@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
@@ -1 +1 @@
1
- {"version":3,"file":"auth.build.config.d.ts","sourceRoot":"","sources":["../src/auth.build.config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,QAAA,MAAM,eAAe,EAAE,iBAgWtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"auth.build.config.d.ts","sourceRoot":"","sources":["../src/auth.build.config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,QAAA,MAAM,eAAe,EAAE,iBAkVtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -139,8 +139,8 @@ const authBuildConfig = {
139
139
  menu: {
140
140
  public: [
141
141
  {
142
- title: "Notifications",
143
- description: "Vos notifications",
142
+ title: "module-auth.menu.notifications",
143
+ description: "module-auth.menu.notifications_desc",
144
144
  icon: "Bell",
145
145
  path: "#",
146
146
  order: 998,
@@ -149,8 +149,8 @@ const authBuildConfig = {
149
149
  componentExport: "NotificationButton",
150
150
  },
151
151
  {
152
- title: "Compte",
153
- description: "Gérer votre compte",
152
+ title: "module-auth.menu.account",
153
+ description: "module-auth.menu.account_desc",
154
154
  icon: "User",
155
155
  path: "#",
156
156
  order: 999,
@@ -159,8 +159,8 @@ const authBuildConfig = {
159
159
  componentExport: "AccountButton",
160
160
  },
161
161
  {
162
- title: "Theme",
163
- description: "Changer le thème",
162
+ title: "module-auth.menu.theme",
163
+ description: "module-auth.menu.theme_desc",
164
164
  icon: "Palette",
165
165
  path: "#",
166
166
  order: 9999,
@@ -171,8 +171,8 @@ const authBuildConfig = {
171
171
  ],
172
172
  admin: [
173
173
  {
174
- title: "Gestion des utilisateurs",
175
- description: "Gérez les utilisateurs de la plateforme",
174
+ title: "module-auth.menu.users_management",
175
+ description: "module-auth.menu.users_management_desc",
176
176
  icon: "Users2",
177
177
  path: "/admin/auth/users",
178
178
  order: 1,
@@ -180,15 +180,15 @@ const authBuildConfig = {
180
180
  shortcutDisplay: "⌘⇧U",
181
181
  },
182
182
  {
183
- title: "Statistiques d'inscriptions",
184
- description: "Suivez les inscriptions par source",
183
+ title: "module-auth.menu.signup_stats",
184
+ description: "module-auth.menu.signup_stats_desc",
185
185
  icon: "UserStar",
186
186
  path: "/admin/auth/signup-stats",
187
187
  order: 2,
188
188
  },
189
189
  {
190
- title: "Notifications",
191
- description: "Vos notifications",
190
+ title: "module-auth.menu.notifications",
191
+ description: "module-auth.menu.notifications_desc",
192
192
  icon: "Bell",
193
193
  path: "#",
194
194
  order: 998,
@@ -197,8 +197,8 @@ const authBuildConfig = {
197
197
  componentExport: "NotificationButton",
198
198
  },
199
199
  {
200
- title: "Compte",
201
- description: "Gérer votre compte",
200
+ title: "module-auth.menu.account",
201
+ description: "module-auth.menu.account_desc",
202
202
  icon: "User",
203
203
  path: "#",
204
204
  order: 999,
@@ -207,8 +207,8 @@ const authBuildConfig = {
207
207
  componentExport: "AccountButton",
208
208
  },
209
209
  {
210
- title: "Theme",
211
- description: "Changer le thème",
210
+ title: "module-auth.menu.theme",
211
+ description: "module-auth.menu.theme_desc",
212
212
  icon: "Palette",
213
213
  path: "#",
214
214
  order: 9999,
@@ -219,8 +219,8 @@ const authBuildConfig = {
219
219
  ],
220
220
  auth: [
221
221
  {
222
- title: "Tableau de bord",
223
- description: "Accédez à votre tableau de bord",
222
+ title: "module-auth.menu.dashboard",
223
+ description: "module-auth.menu.dashboard_desc",
224
224
  icon: "LayoutDashboard",
225
225
  path: "/auth/dashboard",
226
226
  order: 1,
@@ -228,17 +228,17 @@ const authBuildConfig = {
228
228
  shortcutDisplay: "⌘⇧D",
229
229
  },
230
230
  {
231
- title: "Dossier",
232
- description: "Accédez à votre dossier personnel",
231
+ title: "module-auth.menu.folder",
232
+ description: "module-auth.menu.folder_desc",
233
233
  icon: "FolderOpen",
234
234
  path: "/auth/folder",
235
- order: 2,
235
+ order: 99,
236
236
  shortcut: "cmd+shift+f",
237
237
  shortcutDisplay: "⌘⇧F",
238
238
  },
239
239
  {
240
- title: "Notifications",
241
- description: "Vos notifications",
240
+ title: "module-auth.menu.notifications",
241
+ description: "module-auth.menu.notifications_desc",
242
242
  icon: "Bell",
243
243
  path: "#",
244
244
  order: 998,
@@ -247,8 +247,8 @@ const authBuildConfig = {
247
247
  componentExport: "NotificationButton",
248
248
  },
249
249
  {
250
- title: "Compte",
251
- description: "Gérer votre compte",
250
+ title: "module-auth.menu.account",
251
+ description: "module-auth.menu.account_desc",
252
252
  icon: "User",
253
253
  path: "#",
254
254
  order: 999,
@@ -257,8 +257,8 @@ const authBuildConfig = {
257
257
  componentExport: "AccountButton",
258
258
  },
259
259
  {
260
- title: "Theme",
261
- description: "Changer le thème",
260
+ title: "module-auth.menu.theme",
261
+ description: "module-auth.menu.theme_desc",
262
262
  icon: "Palette",
263
263
  path: "#",
264
264
  order: 9999,
@@ -269,8 +269,8 @@ const authBuildConfig = {
269
269
  ],
270
270
  account: [
271
271
  {
272
- title: "Mon profil",
273
- description: "Gérez vos informations personnelles",
272
+ title: "module-auth.menu.profile",
273
+ description: "module-auth.menu.profile_desc",
274
274
  icon: "User2",
275
275
  path: "/auth/profile",
276
276
  order: 1,
@@ -278,8 +278,8 @@ const authBuildConfig = {
278
278
  shortcutDisplay: "⌘⇧P",
279
279
  },
280
280
  {
281
- title: "Paramètres",
282
- description: "Configurez votre compte",
281
+ title: "module-auth.menu.settings",
282
+ description: "module-auth.menu.settings_desc",
283
283
  icon: "Settings",
284
284
  path: "/auth/reglage",
285
285
  order: 2,
@@ -287,8 +287,8 @@ const authBuildConfig = {
287
287
  shortcutDisplay: "⌘⇧S",
288
288
  },
289
289
  {
290
- title: "Déconnexion",
291
- description: "Se déconnecter",
290
+ title: "module-auth.menu.signout",
291
+ description: "module-auth.menu.signout",
292
292
  icon: "LogOut",
293
293
  path: "/signout",
294
294
  order: 99,
@@ -305,20 +305,6 @@ const authBuildConfig = {
305
305
  filter: "owner_id=eq.${USER_ID}",
306
306
  broadcast: "user_notifications_updated",
307
307
  },
308
- {
309
- schema: "public",
310
- table: "user_profil",
311
- event: "*",
312
- filter: "owner_id=eq.${USER_ID}",
313
- broadcast: "user_profil_updated",
314
- },
315
- {
316
- schema: "public",
317
- table: "user_addresses",
318
- event: "*",
319
- filter: "owner_id=eq.${USER_ID}",
320
- broadcast: "user_address_updated",
321
- },
322
308
  ],
323
309
  },
324
310
  storage: {
@@ -1 +1 @@
1
- {"version":3,"file":"AccountButton.d.ts","sourceRoot":"","sources":["../../src/components/AccountButton.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAElD,UAAU,kBAAkB;IAC1B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AASD,eAAO,MAAM,aAAa,GAAI,kCAI3B,kBAAkB,4CA8HpB,CAAC"}
1
+ {"version":3,"file":"AccountButton.d.ts","sourceRoot":"","sources":["../../src/components/AccountButton.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAIlD,UAAU,kBAAkB;IAC1B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AASD,eAAO,MAAM,aAAa,GAAI,kCAI3B,kBAAkB,4CAmIpB,CAAC"}
@@ -1,9 +1,11 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { Button, Link } from "@lastbrain/ui";
3
+ import { AppLink, Button } from "@lastbrain/ui";
4
4
  import { Avatar } from "@lastbrain/ui";
5
5
  import { Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, } from "@lastbrain/ui";
6
6
  import * as LucideIcons from "lucide-react";
7
+ import { useModuleTranslation, langHref } from "@lastbrain/app";
8
+ import { useLanguage } from "@lastbrain/app";
7
9
  // Fonction pour récupérer l'icône Lucide
8
10
  const getIcon = (iconName) => {
9
11
  if (!iconName)
@@ -12,8 +14,10 @@ const getIcon = (iconName) => {
12
14
  return Icon ? Icon : null;
13
15
  };
14
16
  export const AccountButton = ({ user, accountMenu = [], onLogout, }) => {
17
+ const { lang } = useLanguage();
18
+ const t = useModuleTranslation("auth");
15
19
  if (!user)
16
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "block md:hidden", children: [_jsx(Button, { as: Link, href: "/signin", radius: "full", isIconOnly: true, variant: "light", color: "primary", children: _jsx(LucideIcons.LogIn, { size: 16 }) }), _jsx(Button, { as: Link, href: "/signup", radius: "full", isIconOnly: true, variant: "flat", className: "ml-2", color: "secondary", children: _jsx(LucideIcons.UserPlus2, { size: 16 }) })] }), _jsxs("div", { className: "hidden md:block", children: [_jsx(Button, { as: Link, href: "/signin", startContent: _jsx(LucideIcons.LogIn, { size: 16 }), variant: "light", color: "primary", children: "Se connecter" }), _jsx(Button, { as: Link, href: "/signup", variant: "flat", className: "ml-2", color: "secondary", startContent: _jsx(LucideIcons.UserPlus2, { size: 16 }), children: "S'inscrire" })] })] }));
20
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "block md:hidden", children: [_jsx(Button, { as: AppLink, href: "/signin", radius: "full", isIconOnly: true, variant: "light", color: "primary", children: _jsx(LucideIcons.LogIn, { size: 16 }) }), _jsx(Button, { as: AppLink, href: "/signup", radius: "full", isIconOnly: true, variant: "flat", className: "ml-2", color: "secondary", children: _jsx(LucideIcons.UserPlus2, { size: 16 }) })] }), _jsxs("div", { className: "hidden md:block", children: [_jsx(Button, { as: AppLink, href: "/signin", startContent: _jsx(LucideIcons.LogIn, { size: 16 }), variant: "light", color: "primary", children: t("signin") }), _jsx(Button, { as: AppLink, href: "/signup", variant: "flat", className: "ml-2", color: "secondary", startContent: _jsx(LucideIcons.UserPlus2, { size: 16 }), children: t("signup") })] })] }));
17
21
  return (_jsxs(Dropdown, { children: [_jsx(DropdownTrigger, { children: user?.user_metadata.avatar ? (_jsx(Avatar, { size: "sm", src: user?.user_metadata.avatar
18
22
  ? `/api/storage/${user?.user_metadata.avatar}`
19
23
  : undefined, title: user.email, fallback: _jsx(LucideIcons.User2, { size: 18 }), classNames: {
@@ -22,7 +26,7 @@ export const AccountButton = ({ user, accountMenu = [], onLogout, }) => {
22
26
  } })) : (_jsx(Button, { size: "sm", variant: "flat", radius: "full", isIconOnly: true, children: _jsx(LucideIcons.User2, { size: 16 }) })) }), _jsx(DropdownMenu, { items: [
23
27
  {
24
28
  key: "hello",
25
- label: `Bonjour ${user?.user_metadata?.full_name || user.email}`,
29
+ label: `${t("hello")} ${user?.user_metadata?.full_name || user.email}`,
26
30
  isReadOnly: true,
27
31
  },
28
32
  ...accountMenu.map((item) => ({
@@ -33,10 +37,10 @@ export const AccountButton = ({ user, accountMenu = [], onLogout, }) => {
33
37
  isLogout: item.path.includes("signout") || item.path.includes("logout"),
34
38
  href: item.path.includes("signout") || item.path.includes("logout")
35
39
  ? undefined
36
- : item.path,
40
+ : langHref(item.path, lang),
37
41
  })),
38
42
  ], children: (item) => {
39
43
  const Icon = item.icon ? getIcon(item.icon) : null;
40
- return (_jsx(DropdownItem, { href: item.href, onPress: item.isLogout ? () => onLogout?.() : undefined, color: item.isLogout ? "danger" : "default", description: item.description, startContent: Icon && _jsx(Icon, { size: 16 }), isDisabled: item.isReadOnly, isReadOnly: item.isReadOnly, children: item.label }, item.key));
44
+ return (_jsx(DropdownItem, { href: item.href, onPress: item.isLogout ? () => onLogout?.() : undefined, color: item.isLogout ? "danger" : "default", description: !item.isLogout && item.description, startContent: Icon && _jsx(Icon, { size: 16 }), isDisabled: item.isReadOnly, isReadOnly: item.isReadOnly, children: item.label }, item.key));
41
45
  } })] }));
42
46
  };
@@ -1 +1 @@
1
- {"version":3,"file":"signup-stats.d.ts","sourceRoot":"","sources":["../../../src/web/admin/signup-stats.tsx"],"names":[],"mappings":"AAkCA,wBAAgB,eAAe,4CA6Q9B"}
1
+ {"version":3,"file":"signup-stats.d.ts","sourceRoot":"","sources":["../../../src/web/admin/signup-stats.tsx"],"names":[],"mappings":"AAmCA,wBAAgB,eAAe,4CAmR9B"}
@@ -3,7 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from "react";
4
4
  import { Card, CardBody, CardHeader, Chip, Spinner, Tab, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow, Tabs, } from "@lastbrain/ui";
5
5
  import { BarChart3, TrendingUp } from "lucide-react";
6
+ import { useModuleTranslation } from "@lastbrain/core";
6
7
  export function SignupStatsPage() {
8
+ const t = useModuleTranslation("auth");
7
9
  const [stats, setStats] = useState(null);
8
10
  const [loading, setLoading] = useState(true);
9
11
  const [error, setError] = useState(null);
@@ -28,7 +30,7 @@ export function SignupStatsPage() {
28
30
  }
29
31
  };
30
32
  if (loading) {
31
- return (_jsx("div", { className: "flex justify-center items-center min-h-screen", children: _jsx(Spinner, { size: "lg", label: "Chargement des statistiques..." }) }));
33
+ return (_jsx("div", { className: "flex justify-center items-center min-h-screen", children: _jsx(Spinner, { size: "lg", label: t("signup_stats.loading") || "Chargement des statistiques..." }) }));
32
34
  }
33
35
  if (error || !stats) {
34
36
  return (_jsx("div", { className: "p-6", children: _jsx(Card, { className: "border border-danger-200 bg-danger-50/50", children: _jsx(CardBody, { children: _jsx("p", { className: "text-danger-600", children: error || "Erreur de chargement" }) }) }) }));
@@ -37,7 +39,7 @@ export function SignupStatsPage() {
37
39
  100).toFixed(1);
38
40
  const recipePercentage = ((stats.bySource.recipe / stats.total) *
39
41
  100).toFixed(1);
40
- return (_jsxs("div", { className: "space-y-6 px-2 md:p-6", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(BarChart3, { size: 28, className: "text-primary-600" }), _jsx("h1", { className: "text-3xl font-bold", children: "Statistiques d'inscriptions" })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-12", children: [_jsx(Card, { className: " ", children: _jsxs(CardBody, { className: "gap-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-medium text-primary-600 dark:text-primary-400", children: "Total d'inscriptions" }), _jsx(TrendingUp, { size: 20, className: "text-primary-600" })] }), _jsx("p", { className: "text-4xl font-bold text-primary-700 dark:text-primary-300", children: stats.total })] }) }), _jsx(Card, { className: " ", children: _jsxs(CardBody, { className: "gap-4", children: [_jsx("div", { className: "flex items-center justify-between", children: _jsx("span", { className: "text-sm font-medium text-secondary-600 dark:text-secondary-400", children: "Inscriptions LastBrain" }) }), _jsxs("div", { className: "flex items-end justify-between gap-2", children: [_jsx("p", { className: "text-4xl font-bold text-secondary-700 dark:text-secondary-300", children: stats.bySource.lastbrain }), _jsxs(Chip, { size: "sm", color: "secondary", variant: "flat", children: [lastbrainPercentage, "%"] })] })] }) }), _jsx(Card, { className: " ", children: _jsxs(CardBody, { className: "gap-4", children: [_jsx("div", { className: "flex items-center justify-between", children: _jsx("span", { className: "text-sm font-medium text-success-600 dark:text-success-400", children: "Inscriptions Recipe" }) }), _jsxs("div", { className: "flex items-end justify-between gap-2", children: [_jsx("p", { className: "text-4xl font-bold text-success-700 dark:text-success-300", children: stats.bySource.recipe }), _jsxs(Chip, { size: "sm", color: "success", variant: "flat", children: [recipePercentage, "%"] })] })] }) })] }), _jsxs(Tabs, { "aria-label": "Vues des statistiques", color: "primary", variant: "bordered", children: [_jsx(Tab, { title: "Par Source", children: _jsxs(Card, { className: "mt-6", children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "R\u00E9sum\u00E9 par source" }) }), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "p-4 rounded-lg border border-secondary-800 dark:border-secondary-800", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "font-medium text-secondary-700 dark:text-secondary-300", children: "LastBrain" }), _jsxs(Chip, { size: "sm", color: "secondary", variant: "flat", children: [stats.bySource.lastbrain, " inscriptions"] })] }), _jsx("div", { className: "w-full bg-default-200 rounded-full h-2 dark:bg-default-700", children: _jsx("div", { className: "bg-secondary-500 h-2 rounded-full", style: {
42
+ return (_jsxs("div", { className: "space-y-6 px-2 md:p-6", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(BarChart3, { size: 28, className: "text-primary-600" }), _jsx("h1", { className: "text-3xl font-bold", children: t("signup_stats.title") || "Statistiques d'inscriptions" })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-12", children: [_jsx(Card, { className: " ", children: _jsxs(CardBody, { className: "gap-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-medium text-primary-600 dark:text-primary-400", children: t("signup_stats.total") || "Total d'inscriptions" }), _jsx(TrendingUp, { size: 20, className: "text-primary-600" })] }), _jsx("p", { className: "text-4xl font-bold text-primary-700 dark:text-primary-300", children: stats.total })] }) }), _jsx(Card, { className: " ", children: _jsxs(CardBody, { className: "gap-4", children: [_jsx("div", { className: "flex items-center justify-between", children: _jsx("span", { className: "text-sm font-medium text-secondary-600 dark:text-secondary-400", children: "Inscriptions LastBrain" }) }), _jsxs("div", { className: "flex items-end justify-between gap-2", children: [_jsx("p", { className: "text-4xl font-bold text-secondary-700 dark:text-secondary-300", children: stats.bySource.lastbrain }), _jsxs(Chip, { size: "sm", color: "secondary", variant: "flat", children: [lastbrainPercentage, "%"] })] })] }) }), _jsx(Card, { className: " ", children: _jsxs(CardBody, { className: "gap-4", children: [_jsx("div", { className: "flex items-center justify-between", children: _jsx("span", { className: "text-sm font-medium text-success-600 dark:text-success-400", children: "Inscriptions Recipe" }) }), _jsxs("div", { className: "flex items-end justify-between gap-2", children: [_jsx("p", { className: "text-4xl font-bold text-success-700 dark:text-success-300", children: stats.bySource.recipe }), _jsxs(Chip, { size: "sm", color: "success", variant: "flat", children: [recipePercentage, "%"] })] })] }) })] }), _jsxs(Tabs, { "aria-label": "Vues des statistiques", color: "primary", variant: "bordered", children: [_jsx(Tab, { title: "Par Source", children: _jsxs(Card, { className: "mt-6", children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "R\u00E9sum\u00E9 par source" }) }), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "p-4 rounded-lg border border-secondary-800 dark:border-secondary-800", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "font-medium text-secondary-700 dark:text-secondary-300", children: "LastBrain" }), _jsxs(Chip, { size: "sm", color: "secondary", variant: "flat", children: [stats.bySource.lastbrain, " inscriptions"] })] }), _jsx("div", { className: "w-full bg-default-200 rounded-full h-2 dark:bg-default-700", children: _jsx("div", { className: "bg-secondary-500 h-2 rounded-full", style: {
41
43
  width: `${(stats.bySource.lastbrain / stats.total) * 100}%`,
42
44
  } }) }), _jsxs("p", { className: "text-xs text-default-500 mt-2", children: [lastbrainPercentage, "% du total"] })] }), _jsxs("div", { className: "p-4 rounded-lg border border-success-200 dark:border-success-800", children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "font-medium text-success-700 dark:text-success-300", children: "Recipe" }), _jsxs(Chip, { size: "sm", color: "success", variant: "flat", children: [stats.bySource.recipe, " inscriptions"] })] }), _jsx("div", { className: "w-full bg-default-200 rounded-full h-2 dark:bg-default-700", children: _jsx("div", { className: "bg-success-500 h-2 rounded-full", style: {
43
45
  width: `${(stats.bySource.recipe / stats.total) * 100}%`,
@@ -1 +1 @@
1
- {"version":3,"file":"user-detail.d.ts","sourceRoot":"","sources":["../../../src/web/admin/user-detail.tsx"],"names":[],"mappings":"AAwBA,UAAU,aAAa;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAkCD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;CAClC;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,cAAmB,GACpB,EAAE,mBAAmB,2CAygBrB"}
1
+ {"version":3,"file":"user-detail.d.ts","sourceRoot":"","sources":["../../../src/web/admin/user-detail.tsx"],"names":[],"mappings":"AAyBA,UAAU,aAAa;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAkCD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;CAClC;AAED,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,cAAmB,GACpB,EAAE,mBAAmB,2CAulBrB"}
@@ -1,11 +1,14 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useCallback } from "react";
4
+ import { useModuleTranslation, useLanguage } from "@lastbrain/core";
4
5
  import { Card, CardHeader, CardBody, Tabs, Tab, Avatar, Chip, Button, Input, Textarea, Select, SelectItem, Spinner, addToast, Snippet, } from "@lastbrain/ui";
5
6
  import { User, Bell, Settings } from "lucide-react";
6
7
  import { useAuth } from "@lastbrain/core";
7
8
  import * as LucideIcons from "lucide-react";
8
9
  export function UserDetailPage({ userId, moduleUserTabs = [], }) {
10
+ const t = useModuleTranslation("auth");
11
+ const { t: tGlobal } = useLanguage(); // Pour les traductions des autres modules
9
12
  const { user: _currentUser } = useAuth();
10
13
  const [userProfile, setUserProfile] = useState(null);
11
14
  const [loading, setLoading] = useState(true);
@@ -33,7 +36,8 @@ export function UserDetailPage({ userId, moduleUserTabs = [], }) {
33
36
  setUserProfile(userDetails);
34
37
  }
35
38
  catch (error) {
36
- console.error("Erreur lors du chargement du profil:", error);
39
+ console.error(t("user_detail.profile_loading_error") ||
40
+ "Erreur lors du chargement du profil:", error);
37
41
  setUserProfile(null);
38
42
  }
39
43
  finally {
@@ -48,7 +52,8 @@ export function UserDetailPage({ userId, moduleUserTabs = [], }) {
48
52
  if (!notificationTitle.trim() || !notificationMessage.trim()) {
49
53
  addToast({
50
54
  color: "danger",
51
- title: "Veuillez remplir le titre et le message",
55
+ title: t("user_detail.fill_title_message") ||
56
+ "Veuillez remplir le titre et le message",
52
57
  });
53
58
  return;
54
59
  }
@@ -76,13 +81,15 @@ export function UserDetailPage({ userId, moduleUserTabs = [], }) {
76
81
  setNotificationType("info");
77
82
  addToast({
78
83
  color: "success",
79
- title: "Notification envoyée avec succès",
84
+ title: t("user_detail.notification_sent_success") ||
85
+ "Notification envoyée avec succès",
80
86
  });
81
87
  }
82
88
  catch {
83
89
  addToast({
84
90
  color: "danger",
85
- title: "Erreur lors de l'envoi de la notification",
91
+ title: t("user_detail.notification_send_error") ||
92
+ "Erreur lors de l'envoi de la notification",
86
93
  });
87
94
  }
88
95
  finally {
@@ -93,32 +100,40 @@ export function UserDetailPage({ userId, moduleUserTabs = [], }) {
93
100
  return (_jsx("div", { className: "flex justify-center items-center min-h-64", children: _jsx(Spinner, { size: "lg" }) }));
94
101
  }
95
102
  if (!userProfile) {
96
- return (_jsx(Card, { children: _jsx(CardBody, { children: _jsx("p", { className: "text-center text-gray-500", children: "Utilisateur non trouv\u00E9" }) }) }));
103
+ return (_jsx(Card, { children: _jsx(CardBody, { children: _jsx("p", { className: "text-center text-gray-500", children: t("user_detail.user_not_found") || "Utilisateur non trouvé" }) }) }));
97
104
  }
98
105
  const isAdmin = Array.isArray(userProfile.raw_app_meta_data?.roles) &&
99
106
  userProfile.raw_app_meta_data.roles.includes("admin");
100
107
  return (_jsxs("div", { className: "max-w-[calc(100vw-8rem)] mx-auto mt-4 space-y-6", children: [_jsx(Card, { children: _jsxs(CardHeader, { className: "flex flex-col md:flex-row gap-4", children: [_jsx(Avatar, { isBordered: true, src: userProfile.avatar_sizes?.large || userProfile.avatar_url
101
108
  ? `/api/storage/${userProfile.avatar_sizes?.large || userProfile.avatar_url}`
102
- : undefined, name: userProfile.full_name || userProfile.email, size: "lg" }), _jsxs("div", { className: "w-full flex flex-col gap-1", children: [_jsxs("div", { className: "w-full flex flex-col md:flex-row justify-between", children: [_jsx("h1", { className: "text-xl font-bold", children: userProfile.full_name || userProfile.email }), _jsxs("p", { className: "text-sm text-default-500 ", children: [_jsx("span", { className: "", children: "Derni\u00E8re connexion:" }), " ", userProfile.last_sign_in_at
109
+ : undefined, name: userProfile.full_name || userProfile.email, size: "lg" }), _jsxs("div", { className: "w-full flex flex-col gap-1", children: [_jsxs("div", { className: "w-full flex flex-col md:flex-row justify-between", children: [_jsx("h1", { className: "text-xl font-bold", children: userProfile.full_name || userProfile.email }), _jsxs("p", { className: "text-sm text-default-500 ", children: [_jsx("span", { className: "", children: t("user_detail.last_login") || "Dernière connexion:" }), " ", userProfile.last_sign_in_at
103
110
  ? new Date(userProfile.last_sign_in_at).toLocaleDateString()
104
- : "N/A", " ", "\u00E0", " ", userProfile.last_sign_in_at
111
+ : t("user_detail.not_available") || "N/A", " ", t("user_detail.at") || "à", " ", userProfile.last_sign_in_at
105
112
  ? new Date(userProfile.last_sign_in_at).toLocaleTimeString()
106
- : "N/A"] })] }), _jsx("p", { className: "text-gray-500", children: userProfile.email }), _jsxs("div", { className: "flex flex-col md:flex-row md:items-center gap-2", children: [_jsx(Chip, { variant: "flat", color: isAdmin ? "danger" : "primary", size: "sm", children: isAdmin ? "Administrateur" : "Utilisateur" }), userProfile.profile?.signup_source && (_jsx(Chip, { variant: "flat", color: userProfile.profile.signup_source.toLowerCase() === "recipe"
113
+ : t("user_detail.not_available") || "N/A"] })] }), _jsx("p", { className: "text-gray-500", children: userProfile.email }), _jsxs("div", { className: "flex flex-col md:flex-row md:items-center gap-2", children: [_jsx(Chip, { variant: "flat", color: isAdmin ? "danger" : "primary", size: "sm", children: isAdmin
114
+ ? t("user_detail.administrator") || "Administrateur"
115
+ : t("user_detail.user") || "Utilisateur" }), userProfile.profile?.signup_source && (_jsx(Chip, { variant: "flat", color: userProfile.profile.signup_source.toLowerCase() === "recipe"
107
116
  ? "success"
108
117
  : "secondary", size: "sm", children: userProfile.profile.signup_source.toLowerCase() === "recipe"
109
- ? "Recipe"
110
- : "LastBrain" })), _jsx(Snippet, { color: "default", size: "sm", symbol: "#", children: userId })] })] })] }) }), _jsx(Card, { children: _jsx(CardBody, { children: _jsxs(Tabs, { "aria-label": "Options utilisateur", color: "primary", variant: "underlined", children: [_jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(User, { size: 16 }), _jsx("span", { children: "Profil" })] }), children: _jsxs("div", { className: "space-y-6 mt-4", children: [_jsx(Card, { children: _jsxs(CardBody, { children: [_jsxs("h3", { className: "font-semibold text-lg mb-4 flex items-center gap-2", children: [_jsx(User, { size: 18 }), "Identit\u00E9"] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Nom complet" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.full_name || "Non renseigné" })] }), userProfile.profile?.first_name && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Pr\u00E9nom" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.first_name })] })), userProfile.profile?.last_name && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Nom" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.last_name })] })), _jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Email" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.email })] }), userProfile.profile?.phone && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "T\u00E9l\u00E9phone" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.phone })] }))] }), userProfile.profile?.bio && (_jsxs("div", { className: "mt-4", children: [_jsx("span", { className: "text-default-500 text-sm", children: "Bio" }), _jsx("p", { className: "font-medium mt-1 text-sm", children: userProfile.profile.bio })] }))] }) }), (userProfile.profile?.company ||
118
+ ? t("user_detail.source_recipe") || "Recipe"
119
+ : t("user_detail.source_lastbrain") || "LastBrain" })), _jsx(Snippet, { color: "default", size: "sm", symbol: "#", children: userId })] })] })] }) }), _jsx(Card, { children: _jsx(CardBody, { children: _jsxs(Tabs, { "aria-label": t("user_detail.user_options") || "Options utilisateur", color: "primary", variant: "underlined", children: [_jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(User, { size: 16 }), _jsx("span", { children: t("user_detail.tab_profile") || "Profil" })] }), children: _jsxs("div", { className: "space-y-6 mt-4", children: [_jsx(Card, { children: _jsxs(CardBody, { children: [_jsxs("h3", { className: "font-semibold text-lg mb-4 flex items-center gap-2", children: [_jsx(User, { size: 18 }), t("user_detail.identity_section") || "Identité"] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.full_name") || "Nom complet" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.full_name ||
120
+ t("user_detail.not_provided") ||
121
+ "Non renseigné" })] }), userProfile.profile?.first_name && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.first_name") || "Prénom" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.first_name })] })), userProfile.profile?.last_name && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.last_name") || "Nom" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.last_name })] })), _jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.email") || "Email" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.email })] }), userProfile.profile?.phone && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.phone") || "Téléphone" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.phone })] }))] }), userProfile.profile?.bio && (_jsxs("div", { className: "mt-4", children: [_jsx("span", { className: "text-default-500 text-sm", children: t("user_detail.bio") || "Bio" }), _jsx("p", { className: "font-medium mt-1 text-sm", children: userProfile.profile.bio })] }))] }) }), (userProfile.profile?.company ||
111
122
  userProfile.profile?.website ||
112
- userProfile.profile?.location) && (_jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: "Informations professionnelles" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [userProfile.profile?.company && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Entreprise" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.company })] })), userProfile.profile?.website && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Site web" }), _jsx("p", { className: "font-medium mt-1", children: _jsx("a", { href: userProfile.profile.website, target: "_blank", rel: "noopener noreferrer", className: "text-primary hover:underline", children: userProfile.profile.website }) })] })), userProfile.profile?.location && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Localisation" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.location })] }))] })] }) })), (userProfile.profile?.language ||
113
- userProfile.profile?.timezone) && (_jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: "Pr\u00E9f\u00E9rences" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [userProfile.profile?.language && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Langue" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.language.toUpperCase() })] })), userProfile.profile?.timezone && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Fuseau horaire" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.timezone })] }))] })] }) })), _jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: "Informations du compte" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "R\u00F4le" }), _jsx("div", { className: "mt-2", children: _jsx(Chip, { variant: "flat", color: isAdmin ? "danger" : "default", size: "sm", children: isAdmin
114
- ? "Administrateur"
115
- : "Utilisateur standard" }) })] }), _jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Date de cr\u00E9ation" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.created_at
123
+ userProfile.profile?.location) && (_jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: t("user_detail.professional_info") ||
124
+ "Informations professionnelles" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [userProfile.profile?.company && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.company") || "Entreprise" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.company })] })), userProfile.profile?.website && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.website") || "Site web" }), _jsx("p", { className: "font-medium mt-1", children: _jsx("a", { href: userProfile.profile.website, target: "_blank", rel: "noopener noreferrer", className: "text-primary hover:underline", children: userProfile.profile.website }) })] })), userProfile.profile?.location && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.location") || "Localisation" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.location })] }))] })] }) })), (userProfile.profile?.language ||
125
+ userProfile.profile?.timezone) && (_jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: t("user_detail.preferences") || "Préférences" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [userProfile.profile?.language && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.language") || "Langue" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.language.toUpperCase() })] })), userProfile.profile?.timezone && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.timezone") || "Fuseau horaire" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.timezone })] }))] })] }) })), _jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: t("user_detail.account_info") ||
126
+ "Informations du compte" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.role") || "Rôle" }), _jsx("div", { className: "mt-2", children: _jsx(Chip, { variant: "flat", color: isAdmin ? "danger" : "default", size: "sm", children: isAdmin
127
+ ? t("user_detail.administrator") ||
128
+ "Administrateur"
129
+ : t("user_detail.standard_user") ||
130
+ "Utilisateur standard" }) })] }), _jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.creation_date") || "Date de création" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.created_at
116
131
  ? new Date(userProfile.created_at).toLocaleDateString("fr-FR", {
117
132
  year: "numeric",
118
133
  month: "long",
119
134
  day: "numeric",
120
135
  })
121
- : "N/A" })] }), _jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Derni\u00E8re connexion" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.last_sign_in_at
136
+ : t("user_detail.not_available") || "N/A" })] }), _jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: t("user_detail.last_login") || "Dernière connexion" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.last_sign_in_at
122
137
  ? new Date(userProfile.last_sign_in_at).toLocaleDateString("fr-FR", {
123
138
  year: "numeric",
124
139
  month: "long",
@@ -126,7 +141,17 @@ export function UserDetailPage({ userId, moduleUserTabs = [], }) {
126
141
  hour: "2-digit",
127
142
  minute: "2-digit",
128
143
  })
129
- : "Jamais" })] })] })] }) })] }) }, "profile"), _jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(Bell, { size: 16 }), _jsx("span", { children: "Notifications" })] }), children: _jsxs("div", { className: "space-y-4 mt-4", children: [_jsx("h3", { className: "font-semibold", children: "Envoyer une notification" }), _jsxs("div", { className: "space-y-4", children: [_jsx(Input, { label: "Titre de la notification", placeholder: "Ex: Nouveau message important", value: notificationTitle, onChange: (e) => setNotificationTitle(e.target.value), maxLength: 100 }), _jsx(Textarea, { label: "Message", placeholder: "Contenu de la notification...", value: notificationMessage, onChange: (e) => setNotificationMessage(e.target.value), maxLength: 500, minRows: 3 }), _jsxs(Select, { label: "Type de notification", selectedKeys: [notificationType], onSelectionChange: (keys) => setNotificationType(Array.from(keys)[0]), children: [_jsx(SelectItem, { children: "Information" }, "info"), _jsx(SelectItem, { children: "Avertissement" }, "warning"), _jsx(SelectItem, { children: "Danger" }, "danger"), _jsx(SelectItem, { children: "Succ\u00E8s" }, "success")] }), _jsx(Button, { color: "primary", onPress: handleSendNotification, isLoading: sendingNotification, startContent: _jsx(Bell, { size: 16 }), isDisabled: !notificationTitle.trim() || !notificationMessage.trim(), children: "Envoyer la notification" })] })] }) }, "notifications"), _jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(Settings, { size: 16 }), _jsx("span", { children: "Param\u00E8tres" })] }), children: _jsxs("div", { className: "space-y-4 mt-4", children: [_jsx("h3", { className: "font-semibold", children: "Actions administrateur" }), _jsxs("div", { className: "space-y-3 space-x-5", children: [_jsx(Button, { color: "warning", variant: "bordered", size: "sm", children: "R\u00E9initialiser le mot de passe" }), _jsx(Button, { color: "danger", variant: "bordered", size: "sm", children: "Suspendre le compte" }), _jsx(Button, { color: "secondary", variant: "bordered", size: "sm", children: "Promouvoir en administrateur" })] }), _jsxs("div", { className: "mt-6 p-4 bg-gray-50 dark:bg-gray-800 rounded-lg", children: [_jsx("h4", { className: "font-medium mb-2", children: "M\u00E9tadonn\u00E9es techniques" }), _jsx("pre", { className: "text-xs text-gray-600 dark:text-gray-400 overflow-auto", children: JSON.stringify({
144
+ : t("user_detail.never") || "Jamais" })] })] })] }) })] }) }, "profile"), _jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(Bell, { size: 16 }), _jsx("span", { children: t("user_detail.tab_notifications") || "Notifications" })] }), children: _jsxs("div", { className: "space-y-4 mt-4", children: [_jsx("h3", { className: "font-semibold", children: t("user_detail.send_notification") ||
145
+ "Envoyer une notification" }), _jsxs("div", { className: "space-y-4", children: [_jsx(Input, { label: t("user_detail.notification_title") ||
146
+ "Titre de la notification", placeholder: t("user_detail.notification_title_placeholder") ||
147
+ "Ex: Nouveau message important", value: notificationTitle, onChange: (e) => setNotificationTitle(e.target.value), maxLength: 100 }), _jsx(Textarea, { label: t("user_detail.notification_message") || "Message", placeholder: t("user_detail.notification_message_placeholder") ||
148
+ "Contenu de la notification...", value: notificationMessage, onChange: (e) => setNotificationMessage(e.target.value), maxLength: 500, minRows: 3 }), _jsxs(Select, { label: t("user_detail.notification_type") ||
149
+ "Type de notification", selectedKeys: [notificationType], onSelectionChange: (keys) => setNotificationType(Array.from(keys)[0]), children: [_jsx(SelectItem, { children: t("user_detail.notification_type_info") || "Information" }, "info"), _jsx(SelectItem, { children: t("user_detail.notification_type_warning") ||
150
+ "Avertissement" }, "warning"), _jsx(SelectItem, { children: t("user_detail.notification_type_danger") || "Danger" }, "danger"), _jsx(SelectItem, { children: t("user_detail.notification_type_success") || "Succès" }, "success")] }), _jsx(Button, { color: "primary", onPress: handleSendNotification, isLoading: sendingNotification, startContent: _jsx(Bell, { size: 16 }), isDisabled: !notificationTitle.trim() || !notificationMessage.trim(), children: t("user_detail.send_button") || "Envoyer la notification" })] })] }) }, "notifications"), _jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(Settings, { size: 16 }), _jsx("span", { children: t("user_detail.tab_settings") || "Paramètres" })] }), children: _jsxs("div", { className: "space-y-4 mt-4", children: [_jsx("h3", { className: "font-semibold", children: t("user_detail.admin_actions") || "Actions administrateur" }), _jsxs("div", { className: "space-y-3 space-x-5", children: [_jsx(Button, { color: "warning", variant: "bordered", size: "sm", children: t("user_detail.reset_password_btn") ||
151
+ "Réinitialiser le mot de passe" }), _jsx(Button, { color: "danger", variant: "bordered", size: "sm", children: t("user_detail.suspend_account_btn") ||
152
+ "Suspendre le compte" }), _jsx(Button, { color: "secondary", variant: "bordered", size: "sm", children: t("user_detail.promote_admin_btn") ||
153
+ "Promouvoir en administrateur" })] }), _jsxs("div", { className: "mt-6 p-4 bg-gray-50 dark:bg-gray-800 rounded-lg", children: [_jsx("h4", { className: "font-medium mb-2", children: t("user_detail.technical_metadata") ||
154
+ "Métadonnées techniques" }), _jsx("pre", { className: "text-xs text-gray-600 dark:text-gray-400 overflow-auto", children: JSON.stringify({
130
155
  app_metadata: userProfile.raw_app_meta_data,
131
156
  user_metadata: userProfile.raw_user_meta_data,
132
157
  }, null, 2) })] })] }) }, "settings"), moduleUserTabs.map((tab) => {
@@ -134,6 +159,6 @@ export function UserDetailPage({ userId, moduleUserTabs = [], }) {
134
159
  const IconComponent = tab.icon
135
160
  ? LucideIcons[tab.icon]
136
161
  : null;
137
- return (_jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [IconComponent && _jsx(IconComponent, { size: 16 }), _jsx("span", { children: tab.title })] }), children: _jsx(TabComponent, { userId: userId }) }, tab.key));
162
+ return (_jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [IconComponent && _jsx(IconComponent, { size: 16 }), _jsx("span", { children: tGlobal(tab.title) })] }), children: _jsx(TabComponent, { userId: userId }) }, tab.key));
138
163
  })] }) }) })] }));
139
164
  }
@@ -1 +1 @@
1
- {"version":3,"file":"users-by-signup-source.d.ts","sourceRoot":"","sources":["../../../src/web/admin/users-by-signup-source.tsx"],"names":[],"mappings":"AAsCA,wBAAgB,uBAAuB,4CA+NtC"}
1
+ {"version":3,"file":"users-by-signup-source.d.ts","sourceRoot":"","sources":["../../../src/web/admin/users-by-signup-source.tsx"],"names":[],"mappings":"AAuCA,wBAAgB,uBAAuB,4CAqQtC"}
@@ -1,9 +1,11 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from "react";
4
+ import { useModuleTranslation } from "@lastbrain/core";
4
5
  import { Card, CardBody, CardHeader, Chip, Input, Pagination, Select, SelectItem, Spinner, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow, } from "@lastbrain/ui";
5
6
  import { Search, Users } from "lucide-react";
6
7
  export function UsersBySignupSourcePage() {
8
+ const t = useModuleTranslation("auth");
7
9
  const [users, setUsers] = useState([]);
8
10
  const [loading, setLoading] = useState(true);
9
11
  const [error, setError] = useState(null);
@@ -27,7 +29,8 @@ export function UsersBySignupSourcePage() {
27
29
  }
28
30
  const response = await fetch(url);
29
31
  if (!response.ok) {
30
- throw new Error("Erreur lors du chargement des utilisateurs");
32
+ throw new Error(t("users_by_source.loading_error") ||
33
+ "Erreur lors du chargement des utilisateurs");
31
34
  }
32
35
  const result = await response.json();
33
36
  // Filter by search query if provided
@@ -40,7 +43,10 @@ export function UsersBySignupSourcePage() {
40
43
  setPagination(result.pagination);
41
44
  }
42
45
  catch (err) {
43
- setError(err instanceof Error ? err.message : "Erreur lors du chargement");
46
+ setError(err instanceof Error
47
+ ? err.message
48
+ : t("users_by_source.loading_error_generic") ||
49
+ "Erreur lors du chargement");
44
50
  }
45
51
  finally {
46
52
  setLoading(false);
@@ -64,16 +70,21 @@ export function UsersBySignupSourcePage() {
64
70
  if (error) {
65
71
  return (_jsx("div", { className: "p-6", children: _jsx(Card, { className: "border border-danger-200 bg-danger-50/50", children: _jsx(CardBody, { children: _jsx("p", { className: "text-danger-600", children: error }) }) }) }));
66
72
  }
67
- return (_jsxs("div", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(Users, { size: 28, className: "text-primary-600" }), _jsx("h1", { className: "text-3xl font-bold", children: "Utilisateurs par source d'inscription" })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsx(Input, { placeholder: "Rechercher par email ou nom...", value: searchQuery, onChange: handleSearch, startContent: _jsx(Search, { size: 16 }), isClearable: true, onClear: () => {
73
+ return (_jsxs("div", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(Users, { size: 28, className: "text-primary-600" }), _jsx("h1", { className: "text-3xl font-bold", children: t("users_by_source.title") ||
74
+ "Utilisateurs par source d'inscription" })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsx(Input, { placeholder: t("users_by_source.search_placeholder") ||
75
+ "Rechercher par email ou nom...", value: searchQuery, onChange: handleSearch, startContent: _jsx(Search, { size: 16 }), isClearable: true, onClear: () => {
68
76
  setSearchQuery("");
69
77
  fetchUsers(1, source, "");
70
- } }), _jsxs(Select, { label: "Filtrer par source", selectedKeys: [source], onChange: (e) => handleSourceChange(e.target.value), children: [_jsx(SelectItem, { children: "Toutes les sources" }, ""), _jsx(SelectItem, { children: "LastBrain" }, "lastbrain"), _jsx(SelectItem, { children: "Recipe" }, "recipe")] })] }), _jsxs("div", { className: "text-sm text-default-600", children: ["Affichage de", " ", _jsxs("span", { className: "font-semibold", children: [(pagination.page - 1) * pagination.limit + 1, "-", Math.min(pagination.page * pagination.limit, pagination.total)] }), " ", "sur ", _jsx("span", { className: "font-semibold", children: pagination.total }), " ", "utilisateurs"] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Liste des utilisateurs" }) }), _jsx(CardBody, { children: loading ? (_jsx("div", { className: "flex justify-center py-8", children: _jsx(Spinner, { size: "lg", label: "Chargement..." }) })) : (_jsxs(_Fragment, { children: [_jsxs(Table, { "aria-label": "Tableau des utilisateurs", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: "Nom" }), _jsx(TableColumn, { children: "Email" }), _jsx(TableColumn, { children: "Source" }), _jsx(TableColumn, { children: "Date d'inscription" })] }), _jsx(TableBody, { children: users.length > 0 ? (users.map((user) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx("span", { className: "font-medium", children: user.name }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-sm text-default-600", children: user.email }) }), _jsx(TableCell, { children: _jsx(Chip, { size: "sm", color: getSourceColor(user.signup_source), variant: "flat", children: user.signup_source.toLowerCase() === "recipe"
71
- ? "🍳 Recipe"
72
- : "🧠 LastBrain" }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-sm text-default-500", children: new Date(user.created_at).toLocaleDateString("fr-FR", {
78
+ } }), _jsxs(Select, { label: t("users_by_source.filter_label") || "Filtrer par source", selectedKeys: [source], onChange: (e) => handleSourceChange(e.target.value), children: [_jsx(SelectItem, { children: t("users_by_source.all_sources") || "Toutes les sources" }, ""), _jsx(SelectItem, { children: t("users_by_source.source_lastbrain") || "LastBrain" }, "lastbrain"), _jsx(SelectItem, { children: t("users_by_source.source_recipe") || "Recipe" }, "recipe")] })] }), _jsxs("div", { className: "text-sm text-default-600", children: [t("users_by_source.showing") || "Affichage de", " ", _jsxs("span", { className: "font-semibold", children: [(pagination.page - 1) * pagination.limit + 1, "-", Math.min(pagination.page * pagination.limit, pagination.total)] }), " ", t("users_by_source.of") || "sur", " ", _jsx("span", { className: "font-semibold", children: pagination.total }), " ", t("users_by_source.users") || "utilisateurs"] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("users_by_source.list_title") || "Liste des utilisateurs" }) }), _jsx(CardBody, { children: loading ? (_jsx("div", { className: "flex justify-center py-8", children: _jsx(Spinner, { size: "lg", label: t("users_by_source.loading") || "Chargement..." }) })) : (_jsxs(_Fragment, { children: [_jsxs(Table, { "aria-label": t("users_by_source.table_aria_label") ||
79
+ "Tableau des utilisateurs", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: t("users_by_source.column_name") || "Nom" }), _jsx(TableColumn, { children: t("users_by_source.column_email") || "Email" }), _jsx(TableColumn, { children: t("users_by_source.column_source") || "Source" }), _jsx(TableColumn, { children: t("users_by_source.column_signup_date") ||
80
+ "Date d'inscription" })] }), _jsx(TableBody, { children: users.length > 0 ? (users.map((user) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx("span", { className: "font-medium", children: user.name }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-sm text-default-600", children: user.email }) }), _jsx(TableCell, { children: _jsx(Chip, { size: "sm", color: getSourceColor(user.signup_source), variant: "flat", children: user.signup_source.toLowerCase() === "recipe"
81
+ ? `🍳 ${t("users_by_source.recipe") || "Recipe"}`
82
+ : `🧠 ${t("users_by_source.lastbrain") || "LastBrain"}` }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-sm text-default-500", children: new Date(user.created_at).toLocaleDateString("fr-FR", {
73
83
  year: "2-digit",
74
84
  month: "2-digit",
75
85
  day: "2-digit",
76
86
  hour: "2-digit",
77
87
  minute: "2-digit",
78
- }) }) })] }, user.id)))) : (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 4, className: "text-center py-8", children: _jsx("p", { className: "text-default-500", children: "Aucun utilisateur trouv\u00E9" }) }) })) })] }), pagination.totalPages > 1 && (_jsx("div", { className: "flex justify-center mt-6", children: _jsx(Pagination, { total: pagination.totalPages, page: pagination.page, onChange: handlePageChange, showControls: true }) }))] })) })] })] }));
88
+ }) }) })] }, user.id)))) : (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 4, className: "text-center py-8", children: _jsx("p", { className: "text-default-500", children: t("users_by_source.no_users") ||
89
+ "Aucun utilisateur trouvé" }) }) })) })] }), pagination.totalPages > 1 && (_jsx("div", { className: "flex justify-center mt-6", children: _jsx(Pagination, { total: pagination.totalPages, page: pagination.page, onChange: handlePageChange, showControls: true }) }))] })) })] })] }));
79
90
  }
@@ -1 +1 @@
1
- {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/web/admin/users.tsx"],"names":[],"mappings":"AA6CA,wBAAgB,cAAc,4CAmP7B"}
1
+ {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/web/admin/users.tsx"],"names":[],"mappings":"AA8CA,wBAAgB,cAAc,4CAyQ7B"}