@lastbrain/module-auth 2.0.13 → 2.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/auth.build.config.d.ts.map +1 -1
  2. package/dist/auth.build.config.js +33 -47
  3. package/dist/components/AccountButton.d.ts.map +1 -1
  4. package/dist/components/AccountButton.js +9 -5
  5. package/dist/web/admin/signup-stats.d.ts.map +1 -1
  6. package/dist/web/admin/signup-stats.js +4 -2
  7. package/dist/web/admin/user-detail.d.ts.map +1 -1
  8. package/dist/web/admin/user-detail.js +42 -17
  9. package/dist/web/admin/users-by-signup-source.d.ts.map +1 -1
  10. package/dist/web/admin/users-by-signup-source.js +18 -7
  11. package/dist/web/admin/users.d.ts.map +1 -1
  12. package/dist/web/admin/users.js +11 -6
  13. package/dist/web/auth/dashboard.d.ts.map +1 -1
  14. package/dist/web/auth/dashboard.js +7 -3
  15. package/dist/web/auth/folder.d.ts.map +1 -1
  16. package/dist/web/auth/folder.js +5 -3
  17. package/dist/web/auth/profile.d.ts.map +1 -1
  18. package/dist/web/auth/profile.js +13 -6
  19. package/dist/web/auth/reglage.d.ts.map +1 -1
  20. package/dist/web/auth/reglage.js +11 -6
  21. package/dist/web/public/SignInPage.d.ts.map +1 -1
  22. package/dist/web/public/SignInPage.js +14 -56
  23. package/dist/web/public/SignUpPage.d.ts.map +1 -1
  24. package/dist/web/public/SignUpPage.js +18 -11
  25. package/package.json +4 -3
  26. package/src/auth.build.config.ts +34 -48
  27. package/src/components/AccountButton.tsx +17 -10
  28. package/src/i18n/en.json +263 -0
  29. package/src/i18n/fr.json +261 -0
  30. package/src/web/admin/signup-stats.tsx +10 -3
  31. package/src/web/admin/user-detail.tsx +135 -56
  32. package/src/web/admin/users-by-signup-source.tsx +60 -21
  33. package/src/web/admin/users.tsx +41 -18
  34. package/src/web/auth/dashboard.tsx +25 -9
  35. package/src/web/auth/folder.tsx +11 -3
  36. package/src/web/auth/profile.tsx +63 -29
  37. package/src/web/auth/reglage.tsx +43 -19
  38. package/src/web/public/SignInPage.tsx +32 -70
  39. package/src/web/public/SignUpPage.tsx +48 -26
  40. package/supabase/migrations/20251112000000_user_init.sql +35 -19
  41. package/supabase/migrations/20251112000001_auto_profile_and_admin_view.sql +8 -3
  42. package/supabase/migrations/20251112000002_sync_avatars.sql +7 -1
  43. package/supabase/migrations/20251124000001_add_get_admin_user_details.sql +2 -1
@@ -19,7 +19,8 @@ import {
19
19
  Avatar,
20
20
  } from "@lastbrain/ui";
21
21
  import { Search, RefreshCw, Eye, Users2 } from "lucide-react";
22
- import { useRouter } from "next/navigation";
22
+ import { useModuleTranslation } from "@lastbrain/core";
23
+ import { useLocalizedRouter } from "@lastbrain/core";
23
24
 
24
25
  interface User {
25
26
  id: string;
@@ -44,7 +45,8 @@ interface PaginationData {
44
45
  }
45
46
 
46
47
  export function AdminUsersPage() {
47
- const router = useRouter();
48
+ const router = useLocalizedRouter();
49
+ const t = useModuleTranslation("auth");
48
50
  const searchInputId = useId();
49
51
 
50
52
  const [users, setUsers] = useState<User[]>([]);
@@ -144,7 +146,9 @@ export function AdminUsersPage() {
144
146
  <div className="pt-12 pb-12 max-w-7xl mx-auto px-4">
145
147
  <div className="flex items-center gap-2 mb-8">
146
148
  <Users2 className="w-8 h-8" />
147
- <h1 className="text-3xl font-bold">User Management</h1>
149
+ <h1 className="text-3xl font-bold">
150
+ {t("users.title") || "User Management"}
151
+ </h1>
148
152
  </div>
149
153
 
150
154
  <Card>
@@ -153,7 +157,9 @@ export function AdminUsersPage() {
153
157
  <div className="flex gap-2 flex-1">
154
158
  <Input
155
159
  id={searchInputId}
156
- placeholder="Search by email or name..."
160
+ placeholder={
161
+ t("users.search_placeholder") || "Search by email or name..."
162
+ }
157
163
  value={searchQuery}
158
164
  onChange={(e) => setSearchQuery(e.target.value)}
159
165
  onKeyPress={(e) => {
@@ -169,7 +175,7 @@ export function AdminUsersPage() {
169
175
  onPress={handleSearch}
170
176
  isDisabled={isLoading}
171
177
  >
172
- Search
178
+ {t("users.search_button") || "Search"}
173
179
  </Button>
174
180
  </div>
175
181
  <Button
@@ -178,29 +184,43 @@ export function AdminUsersPage() {
178
184
  isDisabled={isLoading}
179
185
  startContent={<RefreshCw className="w-4 h-4" />}
180
186
  >
181
- Refresh
187
+ {t("users.refresh_button") || "Refresh"}
182
188
  </Button>
183
189
  </div>
184
190
  </CardHeader>
185
191
  <CardBody>
186
192
  {isLoading ? (
187
193
  <div className="flex justify-center items-center py-12">
188
- <Spinner size="lg" label="Loading users..." />
194
+ <Spinner
195
+ size="lg"
196
+ label={t("users.loading_users") || "Loading users..."}
197
+ />
189
198
  </div>
190
199
  ) : users.length === 0 ? (
191
200
  <div className="text-center py-12 text-default-500">
192
- No users found
201
+ {t("users.no_users_found") || "No users found"}
193
202
  </div>
194
203
  ) : (
195
204
  <>
196
- <Table isStriped aria-label="Users table">
205
+ <Table
206
+ isStriped
207
+ aria-label={t("users.table_aria_label") || "Users table"}
208
+ >
197
209
  <TableHeader>
198
- <TableColumn>USER</TableColumn>
199
- <TableColumn>EMAIL</TableColumn>
200
- <TableColumn>ROLE</TableColumn>
201
- <TableColumn>LAST SIGN IN</TableColumn>
202
- <TableColumn>CREATED</TableColumn>
203
- <TableColumn>ACTIONS</TableColumn>
210
+ <TableColumn>{t("users.column_user") || "USER"}</TableColumn>
211
+ <TableColumn>
212
+ {t("users.column_email") || "EMAIL"}
213
+ </TableColumn>
214
+ <TableColumn>{t("users.column_role") || "ROLE"}</TableColumn>
215
+ <TableColumn>
216
+ {t("users.column_last_sign_in") || "LAST SIGN IN"}
217
+ </TableColumn>
218
+ <TableColumn>
219
+ {t("users.column_created") || "CREATED"}
220
+ </TableColumn>
221
+ <TableColumn>
222
+ {t("users.column_actions") || "ACTIONS"}
223
+ </TableColumn>
204
224
  </TableHeader>
205
225
  <TableBody>
206
226
  {users.map((user) => {
@@ -241,7 +261,7 @@ export function AdminUsersPage() {
241
261
  <span className="text-small">
242
262
  {user.last_sign_in_at
243
263
  ? formatDate(user.last_sign_in_at)
244
- : "Jamais"}
264
+ : t("users.never") || "Jamais"}
245
265
  </span>
246
266
  </TableCell>
247
267
  <TableCell>
@@ -257,7 +277,7 @@ export function AdminUsersPage() {
257
277
  onPress={() => handleViewUser(user.id)}
258
278
  startContent={<Eye size={14} />}
259
279
  >
260
- Voir
280
+ {t("users.view_button") || "Voir"}
261
281
  </Button>
262
282
  </TableCell>
263
283
  </TableRow>
@@ -278,7 +298,10 @@ export function AdminUsersPage() {
278
298
  )}
279
299
 
280
300
  <div className="mt-4 text-small text-default-500 text-center">
281
- Showing {users.length} of {pagination.total} users
301
+ {t("users.showing_results")
302
+ ?.replace("{{count}}", users.length.toString())
303
+ .replace("{{total}}", pagination.total.toString()) ||
304
+ `Showing ${users.length} of ${pagination.total} users`}
282
305
  </div>
283
306
  </>
284
307
  )}
@@ -12,6 +12,7 @@ import {
12
12
  } from "@lastbrain/ui";
13
13
 
14
14
  import { User, Mail, Calendar, Shield } from "lucide-react";
15
+ import { useModuleTranslation } from "@lastbrain/core";
15
16
 
16
17
  interface UserData {
17
18
  id: string;
@@ -28,6 +29,7 @@ interface UserData {
28
29
  }
29
30
 
30
31
  export function DashboardPage() {
32
+ const t = useModuleTranslation("auth");
31
33
  const [userData, setUserData] = useState<UserData | null>(null);
32
34
  const [isLoading, setIsLoading] = useState(true);
33
35
  const [error, setError] = useState<string | null>(null);
@@ -59,7 +61,9 @@ export function DashboardPage() {
59
61
  <div className="flex justify-center items-center min-h-[400px]">
60
62
  <Spinner color="primary" size="lg">
61
63
  {" "}
62
- <span className="text-xs text-default-700">Loading dashboard...</span>
64
+ <span className="text-xs text-default-700">
65
+ {t("dashboard.loading") || "Loading dashboard..."}
66
+ </span>
63
67
  </Spinner>
64
68
  </div>
65
69
  );
@@ -70,7 +74,9 @@ export function DashboardPage() {
70
74
  <div className="pt-12">
71
75
  <Card className="max-w-2xl mx-auto">
72
76
  <CardBody>
73
- <p className="text-danger">Error: {error}</p>
77
+ <p className="text-danger">
78
+ {t("dashboard.error") || "Error"}: {error}
79
+ </p>
74
80
  </CardBody>
75
81
  </Card>
76
82
  </div>
@@ -88,7 +94,9 @@ export function DashboardPage() {
88
94
 
89
95
  return (
90
96
  <div className="pt-12 pb-12 max-w-6xl mx-auto px-4">
91
- <h1 className="text-3xl font-bold mb-8">Dashboard</h1>
97
+ <h1 className="text-3xl font-bold mb-8">
98
+ {t("dashboard.title") || "Dashboard"}
99
+ </h1>
92
100
 
93
101
  <div className="grid gap-6 md:grid-cols-2">
94
102
  {/* Profile Summary Card */}
@@ -115,7 +123,7 @@ export function DashboardPage() {
115
123
  <div className="flex items-center gap-2">
116
124
  <Calendar className="w-4 h-4 text-default-400" />
117
125
  <span className="text-small">
118
- Member since{" "}
126
+ {t("dashboard.member_since") || "Member since"}{" "}
119
127
  {new Date(userData.created_at).toLocaleDateString()}
120
128
  </span>
121
129
  </div>
@@ -132,25 +140,33 @@ export function DashboardPage() {
132
140
  {/* Account Status Card */}
133
141
  <Card>
134
142
  <CardHeader>
135
- <h3 className="text-lg font-semibold">Account Status</h3>
143
+ <h3 className="text-lg font-semibold">
144
+ {t("dashboard.account_status") || "Account Status"}
145
+ </h3>
136
146
  </CardHeader>
137
147
  <Divider />
138
148
  <CardBody>
139
149
  <div className="space-y-4">
140
150
  <div className="flex justify-between items-center">
141
- <span className="text-small">Status</span>
151
+ <span className="text-small">
152
+ {t("dashboard.status") || "Status"}
153
+ </span>
142
154
  <Chip color="success" size="sm" variant="flat">
143
- Active
155
+ {t("dashboard.active") || "Active"}
144
156
  </Chip>
145
157
  </div>
146
158
  <div className="flex justify-between items-center">
147
- <span className="text-small">Profile</span>
159
+ <span className="text-small">
160
+ {t("dashboard.profile") || "Profile"}
161
+ </span>
148
162
  <Chip
149
163
  color={userData.profile ? "success" : "warning"}
150
164
  size="sm"
151
165
  variant="flat"
152
166
  >
153
- {userData.profile ? "Complete" : "Incomplete"}
167
+ {userData.profile
168
+ ? t("dashboard.complete") || "Complete"
169
+ : t("dashboard.incomplete") || "Incomplete"}
154
170
  </Chip>
155
171
  </div>
156
172
  </div>
@@ -3,6 +3,7 @@
3
3
  import { useEffect, useState } from "react";
4
4
  import { Card, CardBody, Spinner } from "@lastbrain/ui";
5
5
  import { FileManager } from "@lastbrain/ui";
6
+ import { useModuleTranslation } from "@lastbrain/core";
6
7
 
7
8
  interface UserData {
8
9
  id: string;
@@ -19,6 +20,7 @@ interface UserData {
19
20
  }
20
21
 
21
22
  export function FolderPage() {
23
+ const t = useModuleTranslation("auth");
22
24
  const [userData, setUserData] = useState<UserData | null>(null);
23
25
  const [isLoading, setIsLoading] = useState(true);
24
26
  const [error, setError] = useState<string | null>(null);
@@ -50,7 +52,9 @@ export function FolderPage() {
50
52
  <div className="flex justify-center items-center min-h-[400px]">
51
53
  <Spinner color="primary" size="lg">
52
54
  {" "}
53
- <span className="text-xs text-default-700">Loading folder...</span>
55
+ <span className="text-xs text-default-700">
56
+ {t("folder.loading") || "Loading folder..."}
57
+ </span>
54
58
  </Spinner>
55
59
  </div>
56
60
  );
@@ -61,7 +65,9 @@ export function FolderPage() {
61
65
  <div className="pt-12">
62
66
  <Card className="max-w-2xl mx-auto">
63
67
  <CardBody>
64
- <p className="text-danger">Error: {error}</p>
68
+ <p className="text-danger">
69
+ {t("folder.error") || "Error"}: {error}
70
+ </p>
65
71
  </CardBody>
66
72
  </Card>
67
73
  </div>
@@ -74,7 +80,9 @@ export function FolderPage() {
74
80
 
75
81
  return (
76
82
  <div className="pt-4 pb-12 max-w-8xl mx-auto px-4">
77
- <h1 className="text-3xl font-bold mb-8">Dossier</h1>
83
+ <h1 className="text-3xl font-bold mb-8">
84
+ {t("folder.title") || "Dossier"}
85
+ </h1>
78
86
 
79
87
  <FileManager
80
88
  bucket="app"
@@ -14,6 +14,7 @@ import {
14
14
  AvatarUploader,
15
15
  } from "@lastbrain/ui";
16
16
  import { Save, User } from "lucide-react";
17
+ import { useModuleTranslation } from "@lastbrain/core";
17
18
  import { uploadFile, deleteFilesWithPrefix } from "../../api/storage";
18
19
  import { supabaseBrowserClient } from "@lastbrain/core";
19
20
 
@@ -40,6 +41,7 @@ interface UserMetadata {
40
41
  }
41
42
 
42
43
  export function ProfilePage() {
44
+ const t = useModuleTranslation("auth");
43
45
  const [profile, setProfile] = useState<ProfileData>({});
44
46
  const [isLoading, setIsLoading] = useState(true);
45
47
  const [isSaving, setIsSaving] = useState(false);
@@ -106,16 +108,16 @@ export function ProfilePage() {
106
108
  }
107
109
 
108
110
  addToast({
109
- title: "Success",
110
- description: "Profile updated successfully",
111
+ title: t("profile.success") || "Success",
112
+ description: t("profile.updated") || "Profile updated successfully",
111
113
  color: "success",
112
114
  });
113
115
  } catch (err) {
114
116
  console.error("Error updating profile:", err);
115
117
  setError(err instanceof Error ? err.message : "An error occurred");
116
118
  addToast({
117
- title: "Error",
118
- description: "Failed to update profile",
119
+ title: t("profile.error") || "Error",
120
+ description: t("profile.update_failed") || "Failed to update profile",
119
121
  color: "danger",
120
122
  });
121
123
  } finally {
@@ -245,7 +247,10 @@ export function ProfilePage() {
245
247
  if (isLoading) {
246
248
  return (
247
249
  <div className="flex justify-center items-center min-h-[400px]">
248
- <Spinner size="lg" label="Loading profile..." />
250
+ <Spinner
251
+ size="lg"
252
+ label={t("profile.loading") || "Loading profile..."}
253
+ />
249
254
  </div>
250
255
  );
251
256
  }
@@ -293,7 +298,9 @@ export function ProfilePage() {
293
298
  </div>
294
299
  <div className="flex items-center gap-2 mb-4">
295
300
  <User className="w-8 h-8" />
296
- <h1 className="text-3xl font-bold">Edit Profile</h1>
301
+ <h1 className="text-3xl font-bold">
302
+ {t("profile.edit") || "Edit Profile"}
303
+ </h1>
297
304
  </div>
298
305
 
299
306
  {/* </CardBody>
@@ -302,34 +309,45 @@ export function ProfilePage() {
302
309
  {/* Personal Information */}
303
310
  <Card>
304
311
  <CardHeader>
305
- <h3 className="text-lg font-semibold">Personal Information</h3>
312
+ <h3 className="text-lg font-semibold">
313
+ {t("profile.personal_info") || "Personal Information"}
314
+ </h3>
306
315
  </CardHeader>
307
316
  <Divider />
308
317
  <CardBody>
309
318
  <div className="grid gap-4 md:grid-cols-2">
310
319
  <Input
311
- label="First Name"
312
- placeholder="Enter your first name"
320
+ label={t("profile.first_name") || "First Name"}
321
+ placeholder={
322
+ t("profile.first_name_placeholder") ||
323
+ "Enter your first name"
324
+ }
313
325
  value={profile.first_name || ""}
314
326
  onChange={(e) => handleChange("first_name", e.target.value)}
315
327
  />
316
328
  <Input
317
- label="Last Name"
318
- placeholder="Enter your last name"
329
+ label={t("profile.last_name") || "Last Name"}
330
+ placeholder={
331
+ t("profile.last_name_placeholder") || "Enter your last name"
332
+ }
319
333
  value={profile.last_name || ""}
320
334
  onChange={(e) => handleChange("last_name", e.target.value)}
321
335
  />
322
336
  <Input
323
- label="Phone"
324
- placeholder="Enter your phone number"
337
+ label={t("profile.phone") || "Phone"}
338
+ placeholder={
339
+ t("profile.phone_placeholder") || "Enter your phone number"
340
+ }
325
341
  type="tel"
326
342
  value={profile.phone || ""}
327
343
  onChange={(e) => handleChange("phone", e.target.value)}
328
344
  className="md:col-span-2"
329
345
  />
330
346
  <Textarea
331
- label="Bio"
332
- placeholder="Tell us about yourself"
347
+ label={t("profile.bio") || "Bio"}
348
+ placeholder={
349
+ t("profile.bio_placeholder") || "Tell us about yourself"
350
+ }
333
351
  value={profile.bio || ""}
334
352
  onChange={(e) => handleChange("bio", e.target.value)}
335
353
  minRows={3}
@@ -343,28 +361,35 @@ export function ProfilePage() {
343
361
  <Card>
344
362
  <CardHeader>
345
363
  <h3 className="text-lg font-semibold">
346
- Professional Information
364
+ {t("profile.professional_info") || "Professional Information"}
347
365
  </h3>
348
366
  </CardHeader>
349
367
  <Divider />
350
368
  <CardBody>
351
369
  <div className="grid gap-4 md:grid-cols-2">
352
370
  <Input
353
- label="Company"
354
- placeholder="Enter your company name"
371
+ label={t("profile.company") || "Company"}
372
+ placeholder={
373
+ t("profile.company_placeholder") ||
374
+ "Enter your company name"
375
+ }
355
376
  value={profile.company || ""}
356
377
  onChange={(e) => handleChange("company", e.target.value)}
357
378
  />
358
379
  <Input
359
- label="Website"
360
- placeholder="https://example.com"
380
+ label={t("profile.website") || "Website"}
381
+ placeholder={
382
+ t("profile.website_placeholder") || "https://example.com"
383
+ }
361
384
  type="url"
362
385
  value={profile.website || ""}
363
386
  onChange={(e) => handleChange("website", e.target.value)}
364
387
  />
365
388
  <Input
366
- label="Location"
367
- placeholder="City, Country"
389
+ label={t("profile.location") || "Location"}
390
+ placeholder={
391
+ t("profile.location_placeholder") || "City, Country"
392
+ }
368
393
  value={profile.location || ""}
369
394
  onChange={(e) => handleChange("location", e.target.value)}
370
395
  className="md:col-span-2"
@@ -376,20 +401,27 @@ export function ProfilePage() {
376
401
  {/* Preferences */}
377
402
  <Card>
378
403
  <CardHeader>
379
- <h3 className="text-lg font-semibold">Preferences</h3>
404
+ <h3 className="text-lg font-semibold">
405
+ {t("profile.preferences") || "Preferences"}
406
+ </h3>
380
407
  </CardHeader>
381
408
  <Divider />
382
409
  <CardBody>
383
410
  <div className="grid gap-4 md:grid-cols-2">
384
411
  <Input
385
- label="Language"
386
- placeholder="en, fr, es..."
412
+ label={t("profile.language") || "Language"}
413
+ placeholder={
414
+ t("profile.language_placeholder") || "en, fr, es..."
415
+ }
387
416
  value={profile.language || ""}
388
417
  onChange={(e) => handleChange("language", e.target.value)}
389
418
  />
390
419
  <Input
391
- label="Timezone"
392
- placeholder="Europe/Paris, America/New_York..."
420
+ label={t("profile.timezone") || "Timezone"}
421
+ placeholder={
422
+ t("profile.timezone_placeholder") ||
423
+ "Europe/Paris, America/New_York..."
424
+ }
393
425
  value={profile.timezone || ""}
394
426
  onChange={(e) => handleChange("timezone", e.target.value)}
395
427
  />
@@ -405,7 +437,7 @@ export function ProfilePage() {
405
437
  onPress={() => fetchProfile()}
406
438
  isDisabled={isSaving}
407
439
  >
408
- Cancel
440
+ {t("profile.cancel_button") || "Cancel"}
409
441
  </Button>
410
442
  <Button
411
443
  type="submit"
@@ -413,7 +445,9 @@ export function ProfilePage() {
413
445
  isLoading={isSaving}
414
446
  startContent={!isSaving && <Save className="w-4 h-4" />}
415
447
  >
416
- {isSaving ? "Saving..." : "Save Changes"}
448
+ {isSaving
449
+ ? t("profile.saving") || "Saving..."
450
+ : t("profile.save_button") || "Save Changes"}
417
451
  </Button>
418
452
  </div>
419
453
  </div>
@@ -14,6 +14,7 @@ import {
14
14
  addToast,
15
15
  } from "@lastbrain/ui";
16
16
  import { Settings, Save } from "lucide-react";
17
+ import { useModuleTranslation } from "@lastbrain/core";
17
18
 
18
19
  interface UserPreferences {
19
20
  email_notifications?: boolean;
@@ -31,6 +32,7 @@ interface ProfileData {
31
32
  }
32
33
 
33
34
  export function ReglagePage() {
35
+ const t = useModuleTranslation("auth");
34
36
  const [preferences, setPreferences] = useState<UserPreferences>({
35
37
  email_notifications: true,
36
38
  push_notifications: false,
@@ -103,15 +105,15 @@ export function ReglagePage() {
103
105
  }
104
106
 
105
107
  addToast({
106
- title: "Success",
107
- description: "Settings updated successfully",
108
+ title: t("settings.success") || "Success",
109
+ description: t("settings.updated") || "Settings updated successfully",
108
110
  color: "success",
109
111
  });
110
112
  } catch (err) {
111
113
  console.error("Error updating settings:", err);
112
114
  addToast({
113
- title: "Error",
114
- description: "Failed to update settings",
115
+ title: t("settings.error") || "Error",
116
+ description: t("settings.update_failed") || "Failed to update settings",
115
117
  color: "danger",
116
118
  });
117
119
  } finally {
@@ -130,7 +132,10 @@ export function ReglagePage() {
130
132
  if (isLoading) {
131
133
  return (
132
134
  <div className="flex justify-center items-center min-h-[400px]">
133
- <Spinner size="lg" label="Loading settings..." />
135
+ <Spinner
136
+ size="lg"
137
+ label={t("settings.loading") || "Loading settings..."}
138
+ />
134
139
  </div>
135
140
  );
136
141
  }
@@ -139,23 +144,30 @@ export function ReglagePage() {
139
144
  <div className="pt-12 pb-12 max-w-4xl mx-auto px-4">
140
145
  <div className="flex items-center gap-2 mb-8">
141
146
  <Settings className="w-8 h-8" />
142
- <h1 className="text-3xl font-bold">Account Settings</h1>
147
+ <h1 className="text-3xl font-bold">
148
+ {t("settings.account") || "Account Settings"}
149
+ </h1>
143
150
  </div>
144
151
 
145
152
  <div className="space-y-6">
146
153
  {/* Notifications */}
147
154
  <Card>
148
155
  <CardHeader>
149
- <h3 className="text-lg font-semibold">Notifications</h3>
156
+ <h3 className="text-lg font-semibold">
157
+ {t("settings.notifications") || "Notifications"}
158
+ </h3>
150
159
  </CardHeader>
151
160
  <Divider />
152
161
  <CardBody>
153
162
  <div className="space-y-4">
154
163
  <div className="flex justify-between items-center">
155
164
  <div>
156
- <p className="font-medium">Email Notifications</p>
165
+ <p className="font-medium">
166
+ {t("settings.email_notifications") || "Email Notifications"}
167
+ </p>
157
168
  <p className="text-small text-default-500">
158
- Receive email notifications for important updates
169
+ {t("settings.email_notifications_desc") ||
170
+ "Receive email notifications for important updates"}
159
171
  </p>
160
172
  </div>
161
173
  <Switch
@@ -168,9 +180,12 @@ export function ReglagePage() {
168
180
  <Divider />
169
181
  <div className="flex justify-between items-center">
170
182
  <div>
171
- <p className="font-medium">Push Notifications</p>
183
+ <p className="font-medium">
184
+ {t("settings.push_notifications") || "Push Notifications"}
185
+ </p>
172
186
  <p className="text-small text-default-500">
173
- Receive push notifications in your browser
187
+ {t("settings.push_notifications_desc") ||
188
+ "Receive push notifications in your browser"}
174
189
  </p>
175
190
  </div>
176
191
  <Switch
@@ -183,9 +198,12 @@ export function ReglagePage() {
183
198
  <Divider />
184
199
  <div className="flex justify-between items-center">
185
200
  <div>
186
- <p className="font-medium">Marketing Emails</p>
201
+ <p className="font-medium">
202
+ {t("settings.marketing_emails") || "Marketing Emails"}
203
+ </p>
187
204
  <p className="text-small text-default-500">
188
- Receive emails about new features and updates
205
+ {t("settings.marketing_emails_desc") ||
206
+ "Receive emails about new features and updates"}
189
207
  </p>
190
208
  </div>
191
209
  <Switch
@@ -202,19 +220,25 @@ export function ReglagePage() {
202
220
  {/* Appearance */}
203
221
  <Card>
204
222
  <CardHeader>
205
- <h3 className="text-lg font-semibold">Appearance</h3>
223
+ <h3 className="text-lg font-semibold">
224
+ {t("settings.appearance") || "Appearance"}
225
+ </h3>
206
226
  </CardHeader>
207
227
  <Divider />
208
228
  <CardBody>
209
229
  <Select
210
- label="Theme"
211
- placeholder="Select a theme"
230
+ label={t("settings.theme") || "Theme"}
231
+ placeholder={t("settings.select_theme") || "Select a theme"}
212
232
  selectedKeys={preferences.theme ? [preferences.theme] : []}
213
233
  onChange={(e) => handleSelect("theme", e.target.value)}
214
234
  >
215
- <SelectItem key="light">Light</SelectItem>
216
- <SelectItem key="dark">Dark</SelectItem>
217
- <SelectItem key="system">System</SelectItem>
235
+ <SelectItem key="light">
236
+ {t("settings.light") || "Light"}
237
+ </SelectItem>
238
+ <SelectItem key="dark">{t("settings.dark") || "Dark"}</SelectItem>
239
+ <SelectItem key="system">
240
+ {t("settings.system") || "System"}
241
+ </SelectItem>
218
242
  </Select>
219
243
  </CardBody>
220
244
  </Card>