@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.
- package/dist/auth.build.config.d.ts.map +1 -1
- package/dist/auth.build.config.js +33 -47
- package/dist/components/AccountButton.d.ts.map +1 -1
- package/dist/components/AccountButton.js +9 -5
- package/dist/web/admin/signup-stats.d.ts.map +1 -1
- package/dist/web/admin/signup-stats.js +4 -2
- package/dist/web/admin/user-detail.d.ts.map +1 -1
- package/dist/web/admin/user-detail.js +42 -17
- package/dist/web/admin/users-by-signup-source.d.ts.map +1 -1
- package/dist/web/admin/users-by-signup-source.js +18 -7
- package/dist/web/admin/users.d.ts.map +1 -1
- package/dist/web/admin/users.js +11 -6
- package/dist/web/auth/dashboard.d.ts.map +1 -1
- package/dist/web/auth/dashboard.js +7 -3
- package/dist/web/auth/folder.d.ts.map +1 -1
- package/dist/web/auth/folder.js +5 -3
- package/dist/web/auth/profile.d.ts.map +1 -1
- package/dist/web/auth/profile.js +13 -6
- package/dist/web/auth/reglage.d.ts.map +1 -1
- package/dist/web/auth/reglage.js +11 -6
- package/dist/web/public/SignInPage.d.ts.map +1 -1
- package/dist/web/public/SignInPage.js +14 -56
- package/dist/web/public/SignUpPage.d.ts.map +1 -1
- package/dist/web/public/SignUpPage.js +18 -11
- package/package.json +4 -3
- package/src/auth.build.config.ts +34 -48
- package/src/components/AccountButton.tsx +17 -10
- package/src/i18n/en.json +263 -0
- package/src/i18n/fr.json +261 -0
- package/src/web/admin/signup-stats.tsx +10 -3
- package/src/web/admin/user-detail.tsx +135 -56
- package/src/web/admin/users-by-signup-source.tsx +60 -21
- package/src/web/admin/users.tsx +41 -18
- package/src/web/auth/dashboard.tsx +25 -9
- package/src/web/auth/folder.tsx +11 -3
- package/src/web/auth/profile.tsx +63 -29
- package/src/web/auth/reglage.tsx +43 -19
- package/src/web/public/SignInPage.tsx +32 -70
- package/src/web/public/SignUpPage.tsx +48 -26
- package/supabase/migrations/20251112000000_user_init.sql +35 -19
- package/supabase/migrations/20251112000001_auto_profile_and_admin_view.sql +8 -3
- package/supabase/migrations/20251112000002_sync_avatars.sql +7 -1
- 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,
|
|
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: "
|
|
143
|
-
description: "
|
|
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: "
|
|
153
|
-
description: "
|
|
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: "
|
|
163
|
-
description: "
|
|
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: "
|
|
175
|
-
description: "
|
|
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: "
|
|
184
|
-
description: "
|
|
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: "
|
|
191
|
-
description: "
|
|
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: "
|
|
201
|
-
description: "
|
|
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: "
|
|
211
|
-
description: "
|
|
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: "
|
|
223
|
-
description: "
|
|
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: "
|
|
232
|
-
description: "
|
|
231
|
+
title: "module-auth.menu.folder",
|
|
232
|
+
description: "module-auth.menu.folder_desc",
|
|
233
233
|
icon: "FolderOpen",
|
|
234
234
|
path: "/auth/folder",
|
|
235
|
-
order:
|
|
235
|
+
order: 99,
|
|
236
236
|
shortcut: "cmd+shift+f",
|
|
237
237
|
shortcutDisplay: "⌘⇧F",
|
|
238
238
|
},
|
|
239
239
|
{
|
|
240
|
-
title: "
|
|
241
|
-
description: "
|
|
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: "
|
|
251
|
-
description: "
|
|
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: "
|
|
261
|
-
description: "
|
|
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: "
|
|
273
|
-
description: "
|
|
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: "
|
|
282
|
-
description: "
|
|
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: "
|
|
291
|
-
description: "
|
|
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;
|
|
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 {
|
|
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:
|
|
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:
|
|
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":"
|
|
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":"
|
|
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("
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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
|
|
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: "
|
|
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", " ", "
|
|
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
|
|
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 }), "
|
|
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:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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: "
|
|
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:
|
|
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":"
|
|
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("
|
|
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
|
|
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:
|
|
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":
|
|
71
|
-
|
|
72
|
-
|
|
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: "
|
|
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":"
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/web/admin/users.tsx"],"names":[],"mappings":"AA8CA,wBAAgB,cAAc,4CAyQ7B"}
|