@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
@@ -3,9 +3,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { useCallback, useEffect, useState, useId } from "react";
4
4
  import { Card, CardBody, CardHeader, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Spinner, Chip, Input, Button, Pagination, Avatar, } from "@lastbrain/ui";
5
5
  import { Search, RefreshCw, Eye, Users2 } from "lucide-react";
6
- import { useRouter } from "next/navigation";
6
+ import { useModuleTranslation } from "@lastbrain/core";
7
+ import { useLocalizedRouter } from "@lastbrain/core";
7
8
  export function AdminUsersPage() {
8
- const router = useRouter();
9
+ const router = useLocalizedRouter();
10
+ const t = useModuleTranslation("auth");
9
11
  const searchInputId = useId();
10
12
  const [users, setUsers] = useState([]);
11
13
  const [isLoading, setIsLoading] = useState(true);
@@ -76,16 +78,19 @@ export function AdminUsersPage() {
76
78
  if (error && users.length === 0) {
77
79
  return (_jsx("div", { className: "pt-12 pb-12 max-w-7xl mx-auto px-4", children: _jsx(Card, { children: _jsx(CardBody, { children: _jsx("p", { className: "text-danger", children: error }) }) }) }));
78
80
  }
79
- return (_jsxs("div", { className: "pt-12 pb-12 max-w-7xl mx-auto px-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(Users2, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: "User Management" })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex flex-col md:flex-row gap-4 w-full", children: [_jsxs("div", { className: "flex gap-2 flex-1", children: [_jsx(Input, { id: searchInputId, placeholder: "Search by email or name...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onKeyPress: (e) => {
81
+ return (_jsxs("div", { className: "pt-12 pb-12 max-w-7xl mx-auto px-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(Users2, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: t("users.title") || "User Management" })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex flex-col md:flex-row gap-4 w-full", children: [_jsxs("div", { className: "flex gap-2 flex-1", children: [_jsx(Input, { id: searchInputId, placeholder: t("users.search_placeholder") || "Search by email or name...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onKeyPress: (e) => {
80
82
  if (e.key === "Enter") {
81
83
  handleSearch();
82
84
  }
83
- }, startContent: _jsx(Search, { className: "w-4 h-4 text-default-400" }), className: "flex-1" }), _jsx(Button, { color: "primary", onPress: handleSearch, isDisabled: isLoading, children: "Search" })] }), _jsx(Button, { variant: "flat", onPress: fetchUsers, isDisabled: isLoading, startContent: _jsx(RefreshCw, { className: "w-4 h-4" }), children: "Refresh" })] }) }), _jsx(CardBody, { children: isLoading ? (_jsx("div", { className: "flex justify-center items-center py-12", children: _jsx(Spinner, { size: "lg", label: "Loading users..." }) })) : users.length === 0 ? (_jsx("div", { className: "text-center py-12 text-default-500", children: "No users found" })) : (_jsxs(_Fragment, { children: [_jsxs(Table, { isStriped: true, "aria-label": "Users table", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: "USER" }), _jsx(TableColumn, { children: "EMAIL" }), _jsx(TableColumn, { children: "ROLE" }), _jsx(TableColumn, { children: "LAST SIGN IN" }), _jsx(TableColumn, { children: "CREATED" }), _jsx(TableColumn, { children: "ACTIONS" })] }), _jsx(TableBody, { children: users.map((user) => {
85
+ }, startContent: _jsx(Search, { className: "w-4 h-4 text-default-400" }), className: "flex-1" }), _jsx(Button, { color: "primary", onPress: handleSearch, isDisabled: isLoading, children: t("users.search_button") || "Search" })] }), _jsx(Button, { variant: "flat", onPress: fetchUsers, isDisabled: isLoading, startContent: _jsx(RefreshCw, { className: "w-4 h-4" }), children: t("users.refresh_button") || "Refresh" })] }) }), _jsx(CardBody, { children: isLoading ? (_jsx("div", { className: "flex justify-center items-center py-12", children: _jsx(Spinner, { size: "lg", label: t("users.loading_users") || "Loading users..." }) })) : users.length === 0 ? (_jsx("div", { className: "text-center py-12 text-default-500", children: t("users.no_users_found") || "No users found" })) : (_jsxs(_Fragment, { children: [_jsxs(Table, { isStriped: true, "aria-label": t("users.table_aria_label") || "Users table", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: t("users.column_user") || "USER" }), _jsx(TableColumn, { children: t("users.column_email") || "EMAIL" }), _jsx(TableColumn, { children: t("users.column_role") || "ROLE" }), _jsx(TableColumn, { children: t("users.column_last_sign_in") || "LAST SIGN IN" }), _jsx(TableColumn, { children: t("users.column_created") || "CREATED" }), _jsx(TableColumn, { children: t("users.column_actions") || "ACTIONS" })] }), _jsx(TableBody, { children: users.map((user) => {
84
86
  const displayName = user.full_name || user.email;
85
87
  return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Avatar, { isBordered: true, src: user.avatar_url
86
88
  ? `/api/storage/${user.avatar_url}`
87
89
  : undefined, name: displayName, size: "sm" }), _jsx("span", { className: "text-small font-medium", children: displayName })] }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-small", children: user.email }) }), _jsx(TableCell, { children: _jsx(Chip, { size: "sm", variant: "flat", color: user.role === "admin" ? "danger" : "default", children: user.role || "user" }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-small", children: user.last_sign_in_at
88
90
  ? formatDate(user.last_sign_in_at)
89
- : "Jamais" }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-small", children: formatDate(user.created_at) }) }), _jsx(TableCell, { children: _jsx(Button, { size: "sm", variant: "flat", color: "primary", onPress: () => handleViewUser(user.id), startContent: _jsx(Eye, { size: 14 }), children: "Voir" }) })] }, user.id));
90
- }) })] }), pagination.total_pages > 1 && (_jsx("div", { className: "flex justify-center mt-4", children: _jsx(Pagination, { total: pagination.total_pages, page: pagination.page, onChange: handlePageChange, showControls: true }) })), _jsxs("div", { className: "mt-4 text-small text-default-500 text-center", children: ["Showing ", users.length, " of ", pagination.total, " users"] })] })) })] })] }));
91
+ : t("users.never") || "Jamais" }) }), _jsx(TableCell, { children: _jsx("span", { className: "text-small", children: formatDate(user.created_at) }) }), _jsx(TableCell, { children: _jsx(Button, { size: "sm", variant: "flat", color: "primary", onPress: () => handleViewUser(user.id), startContent: _jsx(Eye, { size: 14 }), children: t("users.view_button") || "Voir" }) })] }, user.id));
92
+ }) })] }), pagination.total_pages > 1 && (_jsx("div", { className: "flex justify-center mt-4", children: _jsx(Pagination, { total: pagination.total_pages, page: pagination.page, onChange: handlePageChange, showControls: true }) })), _jsx("div", { className: "mt-4 text-small text-default-500 text-center", children: t("users.showing_results")
93
+ ?.replace("{{count}}", users.length.toString())
94
+ .replace("{{total}}", pagination.total.toString()) ||
95
+ `Showing ${users.length} of ${pagination.total} users` })] })) })] })] }));
91
96
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../../src/web/auth/dashboard.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,aAAa,mDAoL5B"}
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../../src/web/auth/dashboard.tsx"],"names":[],"mappings":"AA8BA,wBAAgB,aAAa,mDAmM5B"}
@@ -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, Spinner, Chip, Divider, Avatar, } from "@lastbrain/ui";
5
5
  import { User, Mail, Calendar, Shield } from "lucide-react";
6
+ import { useModuleTranslation } from "@lastbrain/core";
6
7
  export function DashboardPage() {
8
+ const t = useModuleTranslation("auth");
7
9
  const [userData, setUserData] = useState(null);
8
10
  const [isLoading, setIsLoading] = useState(true);
9
11
  const [error, setError] = useState(null);
@@ -28,10 +30,10 @@ export function DashboardPage() {
28
30
  }
29
31
  };
30
32
  if (isLoading) {
31
- return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsxs(Spinner, { color: "primary", size: "lg", children: [" ", _jsx("span", { className: "text-xs text-default-700", children: "Loading dashboard..." })] }) }));
33
+ return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsxs(Spinner, { color: "primary", size: "lg", children: [" ", _jsx("span", { className: "text-xs text-default-700", children: t("dashboard.loading") || "Loading dashboard..." })] }) }));
32
34
  }
33
35
  if (error) {
34
- return (_jsx("div", { className: "pt-12", children: _jsx(Card, { className: "max-w-2xl mx-auto", children: _jsx(CardBody, { children: _jsxs("p", { className: "text-danger", children: ["Error: ", error] }) }) }) }));
36
+ return (_jsx("div", { className: "pt-12", children: _jsx(Card, { className: "max-w-2xl mx-auto", children: _jsx(CardBody, { children: _jsxs("p", { className: "text-danger", children: [t("dashboard.error") || "Error", ": ", error] }) }) }) }));
35
37
  }
36
38
  if (!userData) {
37
39
  return null;
@@ -39,6 +41,8 @@ export function DashboardPage() {
39
41
  const fullName = userData.profile?.first_name && userData.profile?.last_name
40
42
  ? `${userData.profile.first_name} ${userData.profile.last_name}`
41
43
  : "User";
42
- return (_jsxs("div", { className: "pt-12 pb-12 max-w-6xl mx-auto px-4", children: [_jsx("h1", { className: "text-3xl font-bold mb-8", children: "Dashboard" }), _jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [_jsxs(Card, { className: "col-span-full md:col-span-1", children: [_jsxs(CardHeader, { className: "flex gap-3", children: [_jsx(Avatar, { src: userData.profile?.avatar_url, icon: _jsx(User, {}), size: "lg", className: "shrink-0" }), _jsxs("div", { className: "flex flex-col", children: [_jsx("p", { className: "text-xl font-semibold", children: fullName }), _jsx("p", { className: "text-small text-default-500", children: userData.email })] })] }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Mail, { className: "w-4 h-4 text-default-400" }), _jsx("span", { className: "text-small", children: userData.email })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "w-4 h-4 text-default-400" }), _jsxs("span", { className: "text-small", children: ["Member since", " ", new Date(userData.created_at).toLocaleDateString()] })] }), userData.profile?.company && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Shield, { className: "w-4 h-4 text-default-400" }), _jsx("span", { className: "text-small", children: userData.profile.company })] }))] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Account Status" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-small", children: "Status" }), _jsx(Chip, { color: "success", size: "sm", variant: "flat", children: "Active" })] }), _jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-small", children: "Profile" }), _jsx(Chip, { color: userData.profile ? "success" : "warning", size: "sm", variant: "flat", children: userData.profile ? "Complete" : "Incomplete" })] })] }) })] }), userData.profile?.bio && (_jsxs(Card, { className: "col-span-full", children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Bio" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsx("p", { className: "text-small text-default-600", children: userData.profile.bio }) })] })), _jsxs(Card, { className: "col-span-full", children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Quick Stats" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [_jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-primary", children: "0" }), _jsx("p", { className: "text-small text-default-500", children: "Projects" })] }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-success", children: "0" }), _jsx("p", { className: "text-small text-default-500", children: "Tasks" })] }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-warning", children: "0" }), _jsx("p", { className: "text-small text-default-500", children: "Notifications" })] }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-secondary", children: Math.floor((Date.now() - new Date(userData.created_at).getTime()) /
44
+ return (_jsxs("div", { className: "pt-12 pb-12 max-w-6xl mx-auto px-4", children: [_jsx("h1", { className: "text-3xl font-bold mb-8", children: t("dashboard.title") || "Dashboard" }), _jsxs("div", { className: "grid gap-6 md:grid-cols-2", children: [_jsxs(Card, { className: "col-span-full md:col-span-1", children: [_jsxs(CardHeader, { className: "flex gap-3", children: [_jsx(Avatar, { src: userData.profile?.avatar_url, icon: _jsx(User, {}), size: "lg", className: "shrink-0" }), _jsxs("div", { className: "flex flex-col", children: [_jsx("p", { className: "text-xl font-semibold", children: fullName }), _jsx("p", { className: "text-small text-default-500", children: userData.email })] })] }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Mail, { className: "w-4 h-4 text-default-400" }), _jsx("span", { className: "text-small", children: userData.email })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "w-4 h-4 text-default-400" }), _jsxs("span", { className: "text-small", children: [t("dashboard.member_since") || "Member since", " ", new Date(userData.created_at).toLocaleDateString()] })] }), userData.profile?.company && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Shield, { className: "w-4 h-4 text-default-400" }), _jsx("span", { className: "text-small", children: userData.profile.company })] }))] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("dashboard.account_status") || "Account Status" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-small", children: t("dashboard.status") || "Status" }), _jsx(Chip, { color: "success", size: "sm", variant: "flat", children: t("dashboard.active") || "Active" })] }), _jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-small", children: t("dashboard.profile") || "Profile" }), _jsx(Chip, { color: userData.profile ? "success" : "warning", size: "sm", variant: "flat", children: userData.profile
45
+ ? t("dashboard.complete") || "Complete"
46
+ : t("dashboard.incomplete") || "Incomplete" })] })] }) })] }), userData.profile?.bio && (_jsxs(Card, { className: "col-span-full", children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Bio" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsx("p", { className: "text-small text-default-600", children: userData.profile.bio }) })] })), _jsxs(Card, { className: "col-span-full", children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Quick Stats" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [_jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-primary", children: "0" }), _jsx("p", { className: "text-small text-default-500", children: "Projects" })] }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-success", children: "0" }), _jsx("p", { className: "text-small text-default-500", children: "Tasks" })] }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-warning", children: "0" }), _jsx("p", { className: "text-small text-default-500", children: "Notifications" })] }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "text-2xl font-bold text-secondary", children: Math.floor((Date.now() - new Date(userData.created_at).getTime()) /
43
47
  (1000 * 60 * 60 * 24)) }), _jsx("p", { className: "text-small text-default-500", children: "Days active" })] })] }) })] })] })] }));
44
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"folder.d.ts","sourceRoot":"","sources":["../../../src/web/auth/folder.tsx"],"names":[],"mappings":"AAoBA,wBAAgB,UAAU,mDAoEzB"}
1
+ {"version":3,"file":"folder.d.ts","sourceRoot":"","sources":["../../../src/web/auth/folder.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,UAAU,mDA2EzB"}
@@ -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, Spinner } from "@lastbrain/ui";
5
5
  import { FileManager } from "@lastbrain/ui";
6
+ import { useModuleTranslation } from "@lastbrain/core";
6
7
  export function FolderPage() {
8
+ const t = useModuleTranslation("auth");
7
9
  const [userData, setUserData] = useState(null);
8
10
  const [isLoading, setIsLoading] = useState(true);
9
11
  const [error, setError] = useState(null);
@@ -28,13 +30,13 @@ export function FolderPage() {
28
30
  }
29
31
  };
30
32
  if (isLoading) {
31
- return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsxs(Spinner, { color: "primary", size: "lg", children: [" ", _jsx("span", { className: "text-xs text-default-700", children: "Loading folder..." })] }) }));
33
+ return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsxs(Spinner, { color: "primary", size: "lg", children: [" ", _jsx("span", { className: "text-xs text-default-700", children: t("folder.loading") || "Loading folder..." })] }) }));
32
34
  }
33
35
  if (error) {
34
- return (_jsx("div", { className: "pt-12", children: _jsx(Card, { className: "max-w-2xl mx-auto", children: _jsx(CardBody, { children: _jsxs("p", { className: "text-danger", children: ["Error: ", error] }) }) }) }));
36
+ return (_jsx("div", { className: "pt-12", children: _jsx(Card, { className: "max-w-2xl mx-auto", children: _jsx(CardBody, { children: _jsxs("p", { className: "text-danger", children: [t("folder.error") || "Error", ": ", error] }) }) }) }));
35
37
  }
36
38
  if (!userData) {
37
39
  return null;
38
40
  }
39
- return (_jsxs("div", { className: "pt-4 pb-12 max-w-8xl mx-auto px-4", children: [_jsx("h1", { className: "text-3xl font-bold mb-8", children: "Dossier" }), _jsx(FileManager, { bucket: "app", basePath: userData.id, allowUpload: true, allowCreateFolder: true, allowAIImageGeneration: false, className: "min-h-[80vh]" })] }));
41
+ return (_jsxs("div", { className: "pt-4 pb-12 max-w-8xl mx-auto px-4", children: [_jsx("h1", { className: "text-3xl font-bold mb-8", children: t("folder.title") || "Dossier" }), _jsx(FileManager, { bucket: "app", basePath: userData.id, allowUpload: true, allowCreateFolder: true, allowAIImageGeneration: false, className: "min-h-[80vh]" })] }));
40
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../../src/web/auth/profile.tsx"],"names":[],"mappings":"AAyCA,wBAAgB,WAAW,4CA6X1B"}
1
+ {"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../../src/web/auth/profile.tsx"],"names":[],"mappings":"AA0CA,wBAAgB,WAAW,4CA8Z1B"}
@@ -3,9 +3,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from "react";
4
4
  import { Card, CardBody, CardHeader, Input, Textarea, Button, Spinner, Divider, addToast, AvatarUploader, } from "@lastbrain/ui";
5
5
  import { Save, User } from "lucide-react";
6
+ import { useModuleTranslation } from "@lastbrain/core";
6
7
  import { uploadFile, deleteFilesWithPrefix } from "../../api/storage";
7
8
  import { supabaseBrowserClient } from "@lastbrain/core";
8
9
  export function ProfilePage() {
10
+ const t = useModuleTranslation("auth");
9
11
  const [profile, setProfile] = useState({});
10
12
  const [isLoading, setIsLoading] = useState(true);
11
13
  const [isSaving, setIsSaving] = useState(false);
@@ -64,8 +66,8 @@ export function ProfilePage() {
64
66
  throw new Error("Failed to update profile");
65
67
  }
66
68
  addToast({
67
- title: "Success",
68
- description: "Profile updated successfully",
69
+ title: t("profile.success") || "Success",
70
+ description: t("profile.updated") || "Profile updated successfully",
69
71
  color: "success",
70
72
  });
71
73
  }
@@ -73,8 +75,8 @@ export function ProfilePage() {
73
75
  console.error("Error updating profile:", err);
74
76
  setError(err instanceof Error ? err.message : "An error occurred");
75
77
  addToast({
76
- title: "Error",
77
- description: "Failed to update profile",
78
+ title: t("profile.error") || "Error",
79
+ description: t("profile.update_failed") || "Failed to update profile",
78
80
  color: "danger",
79
81
  });
80
82
  }
@@ -172,7 +174,7 @@ export function ProfilePage() {
172
174
  setProfile((prev) => ({ ...prev, avatar_url: "" }));
173
175
  };
174
176
  if (isLoading) {
175
- return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsx(Spinner, { size: "lg", label: "Loading profile..." }) }));
177
+ return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsx(Spinner, { size: "lg", label: t("profile.loading") || "Loading profile..." }) }));
176
178
  }
177
179
  return (_jsx("div", { className: "pt-12 pb-12 max-w-4xl mx-auto px-4", children: _jsx("form", { onSubmit: handleSubmit, children: _jsxs("div", { className: "space-y-6", children: [_jsx("div", { className: "flex justify-center", children: _jsx(AvatarUploader, { userId: currentUser?.id, bucket: "avatar", shape: "circle", onUpload: handleAvatarUpload, onDelete: handleAvatarDelete, initialAvatarPath: currentUser?.user_metadata?.avatar ||
178
180
  profile.avatar_url ||
@@ -190,5 +192,10 @@ export function ProfilePage() {
190
192
  setProfile((prev) => ({ ...prev, avatar_url: urls.large }));
191
193
  }, onDeleted: () => {
192
194
  setProfile((prev) => ({ ...prev, avatar_url: "" }));
193
- } }) }), _jsxs("div", { className: "flex items-center gap-2 mb-4", children: [_jsx(User, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: "Edit Profile" })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Personal Information" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsx(Input, { label: "First Name", placeholder: "Enter your first name", value: profile.first_name || "", onChange: (e) => handleChange("first_name", e.target.value) }), _jsx(Input, { label: "Last Name", placeholder: "Enter your last name", value: profile.last_name || "", onChange: (e) => handleChange("last_name", e.target.value) }), _jsx(Input, { label: "Phone", placeholder: "Enter your phone number", type: "tel", value: profile.phone || "", onChange: (e) => handleChange("phone", e.target.value), className: "md:col-span-2" }), _jsx(Textarea, { label: "Bio", placeholder: "Tell us about yourself", value: profile.bio || "", onChange: (e) => handleChange("bio", e.target.value), minRows: 3, className: "md:col-span-2" })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Professional Information" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsx(Input, { label: "Company", placeholder: "Enter your company name", value: profile.company || "", onChange: (e) => handleChange("company", e.target.value) }), _jsx(Input, { label: "Website", placeholder: "https://example.com", type: "url", value: profile.website || "", onChange: (e) => handleChange("website", e.target.value) }), _jsx(Input, { label: "Location", placeholder: "City, Country", value: profile.location || "", onChange: (e) => handleChange("location", e.target.value), className: "md:col-span-2" })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Preferences" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsx(Input, { label: "Language", placeholder: "en, fr, es...", value: profile.language || "", onChange: (e) => handleChange("language", e.target.value) }), _jsx(Input, { label: "Timezone", placeholder: "Europe/Paris, America/New_York...", value: profile.timezone || "", onChange: (e) => handleChange("timezone", e.target.value) })] }) })] }), _jsxs("div", { className: "flex justify-end gap-3", children: [_jsx(Button, { type: "button", variant: "flat", onPress: () => fetchProfile(), isDisabled: isSaving, children: "Cancel" }), _jsx(Button, { type: "submit", color: "primary", isLoading: isSaving, startContent: !isSaving && _jsx(Save, { className: "w-4 h-4" }), children: isSaving ? "Saving..." : "Save Changes" })] })] }) }) }));
195
+ } }) }), _jsxs("div", { className: "flex items-center gap-2 mb-4", children: [_jsx(User, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: t("profile.edit") || "Edit Profile" })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("profile.personal_info") || "Personal Information" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsx(Input, { label: t("profile.first_name") || "First Name", placeholder: t("profile.first_name_placeholder") ||
196
+ "Enter your first name", value: profile.first_name || "", onChange: (e) => handleChange("first_name", e.target.value) }), _jsx(Input, { label: t("profile.last_name") || "Last Name", placeholder: t("profile.last_name_placeholder") || "Enter your last name", value: profile.last_name || "", onChange: (e) => handleChange("last_name", e.target.value) }), _jsx(Input, { label: t("profile.phone") || "Phone", placeholder: t("profile.phone_placeholder") || "Enter your phone number", type: "tel", value: profile.phone || "", onChange: (e) => handleChange("phone", e.target.value), className: "md:col-span-2" }), _jsx(Textarea, { label: t("profile.bio") || "Bio", placeholder: t("profile.bio_placeholder") || "Tell us about yourself", value: profile.bio || "", onChange: (e) => handleChange("bio", e.target.value), minRows: 3, className: "md:col-span-2" })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("profile.professional_info") || "Professional Information" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsx(Input, { label: t("profile.company") || "Company", placeholder: t("profile.company_placeholder") ||
197
+ "Enter your company name", value: profile.company || "", onChange: (e) => handleChange("company", e.target.value) }), _jsx(Input, { label: t("profile.website") || "Website", placeholder: t("profile.website_placeholder") || "https://example.com", type: "url", value: profile.website || "", onChange: (e) => handleChange("website", e.target.value) }), _jsx(Input, { label: t("profile.location") || "Location", placeholder: t("profile.location_placeholder") || "City, Country", value: profile.location || "", onChange: (e) => handleChange("location", e.target.value), className: "md:col-span-2" })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("profile.preferences") || "Preferences" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsx(Input, { label: t("profile.language") || "Language", placeholder: t("profile.language_placeholder") || "en, fr, es...", value: profile.language || "", onChange: (e) => handleChange("language", e.target.value) }), _jsx(Input, { label: t("profile.timezone") || "Timezone", placeholder: t("profile.timezone_placeholder") ||
198
+ "Europe/Paris, America/New_York...", value: profile.timezone || "", onChange: (e) => handleChange("timezone", e.target.value) })] }) })] }), _jsxs("div", { className: "flex justify-end gap-3", children: [_jsx(Button, { type: "button", variant: "flat", onPress: () => fetchProfile(), isDisabled: isSaving, children: t("profile.cancel_button") || "Cancel" }), _jsx(Button, { type: "submit", color: "primary", isLoading: isSaving, startContent: !isSaving && _jsx(Save, { className: "w-4 h-4" }), children: isSaving
199
+ ? t("profile.saving") || "Saving..."
200
+ : t("profile.save_button") || "Save Changes" })] })] }) }) }));
194
201
  }
@@ -1 +1 @@
1
- {"version":3,"file":"reglage.d.ts","sourceRoot":"","sources":["../../../src/web/auth/reglage.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,WAAW,4CA6P1B"}
1
+ {"version":3,"file":"reglage.d.ts","sourceRoot":"","sources":["../../../src/web/auth/reglage.tsx"],"names":[],"mappings":"AAiCA,wBAAgB,WAAW,4CAoR1B"}
@@ -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, Switch, Button, Spinner, Divider, Select, SelectItem, addToast, } from "@lastbrain/ui";
5
5
  import { Settings, Save } from "lucide-react";
6
+ import { useModuleTranslation } from "@lastbrain/core";
6
7
  export function ReglagePage() {
8
+ const t = useModuleTranslation("auth");
7
9
  const [preferences, setPreferences] = useState({
8
10
  email_notifications: true,
9
11
  push_notifications: false,
@@ -70,16 +72,16 @@ export function ReglagePage() {
70
72
  throw new Error("Failed to update settings");
71
73
  }
72
74
  addToast({
73
- title: "Success",
74
- description: "Settings updated successfully",
75
+ title: t("settings.success") || "Success",
76
+ description: t("settings.updated") || "Settings updated successfully",
75
77
  color: "success",
76
78
  });
77
79
  }
78
80
  catch (err) {
79
81
  console.error("Error updating settings:", err);
80
82
  addToast({
81
- title: "Error",
82
- description: "Failed to update settings",
83
+ title: t("settings.error") || "Error",
84
+ description: t("settings.update_failed") || "Failed to update settings",
83
85
  color: "danger",
84
86
  });
85
87
  }
@@ -94,7 +96,10 @@ export function ReglagePage() {
94
96
  setPreferences((prev) => ({ ...prev, [key]: value }));
95
97
  };
96
98
  if (isLoading) {
97
- return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsx(Spinner, { size: "lg", label: "Loading settings..." }) }));
99
+ return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsx(Spinner, { size: "lg", label: t("settings.loading") || "Loading settings..." }) }));
98
100
  }
99
- return (_jsxs("div", { className: "pt-12 pb-12 max-w-4xl mx-auto px-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(Settings, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: "Account Settings" })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Notifications" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Email Notifications" }), _jsx("p", { className: "text-small text-default-500", children: "Receive email notifications for important updates" })] }), _jsx(Switch, { isSelected: preferences.email_notifications, onValueChange: (value) => handleToggle("email_notifications", value) })] }), _jsx(Divider, {}), _jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Push Notifications" }), _jsx("p", { className: "text-small text-default-500", children: "Receive push notifications in your browser" })] }), _jsx(Switch, { isSelected: preferences.push_notifications, onValueChange: (value) => handleToggle("push_notifications", value) })] }), _jsx(Divider, {}), _jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Marketing Emails" }), _jsx("p", { className: "text-small text-default-500", children: "Receive emails about new features and updates" })] }), _jsx(Switch, { isSelected: preferences.marketing_emails, onValueChange: (value) => handleToggle("marketing_emails", value) })] })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Appearance" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs(Select, { label: "Theme", placeholder: "Select a theme", selectedKeys: preferences.theme ? [preferences.theme] : [], onChange: (e) => handleSelect("theme", e.target.value), children: [_jsx(SelectItem, { children: "Light" }, "light"), _jsx(SelectItem, { children: "Dark" }, "dark"), _jsx(SelectItem, { children: "System" }, "system")] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Language & Region" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs(Select, { label: "Language", placeholder: "Select a language", selectedKeys: preferences.language ? [preferences.language] : [], onChange: (e) => handleSelect("language", e.target.value), children: [_jsx(SelectItem, { children: "English" }, "en"), _jsx(SelectItem, { children: "Fran\u00E7ais" }, "fr"), _jsx(SelectItem, { children: "Espa\u00F1ol" }, "es"), _jsx(SelectItem, { children: "Deutsch" }, "de")] }), _jsxs(Select, { label: "Timezone", placeholder: "Select a timezone", selectedKeys: preferences.timezone ? [preferences.timezone] : [], onChange: (e) => handleSelect("timezone", e.target.value), children: [_jsx(SelectItem, { children: "UTC" }, "UTC"), _jsx(SelectItem, { children: "Europe/Paris" }, "Europe/Paris"), _jsx(SelectItem, { children: "America/New_York" }, "America/New_York"), _jsx(SelectItem, { children: "America/Los_Angeles" }, "America/Los_Angeles"), _jsx(SelectItem, { children: "Asia/Tokyo" }, "Asia/Tokyo")] })] }) })] }), _jsxs("div", { className: "flex justify-end gap-3", children: [_jsx(Button, { type: "button", variant: "flat", onPress: () => fetchSettings(), isDisabled: isSaving, children: "Reset" }), _jsx(Button, { type: "button", color: "primary", isLoading: isSaving, onPress: handleSave, startContent: !isSaving && _jsx(Save, { className: "w-4 h-4" }), children: isSaving ? "Saving..." : "Save Settings" })] })] })] }));
101
+ return (_jsxs("div", { className: "pt-12 pb-12 max-w-4xl mx-auto px-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-8", children: [_jsx(Settings, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: t("settings.account") || "Account Settings" })] }), _jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("settings.notifications") || "Notifications" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: t("settings.email_notifications") || "Email Notifications" }), _jsx("p", { className: "text-small text-default-500", children: t("settings.email_notifications_desc") ||
102
+ "Receive email notifications for important updates" })] }), _jsx(Switch, { isSelected: preferences.email_notifications, onValueChange: (value) => handleToggle("email_notifications", value) })] }), _jsx(Divider, {}), _jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: t("settings.push_notifications") || "Push Notifications" }), _jsx("p", { className: "text-small text-default-500", children: t("settings.push_notifications_desc") ||
103
+ "Receive push notifications in your browser" })] }), _jsx(Switch, { isSelected: preferences.push_notifications, onValueChange: (value) => handleToggle("push_notifications", value) })] }), _jsx(Divider, {}), _jsxs("div", { className: "flex justify-between items-center", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: t("settings.marketing_emails") || "Marketing Emails" }), _jsx("p", { className: "text-small text-default-500", children: t("settings.marketing_emails_desc") ||
104
+ "Receive emails about new features and updates" })] }), _jsx(Switch, { isSelected: preferences.marketing_emails, onValueChange: (value) => handleToggle("marketing_emails", value) })] })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: t("settings.appearance") || "Appearance" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs(Select, { label: t("settings.theme") || "Theme", placeholder: t("settings.select_theme") || "Select a theme", selectedKeys: preferences.theme ? [preferences.theme] : [], onChange: (e) => handleSelect("theme", e.target.value), children: [_jsx(SelectItem, { children: t("settings.light") || "Light" }, "light"), _jsx(SelectItem, { children: t("settings.dark") || "Dark" }, "dark"), _jsx(SelectItem, { children: t("settings.system") || "System" }, "system")] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Language & Region" }) }), _jsx(Divider, {}), _jsx(CardBody, { children: _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs(Select, { label: "Language", placeholder: "Select a language", selectedKeys: preferences.language ? [preferences.language] : [], onChange: (e) => handleSelect("language", e.target.value), children: [_jsx(SelectItem, { children: "English" }, "en"), _jsx(SelectItem, { children: "Fran\u00E7ais" }, "fr"), _jsx(SelectItem, { children: "Espa\u00F1ol" }, "es"), _jsx(SelectItem, { children: "Deutsch" }, "de")] }), _jsxs(Select, { label: "Timezone", placeholder: "Select a timezone", selectedKeys: preferences.timezone ? [preferences.timezone] : [], onChange: (e) => handleSelect("timezone", e.target.value), children: [_jsx(SelectItem, { children: "UTC" }, "UTC"), _jsx(SelectItem, { children: "Europe/Paris" }, "Europe/Paris"), _jsx(SelectItem, { children: "America/New_York" }, "America/New_York"), _jsx(SelectItem, { children: "America/Los_Angeles" }, "America/Los_Angeles"), _jsx(SelectItem, { children: "Asia/Tokyo" }, "Asia/Tokyo")] })] }) })] }), _jsxs("div", { className: "flex justify-end gap-3", children: [_jsx(Button, { type: "button", variant: "flat", onPress: () => fetchSettings(), isDisabled: isSaving, children: "Reset" }), _jsx(Button, { type: "button", color: "primary", isLoading: isSaving, onPress: handleSave, startContent: !isSaving && _jsx(Save, { className: "w-4 h-4" }), children: isSaving ? "Saving..." : "Save Settings" })] })] })] }));
100
105
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SignInPage.d.ts","sourceRoot":"","sources":["../../../src/web/public/SignInPage.tsx"],"names":[],"mappings":"AAuPA,wBAAgB,UAAU,4CAMzB"}
1
+ {"version":3,"file":"SignInPage.d.ts","sourceRoot":"","sources":["../../../src/web/public/SignInPage.tsx"],"names":[],"mappings":"AAiNA,wBAAgB,UAAU,4CAMzB"}
@@ -4,15 +4,18 @@ import { Suspense, useState } from "react";
4
4
  import { supabaseBrowserClient } from "@lastbrain/core";
5
5
  import { addToast, Button, Card, CardBody, Chip, Input, Link, } from "@lastbrain/ui";
6
6
  import { ArrowRight, Lock, Mail, Sparkles } from "lucide-react";
7
- import { useRouter, useSearchParams } from "next/navigation";
7
+ import { useSearchParams } from "next/navigation";
8
+ import { useModuleTranslation } from "@lastbrain/core";
9
+ import { useLocalizedRouter } from "@lastbrain/core";
8
10
  function SignInForm() {
9
11
  const searchParams = useSearchParams();
12
+ const t = useModuleTranslation("auth");
13
+ const router = useLocalizedRouter();
10
14
  const [email, setEmail] = useState("");
11
15
  const [password, setPassword] = useState("");
12
16
  const [isLoading, setIsLoading] = useState(false);
13
17
  const [error, _setError] = useState(null);
14
18
  const redirectUrl = searchParams.get("redirect");
15
- const router = useRouter();
16
19
  const handleSubmit = async (event) => {
17
20
  event.preventDefault();
18
21
  setIsLoading(true);
@@ -24,18 +27,17 @@ function SignInForm() {
24
27
  if (error) {
25
28
  addToast({
26
29
  color: "danger",
27
- title: "Erreur de connexion",
30
+ title: t("signin.error_title") || "Erreur de connexion",
28
31
  description: error.message,
29
32
  });
30
33
  setIsLoading(false);
31
34
  return;
32
35
  }
33
36
  setIsLoading(false);
34
- console.log("Signed in user:", data.user);
35
37
  addToast({
36
38
  color: "success",
37
- title: "Connecté avec succès !",
38
- description: `Bienvenue ${data.user?.email}`,
39
+ title: t("signin.success_title") || "Connecté avec succès !",
40
+ description: `${t("signin.success_welcome") || "Bienvenue"} ${data.user?.email}`,
39
41
  });
40
42
  router.push(redirectUrl || "/auth/dashboard");
41
43
  }
@@ -43,65 +45,21 @@ function SignInForm() {
43
45
  setIsLoading(false);
44
46
  addToast({
45
47
  color: "danger",
46
- title: "Erreur de connexion",
48
+ title: t("signin.error_title") || "Erreur de connexion",
47
49
  description: `${err instanceof Error ? err.message : String(err)}`,
48
50
  });
49
51
  }
50
52
  };
51
- // return (
52
- // <div className=" min-h-screen h-full flex flex-col justify-center items-center p-4">
53
- // <Card className="w-full max-w-md">
54
- // <CardHeader className="flex flex-col">
55
- // <h1 className="text-2xl font-semibold text-slate-900 dark:text-white">
56
- // Connexion
57
- // </h1>
58
- // <p className="mt-1 text-sm text-slate-500">
59
- // Utilisez votre adresse email pour vous connecter.
60
- // </p>
61
- // </CardHeader>
62
- // <CardBody>
63
- // <form onSubmit={handleSubmit}>
64
- // <div className="space-y-6">
65
- // <Input
66
- // label="Email"
67
- // type="email"
68
- // className="mb-6"
69
- // required
70
- // value={email}
71
- // onChange={(event) => setEmail(event.target.value)}
72
- // />
73
- // <Input
74
- // label="Mot de passe"
75
- // type="password"
76
- // required
77
- // placeholder="Password"
78
- // className="mb-6"
79
- // value={password}
80
- // onChange={(event) => setPassword(event.target.value)}
81
- // />
82
- // <Button
83
- // size="lg"
84
- // type="submit"
85
- // className="w-full"
86
- // isLoading={isLoading}
87
- // >
88
- // Se connecter
89
- // </Button>
90
- // </div>
91
- // </form>
92
- // </CardBody>
93
- // </Card>
94
- // </div>
95
- // );
96
- return (_jsxs("div", { className: "relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-primary-50/30 to-secondary-50/30 dark:from-primary-950/50 dark:to-secondary-950/50", children: [_jsx("div", { className: "absolute inset-0 bg-grid-slate-100 dark:bg-grid-slate-800/20 mask-[linear-gradient(0deg,white,rgba(255,255,255,0.6))] dark:mask-[linear-gradient(0deg,rgba(255,255,255,0.1),rgba(255,255,255,0.05))]" }), _jsx("div", { className: "relative flex min-h-[60vh] items-center justify-center px-4 py-12", children: _jsxs("div", { className: "w-full max-w-md", children: [_jsxs("div", { className: "mb-8 text-center", children: [_jsx(Chip, { color: "primary", variant: "flat", startContent: _jsx(Sparkles, { className: "w-4 h-4" }), className: "mb-4 p-2", children: "Espace membre" }), _jsx("h1", { className: "mb-3 text-4xl font-bold", children: _jsx("span", { className: "bg-gradient-to-r from-primary-600 to-secondary-600 bg-clip-text text-transparent", children: "Bon retour" }) }), _jsx("p", { className: "text-default-600 dark:text-default-400", children: "Connectez-vous pour acc\u00E9der \u00E0 votre espace" })] }), _jsx(Card, { className: "border border-default-200/60 bg-background/60 backdrop-blur-md backdrop-saturate-150 shadow-xl", children: _jsxs(CardBody, { className: "gap-6 p-8", children: [_jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-6", children: [_jsx(Input, { label: "Email", type: "email", placeholder: "votre@email.com", value: email, onChange: (e) => setEmail(e.target.value), required: true, startContent: _jsx(Mail, { className: "h-4 w-4 text-default-400" }), classNames: {
53
+ return (_jsxs("div", { className: "relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-primary-50/30 to-secondary-50/30 dark:from-primary-950/50 dark:to-secondary-950/50", children: [_jsx("div", { className: "absolute inset-0 bg-grid-slate-100 dark:bg-grid-slate-800/20 mask-[linear-gradient(0deg,white,rgba(255,255,255,0.6))] dark:mask-[linear-gradient(0deg,rgba(255,255,255,0.1),rgba(255,255,255,0.05))]" }), _jsx("div", { className: "relative flex min-h-[60vh] items-center justify-center px-4 py-12", children: _jsxs("div", { className: "w-full max-w-md", children: [_jsxs("div", { className: "mb-8 text-center", children: [_jsx(Chip, { color: "primary", variant: "flat", startContent: _jsx(Sparkles, { className: "w-4 h-4" }), className: "mb-4 p-2", children: t("signin.chip_label") || "Espace membre" }), _jsx("h1", { className: "mb-3 text-4xl font-bold", children: _jsx("span", { className: "bg-gradient-to-r from-primary-600 to-secondary-600 bg-clip-text text-transparent", children: t("signin.title") || "Bon retour" }) }), _jsx("p", { className: "text-default-600 dark:text-default-700", children: t("signin.subtitle") ||
54
+ "Connectez-vous pour accéder à votre espace" })] }), _jsx(Card, { className: "border border-default-200/60 bg-background/60 backdrop-blur-md backdrop-saturate-150 shadow-xl", children: _jsxs(CardBody, { className: "gap-6 p-8", children: [_jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-6", children: [_jsx(Input, { label: t("email") || "Email", type: "email", placeholder: t("signin.email_placeholder") || "votre@email.com", value: email, onChange: (e) => setEmail(e.target.value), required: true, startContent: _jsx(Mail, { className: "h-4 w-4 text-default-400" }), classNames: {
97
55
  input: "text-base",
98
56
  inputWrapper: "border border-default-200/60 hover:border-primary-400 focus-within:border-primary-500",
99
- } }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Input, { label: "Mot de passe", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, startContent: _jsx(Lock, { className: "h-4 w-4 text-default-400" }), classNames: {
57
+ } }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Input, { label: t("password") || "Mot de passe", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, startContent: _jsx(Lock, { className: "h-4 w-4 text-default-400" }), classNames: {
100
58
  input: "text-base",
101
59
  inputWrapper: "border border-default-200/60 hover:border-primary-400 focus-within:border-primary-500",
102
- } }), _jsx(Link, { href: "/forgot-password", className: "text-xs text-default-500 hover:text-primary-500 self-end", children: "Mot de passe oubli\u00E9 ?" })] }), error && (_jsx("div", { className: "rounded-lg border border-danger-200 bg-danger-50/50 px-4 py-3 dark:border-danger-800 dark:bg-danger-950/50", children: _jsx("p", { className: "text-sm text-danger-600 dark:text-danger-400", children: error }) })), _jsx(Button, { type: "submit", color: "primary", size: "lg", className: "w-full font-semibold", endContent: isLoading ? null : _jsx(ArrowRight, { className: "h-5 w-5" }), isLoading: isLoading, children: "Se connecter" })] }), _jsxs("div", { className: "relative flex items-center gap-4 py-2", children: [_jsx("div", { className: "h-px flex-1 bg-default-200" }), _jsx("span", { className: "text-xs text-default-400", children: "OU" }), _jsx("div", { className: "h-px flex-1 bg-default-200" })] }), _jsx("div", { className: "text-center", children: _jsxs("p", { className: "text-sm text-default-600", children: ["Pas encore de compte ?", " ", _jsx(Link, { href: redirectUrl
60
+ } }), _jsx(Link, { href: "/forgot-password", className: "text-xs text-default-500 hover:text-primary-500 self-end", children: t("signin.forgot_password") || "Mot de passe oublié ?" })] }), error && (_jsx("div", { className: "rounded-lg border border-danger-200 bg-danger-50/50 px-4 py-3 dark:border-danger-800 dark:bg-danger-950/50", children: _jsx("p", { className: "text-sm text-danger-600 dark:text-danger-400", children: error }) })), _jsx(Button, { type: "submit", color: "primary", size: "lg", className: "w-full font-semibold", endContent: isLoading ? null : _jsx(ArrowRight, { className: "h-5 w-5" }), isLoading: isLoading, children: t("signin.submit") || "Se connecter" })] }), _jsxs("div", { className: "relative flex items-center gap-4 py-2", children: [_jsx("div", { className: "h-px flex-1 bg-default-200" }), _jsx("span", { className: "text-xs text-default-400", children: t("or") || "OU" }), _jsx("div", { className: "h-px flex-1 bg-default-200" })] }), _jsx("div", { className: "text-center", children: _jsxs("p", { className: "text-sm text-default-600", children: [t("signin.no_account") || "Pas encore de compte ?", " ", _jsx(Link, { href: redirectUrl
103
61
  ? `/signup?redirect=${encodeURIComponent(redirectUrl)}`
104
- : "/signup", className: "font-semibold text-primary-600 hover:text-primary-700", children: "Cr\u00E9er un compte" })] }) })] }) }), _jsxs("p", { className: "mt-8 text-center text-xs text-default-400", children: ["En vous connectant, vous acceptez nos", " ", _jsx(Link, { href: "/legal/terms", className: "underline hover:text-primary-500", children: "conditions d'utilisation" })] })] }) })] }));
62
+ : "/signup", className: "font-semibold text-primary-600 hover:text-primary-700", children: t("signin.sign_up") || "Créer un compte" })] }) })] }) }), _jsxs("p", { className: "mt-8 text-center text-sm text-default-700", children: [t("signin.accept_terms"), " ", _jsx(Link, { href: "/legal/terms", className: "underline hover:text-primary-500", children: t("signin.term") })] })] }) })] }));
105
63
  }
106
64
  export function SignInPage() {
107
65
  return (_jsx(Suspense, { fallback: _jsx("div", { children: "Chargement..." }), children: _jsx(SignInForm, {}) }));
@@ -1 +1 @@
1
- {"version":3,"file":"SignUpPage.d.ts","sourceRoot":"","sources":["../../../src/web/public/SignUpPage.tsx"],"names":[],"mappings":"AAqRA,wBAAgB,UAAU,4CAMzB"}
1
+ {"version":3,"file":"SignUpPage.d.ts","sourceRoot":"","sources":["../../../src/web/public/SignUpPage.tsx"],"names":[],"mappings":"AA2SA,wBAAgB,UAAU,4CAMzB"}
@@ -1,12 +1,15 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Button, Card, CardBody, Input, Link, Chip, addToast, } from "@lastbrain/ui";
4
- import { useRouter, useSearchParams } from "next/navigation";
4
+ import { useSearchParams } from "next/navigation";
5
5
  import { Suspense, useState } from "react";
6
6
  import { Mail, Lock, User, ArrowRight, Sparkles, CheckCircle2, } from "lucide-react";
7
+ import { useModuleTranslation } from "@lastbrain/core";
8
+ import { useLocalizedRouter } from "@lastbrain/core";
7
9
  function SignUpForm() {
8
- const router = useRouter();
10
+ const router = useLocalizedRouter();
9
11
  const searchParams = useSearchParams();
12
+ const t = useModuleTranslation("auth");
10
13
  const [fullName, setFullName] = useState("");
11
14
  const [email, setEmail] = useState("");
12
15
  const [password, setPassword] = useState("");
@@ -21,11 +24,13 @@ function SignUpForm() {
21
24
  setError(null);
22
25
  setSuccess(null);
23
26
  if (password !== confirmPassword) {
24
- setError("Les mots de passe ne correspondent pas.");
27
+ setError(t("signup.password_mismatch") ||
28
+ "Les mots de passe ne correspondent pas.");
25
29
  return;
26
30
  }
27
31
  if (password.length < 6) {
28
- setError("Le mot de passe doit contenir au moins 6 caractères.");
32
+ setError(t("signup.password_too_short") ||
33
+ "Le mot de passe doit contenir au moins 6 caractères.");
29
34
  return;
30
35
  }
31
36
  setLoading(true);
@@ -58,7 +63,7 @@ function SignUpForm() {
58
63
  router.push(`/signin?redirect=${encodeURIComponent(redirectUrl)}`);
59
64
  }
60
65
  else {
61
- router.push("/signin");
66
+ router.push(`/signin`);
62
67
  }
63
68
  }, 2000);
64
69
  }
@@ -73,21 +78,23 @@ function SignUpForm() {
73
78
  setLoading(false);
74
79
  }
75
80
  };
76
- return (_jsxs("div", { className: " relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-secondary-50/30 to-primary-50/30 dark:from-secondary-950/50 dark:to-primary-950/50", children: [_jsx("div", { className: "absolute inset-0 bg-grid-slate-100 dark:bg-grid-slate-800/20 mask-[linear-gradient(0deg,white,rgba(255,255,255,0.6))] dark:mask-[linear-gradient(0deg,rgba(255,255,255,0.1),rgba(255,255,255,0.05))]" }), _jsx("div", { className: "relative flex min-h-screen items-center justify-center px-4 py-12", children: _jsxs("div", { className: "w-full max-w-md", children: [_jsxs("div", { className: "mb-8 text-center", children: [_jsx(Chip, { color: "secondary", variant: "flat", startContent: _jsx(Sparkles, { className: "w-4 h-4" }), className: "mb-4 p-2", children: "Rejoignez-nous" }), _jsx("h1", { className: "mb-3 text-4xl font-bold", children: _jsx("span", { className: "bg-gradient-to-r from-secondary-600 to-primary-600 bg-clip-text text-transparent", children: "Commencer gratuitement" }) }), _jsx("p", { className: "text-default-600 dark:text-default-400", children: "Cr\u00E9ez votre compte en quelques secondes" })] }), _jsx(Card, { className: "border border-default-200/60 bg-background/60 backdrop-blur-md backdrop-saturate-150 shadow-xl", children: _jsxs(CardBody, { className: "gap-6 p-8", children: [_jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-6", children: [_jsx(Input, { label: "Nom complet", type: "text", placeholder: "Jean Dupont", value: fullName, onChange: (e) => setFullName(e.target.value), startContent: _jsx(User, { className: "h-4 w-4 text-default-400" }), classNames: {
81
+ return (_jsxs("div", { className: " relative min-h-screen w-full overflow-hidden bg-gradient-to-br from-secondary-50/30 to-primary-50/30 dark:from-secondary-950/50 dark:to-primary-950/50", children: [_jsx("div", { className: "absolute inset-0 bg-grid-slate-100 dark:bg-grid-slate-800/20 mask-[linear-gradient(0deg,white,rgba(255,255,255,0.6))] dark:mask-[linear-gradient(0deg,rgba(255,255,255,0.1),rgba(255,255,255,0.05))]" }), _jsx("div", { className: "relative flex min-h-screen items-center justify-center px-4 py-12", children: _jsxs("div", { className: "w-full max-w-md", children: [_jsxs("div", { className: "mb-8 text-center", children: [_jsx(Chip, { color: "secondary", variant: "flat", startContent: _jsx(Sparkles, { className: "w-4 h-4" }), className: "mb-4 p-2", children: t("signup.chip_label") || "Rejoignez-nous" }), _jsx("h1", { className: "mb-3 text-4xl font-bold", children: _jsx("span", { className: "bg-gradient-to-r from-secondary-600 to-primary-600 bg-clip-text text-transparent", children: t("signup.title") || "Commencer gratuitement" }) }), _jsx("p", { className: "text-default-600 dark:text-default-700", children: t("signup.subtitle") ||
82
+ "Créez votre compte en quelques secondes" })] }), _jsx(Card, { className: "border border-default-200/60 bg-background/60 backdrop-blur-md backdrop-saturate-150 shadow-xl", children: _jsxs(CardBody, { className: "gap-6 p-8", children: [_jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-6", children: [_jsx(Input, { label: t("signup.full_name") || "Nom complet", type: "text", placeholder: t("signup.full_name_placeholder") || "Jean Dupont", value: fullName, onChange: (e) => setFullName(e.target.value), startContent: _jsx(User, { className: "h-4 w-4 text-default-400" }), classNames: {
77
83
  input: "text-base",
78
84
  inputWrapper: "border border-default-200/60 hover:border-secondary-400 focus-within:border-secondary-500",
79
- } }), _jsx(Input, { label: "Email", type: "email", placeholder: "votre@email.com", value: email, onChange: (e) => setEmail(e.target.value), required: true, startContent: _jsx(Mail, { className: "h-4 w-4 text-default-400" }), classNames: {
85
+ } }), _jsx(Input, { label: t("email") || "Email", type: "email", placeholder: t("signin.email_placeholder") || "votre@email.com", value: email, onChange: (e) => setEmail(e.target.value), required: true, startContent: _jsx(Mail, { className: "h-4 w-4 text-default-400" }), classNames: {
80
86
  input: "text-base",
81
87
  inputWrapper: "border border-default-200/60 hover:border-secondary-400 focus-within:border-secondary-500",
82
- } }), _jsx(Input, { label: "Mot de passe", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, startContent: _jsx(Lock, { className: "h-4 w-4 text-default-400" }), classNames: {
88
+ } }), _jsx(Input, { label: t("password") || "Mot de passe", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: password, onChange: (e) => setPassword(e.target.value), required: true, minLength: 6, startContent: _jsx(Lock, { className: "h-4 w-4 text-default-400" }), classNames: {
83
89
  input: "text-base",
84
90
  inputWrapper: "border border-default-200/60 hover:border-secondary-400 focus-within:border-secondary-500",
85
- }, description: "Minimum 6 caract\u00E8res" }), _jsx(Input, { label: "Confirmer le mot de passe", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, minLength: 6, startContent: _jsx(Lock, { className: "h-4 w-4 text-default-400" }), classNames: {
91
+ }, description: t("signup.password_hint") || "Minimum 6 caractères" }), _jsx(Input, { label: t("signup.confirm_password") || "Confirmer le mot de passe", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, minLength: 6, startContent: _jsx(Lock, { className: "h-4 w-4 text-default-400" }), classNames: {
86
92
  input: "text-base",
87
93
  inputWrapper: "border border-default-200/60 hover:border-secondary-400 focus-within:border-secondary-500",
88
- } }), error && (_jsx("div", { className: "rounded-lg border border-danger-200 bg-danger-50/50 px-4 py-3 dark:border-danger-800 dark:bg-danger-950/50", children: _jsx("p", { className: "text-sm text-danger-600 dark:text-danger-400", children: error }) })), success && (_jsx("div", { className: "rounded-lg border border-success-200 bg-success-50/50 px-4 py-3 dark:border-success-800 dark:bg-success-950/50", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-success-600 dark:text-success-400" }), _jsx("p", { className: "text-sm text-success-600 dark:text-success-400", children: success })] }) })), _jsx(Button, { type: "submit", color: "secondary", size: "lg", className: "w-full font-semibold", endContent: loading ? null : _jsx(ArrowRight, { className: "h-5 w-5" }), isLoading: loading, children: "Cr\u00E9er mon compte" })] }), _jsxs("div", { className: "relative flex items-center gap-4 py-2", children: [_jsx("div", { className: "h-px flex-1 bg-default-200" }), _jsx("span", { className: "text-xs text-default-400", children: "OU" }), _jsx("div", { className: "h-px flex-1 bg-default-200" })] }), _jsx("div", { className: "text-center", children: _jsxs("p", { className: "text-sm text-default-600", children: ["D\u00E9j\u00E0 inscrit ?", " ", _jsx(Link, { href: redirectUrl
94
+ } }), error && (_jsx("div", { className: "rounded-lg border border-danger-200 bg-danger-50/50 px-4 py-3 dark:border-danger-800 dark:bg-danger-950/50", children: _jsx("p", { className: "text-sm text-danger-600 dark:text-danger-400", children: error }) })), success && (_jsx("div", { className: "rounded-lg border border-success-200 bg-success-50/50 px-4 py-3 dark:border-success-800 dark:bg-success-950/50", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-success-600 dark:text-success-400" }), _jsx("p", { className: "text-sm text-success-600 dark:text-success-400", children: success })] }) })), _jsx(Button, { type: "submit", color: "secondary", size: "lg", className: "w-full font-semibold", endContent: loading ? null : _jsx(ArrowRight, { className: "h-5 w-5" }), isLoading: loading, children: t("signup.submit") || "Créer mon compte" })] }), _jsxs("div", { className: "relative flex items-center gap-4 py-2", children: [_jsx("div", { className: "h-px flex-1 bg-default-200" }), _jsx("span", { className: "text-xs text-default-400", children: t("signup.or") || "OU" }), _jsx("div", { className: "h-px flex-1 bg-default-200" })] }), _jsx("div", { className: "text-center", children: _jsxs("p", { className: "text-sm text-default-600", children: [t("signup.have_account") || "Déjà inscrit ?", " ", _jsx(Link, { href: redirectUrl
89
95
  ? `/signin?redirect=${encodeURIComponent(redirectUrl)}`
90
- : "/signin", className: "font-semibold text-secondary-600 hover:text-secondary-700", children: "Se connecter" })] }) })] }) }), _jsxs("p", { className: "mt-8 text-center text-xs text-default-400", children: ["En cr\u00E9ant un compte, vous acceptez nos", " ", _jsx(Link, { href: "/legal/terms", className: "underline hover:text-secondary-500", children: "conditions d'utilisation" }), " ", "et notre", " ", _jsx(Link, { href: "/legal/privacy", className: "underline hover:text-secondary-500", children: "politique de confidentialit\u00E9" })] })] }) })] }));
96
+ : "/signin", className: "font-semibold text-secondary-600 hover:text-secondary-700", children: t("signin.submit") || "Se connecter" })] }) })] }) }), _jsxs("p", { className: "mt-8 text-center text-sm text-default-700", children: [t("signup.legal_prefix") ||
97
+ "En créant un compte, vous acceptez nos", " ", _jsx(Link, { href: "/legal/terms", className: "underline hover:text-secondary-500", children: t("signup.terms") || "conditions d'utilisation" }), " ", t("signup.legal_and") || "et notre", " ", _jsx(Link, { href: "/legal/privacy", className: "underline hover:text-secondary-500", children: t("signup.privacy") || "politique de confidentialité" })] })] }) })] }));
91
98
  }
92
99
  export function SignUpPage() {
93
100
  return (_jsx(Suspense, { fallback: _jsx("div", { children: "Chargement..." }), children: _jsx(SignUpForm, {}) }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/module-auth",
3
- "version": "2.0.13",
3
+ "version": "2.0.19",
4
4
  "description": "Module d'authentification complet pour LastBrain avec Supabase",
5
5
  "private": false,
6
6
  "type": "module",
@@ -32,8 +32,9 @@
32
32
  "supabase"
33
33
  ],
34
34
  "dependencies": {
35
- "@lastbrain/core": "^2.0.13",
36
- "@lastbrain/ui": "^2.0.13",
35
+ "@lastbrain/app": "^2.0.21",
36
+ "@lastbrain/core": "^2.0.19",
37
+ "@lastbrain/ui": "^2.0.19",
37
38
  "@supabase/supabase-js": "^2.86.0",
38
39
  "lucide-react": "^0.554.0",
39
40
  "react": "^19.2.1",