ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
1import { Settings as SettingsIcon, ChevronRight } from "lucide-react";
2import { PLATFORMS } from "../config/platforms";
3import { ATPROTO_APPS } from "../config/atprotoApps";
4import type { UserSettings, PlatformDestinations } from "../types/settings";
5import Section from "../components/common/Section";
6import Card from "../components/common/Card";
7import Badge from "../components/common/Badge";
8import PlatformBadge from "../components/common/PlatformBadge";
9import Toggle from "../components/common/Toggle";
10import DropdownWithIcons from "../components/common/DropdownWithIcons";
11import type { DropdownOptionWithIcon } from "../components/common/DropdownWithIcons";
12
13interface SettingsPageProps {
14 userSettings: UserSettings;
15 onSettingsUpdate: (settings: Partial<UserSettings>) => void;
16 onOpenWizard: () => void;
17}
18
19export default function SettingsPage({
20 userSettings,
21 onSettingsUpdate,
22 onOpenWizard,
23}: SettingsPageProps) {
24 const handleDestinationChange = (platform: string, destination: string) => {
25 onSettingsUpdate({
26 platformDestinations: {
27 ...userSettings.platformDestinations,
28 [platform]: destination,
29 },
30 });
31 };
32
33 // Prepare app options with icons for dropdown
34 const appOptions: DropdownOptionWithIcon[] = Object.values(ATPROTO_APPS).map(
35 (app) => ({
36 value: app.id,
37 label: app.name,
38 icon: app.icon,
39 })
40 );
41
42 return (
43 <div className="space-y-0">
44 {/* Setup Assistant Section */}
45 <Section
46 title="Setup Assistant"
47 description="Quick configuration wizard"
48 divider
49 >
50 <Card
51 variant="upload"
52 onClick={onOpenWizard}
53 className="w-full flex items-start space-x-4 p-4 text-left"
54 >
55 <div className="w-12 h-12 bg-firefly-banner dark:bg-firefly-banner-dark rounded-xl flex items-center justify-center flex-shrink-0 shadow-md">
56 <SettingsIcon className="w-6 h-6 text-white" />
57 </div>
58 <div className="flex-1 min-w-0">
59 <div className="flex flex-wrap items-start justify-between gap-x-4 gap-y-2 mb-1">
60 <div className="font-semibold text-purple-950 dark:text-cyan-50 leading-tight">
61 Run Setup Wizard
62 </div>
63 </div>
64 <p className="text-sm text-purple-750 dark:text-cyan-250 leading-tight">
65 Configure platform destinations, privacy, and automation settings
66 </p>
67 </div>
68 <ChevronRight className="w-5 h-5 text-purple-500 dark:text-cyan-400 flex-shrink-0 self-center" />
69 </Card>
70
71 {/* Current Configuration */}
72 <div className="mt-2 py-2 px-3">
73 <h3 className="font-semibold text-purple-950 dark:text-cyan-50 mb-3">
74 Current Configuration
75 </h3>
76 <div className="gap-8 flex flex-wrap text-sm">
77 <div>
78 <div className="text-purple-750 dark:text-cyan-250 mb-1">
79 Data Storage
80 </div>
81 <Badge variant="status">
82 {userSettings.saveData ? "✅ Enabled" : "❌ Disabled"}
83 </Badge>
84 </div>
85 <div>
86 <div className="text-purple-750 dark:text-cyan-250 mb-1">
87 Automation
88 </div>
89 <Badge variant="status">
90 {userSettings.enableAutomation
91 ? `✅ ${userSettings.automationFrequency}`
92 : "❌ Disabled"}
93 </Badge>
94 </div>
95 <div>
96 <div className="text-purple-750 dark:text-cyan-250 mb-1">
97 Wizard
98 </div>
99 <Badge variant="status">
100 {userSettings.wizardCompleted ? "✅ Completed" : "⏳ Pending"}
101 </Badge>
102 </div>
103 </div>
104 </div>
105 </Section>
106
107 {/* Match Destinations Section */}
108 <Section
109 title="Match Destinations"
110 description="Where matches should go for each platform"
111 divider
112 >
113 <Card className="mt-3 px-3 py-2 rounded-lg border-orange-650/50 dark:border-amber-400/50">
114 <p className="text-sm text-purple-900 dark:text-cyan-100">
115 💡 <strong>Tip:</strong> Choose different apps for different
116 platforms based on content type. For example, send TikTok matches to
117 Spark for video content.
118 </p>
119 </Card>
120
121 <div className="py-2 space-y-0">
122 {Object.entries(PLATFORMS).map(([key, p]) => {
123 const currentDestination =
124 userSettings.platformDestinations[
125 key as keyof PlatformDestinations
126 ];
127
128 return (
129 <div
130 key={key}
131 className="flex items-center justify-between gap-3 px-3 py-2 rounded-xl transition-colors"
132 >
133 <PlatformBadge
134 platformKey={key}
135 size="sm"
136 className="flex-1 min-w-0"
137 />
138 <DropdownWithIcons
139 value={currentDestination}
140 onChange={(value) => handleDestinationChange(key, value)}
141 options={appOptions}
142 className="w-48"
143 />
144 </div>
145 );
146 })}
147 </div>
148 </Section>
149
150 {/* Privacy & Data Section */}
151 <Section
152 title="Privacy & Data"
153 description="Control how your data is stored"
154 >
155 <div className="px-3 space-y-4">
156 {/* Save Data Toggle */}
157 <Toggle
158 checked={userSettings.saveData}
159 onChange={(checked) => onSettingsUpdate({ saveData: checked })}
160 label="Save my data"
161 description="Store your following lists for periodic re-checking and new match notifications"
162 id="settings-save-data"
163 />
164
165 {/* Automation Toggle */}
166 <div>
167 <Toggle
168 checked={userSettings.enableAutomation}
169 onChange={(checked) =>
170 onSettingsUpdate({ enableAutomation: checked })
171 }
172 label="Notify about new matches"
173 description="Get DMs when people you follow join the ATmosphere"
174 disabled={!userSettings.saveData}
175 id="settings-automation"
176 />
177
178 {userSettings.enableAutomation && (
179 <div className="flex items-center gap-3 px-0 mt-4">
180 <label className="text-sm font-medium text-purple-950 dark:text-cyan-50 whitespace-nowrap">
181 Frequency
182 </label>
183 <select
184 value={userSettings.automationFrequency}
185 onChange={(e) =>
186 onSettingsUpdate({
187 automationFrequency: e.target.value as
188 | "Weekly"
189 | "Monthly"
190 | "Quarterly",
191 })
192 }
193 className="flex-1 px-3 py-2 bg-white dark:bg-slate-800 border border-cyan-500/30 dark:border-purple-500/30 rounded-lg text-sm text-purple-950 dark:text-cyan-50 hover:border-cyan-400 dark:hover:border-purple-400 focus:outline-none focus:ring-2 focus:ring-orange-500 dark:focus:ring-amber-400 transition-colors"
194 >
195 <option value="daily">Check daily</option>
196 <option value="weekly">Check weekly</option>
197 <option value="monthly">Check monthly</option>
198 </select>
199 </div>
200 )}
201 </div>
202 </div>
203 </Section>
204 </div>
205 );
206}