@lastbrain/module-auth 0.1.16 → 0.1.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 (33) hide show
  1. package/README.md +1 -0
  2. package/dist/auth.build.config.d.ts.map +1 -1
  3. package/dist/auth.build.config.js +114 -10
  4. package/dist/components/AccountButton.d.ts +18 -0
  5. package/dist/components/AccountButton.d.ts.map +1 -0
  6. package/dist/components/AccountButton.js +40 -0
  7. package/dist/components/NotificationButton.d.ts +18 -0
  8. package/dist/components/NotificationButton.d.ts.map +1 -0
  9. package/dist/components/NotificationButton.js +8 -0
  10. package/dist/components/ThemeSwitcherButton.d.ts +9 -0
  11. package/dist/components/ThemeSwitcherButton.d.ts.map +1 -0
  12. package/dist/components/ThemeSwitcherButton.js +6 -0
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +4 -0
  16. package/dist/web/admin/user-detail.d.ts.map +1 -1
  17. package/dist/web/admin/user-detail.js +27 -6
  18. package/dist/web/admin/users.d.ts.map +1 -1
  19. package/dist/web/admin/users.js +6 -6
  20. package/dist/web/auth/profile.js +17 -17
  21. package/package.json +2 -1
  22. package/src/auth.build.config.ts +114 -10
  23. package/src/components/AccountButton.tsx +157 -0
  24. package/src/components/NotificationButton.tsx +41 -0
  25. package/src/components/ThemeSwitcherButton.tsx +14 -0
  26. package/src/index.ts +6 -0
  27. package/src/web/admin/user-detail.tsx +244 -51
  28. package/src/web/admin/users.tsx +21 -3
  29. package/src/web/auth/profile.tsx +34 -34
  30. package/supabase/migrations/20251112000000_user_init.sql +6 -1
  31. package/supabase/migrations/20251112000001_auto_profile_and_admin_view.sql +6 -1
  32. package/supabase/migrations/20251124000001_add_get_admin_user_details.sql +1 -0
  33. package/supabase/migrations/20251127100000_rename_body_to_message.sql +9 -0
package/README.md CHANGED
@@ -85,6 +85,7 @@
85
85
  - `20251112000001_auto_profile_and_admin_view.sql`
86
86
  - `20251112000002_sync_avatars.sql`
87
87
  - `20251124000001_add_get_admin_user_details.sql`
88
+ - `20251127100000_rename_body_to_message.sql`
88
89
 
89
90
  ## 📦 Installation
90
91
 
@@ -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,iBA6NtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"auth.build.config.d.ts","sourceRoot":"","sources":["../src/auth.build.config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,QAAA,MAAM,eAAe,EAAE,iBAqUtB,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -120,18 +120,34 @@ const authBuildConfig = {
120
120
  menu: {
121
121
  public: [
122
122
  {
123
- title: "Connexion",
124
- description: "Connectez-vous à votre compte",
125
- icon: "LogIn",
126
- path: "/signin",
127
- order: 1,
123
+ title: "Notifications",
124
+ description: "Vos notifications",
125
+ icon: "Bell",
126
+ path: "#",
127
+ order: 998,
128
+ type: "icon",
129
+ position: "end",
130
+ componentExport: "NotificationButton",
128
131
  },
129
132
  {
130
- title: "Inscription",
131
- description: "Créez votre compte",
132
- icon: "UserPlus2",
133
- path: "/signup",
134
- order: 2,
133
+ title: "Compte",
134
+ description: "Gérer votre compte",
135
+ icon: "User",
136
+ path: "#",
137
+ order: 999,
138
+ type: "icon",
139
+ position: "end",
140
+ componentExport: "AccountButton",
141
+ },
142
+ {
143
+ title: "Theme",
144
+ description: "Changer le thème",
145
+ icon: "Palette",
146
+ path: "#",
147
+ order: 9999,
148
+ type: "icon",
149
+ position: "end",
150
+ componentExport: "ThemeSwitcherButton",
135
151
  },
136
152
  ],
137
153
  admin: [
@@ -144,6 +160,36 @@ const authBuildConfig = {
144
160
  shortcut: "cmd+shift+u",
145
161
  shortcutDisplay: "⌘⇧U",
146
162
  },
163
+ {
164
+ title: "Notifications",
165
+ description: "Vos notifications",
166
+ icon: "Bell",
167
+ path: "#",
168
+ order: 998,
169
+ type: "icon",
170
+ position: "end",
171
+ componentExport: "NotificationButton",
172
+ },
173
+ {
174
+ title: "Compte",
175
+ description: "Gérer votre compte",
176
+ icon: "User",
177
+ path: "#",
178
+ order: 999,
179
+ type: "icon",
180
+ position: "end",
181
+ componentExport: "AccountButton",
182
+ },
183
+ {
184
+ title: "Theme",
185
+ description: "Changer le thème",
186
+ icon: "Palette",
187
+ path: "#",
188
+ order: 9999,
189
+ type: "icon",
190
+ position: "end",
191
+ componentExport: "ThemeSwitcherButton",
192
+ },
147
193
  ],
148
194
  auth: [
149
195
  {
@@ -164,6 +210,36 @@ const authBuildConfig = {
164
210
  shortcut: "cmd+shift+f",
165
211
  shortcutDisplay: "⌘⇧F",
166
212
  },
213
+ {
214
+ title: "Notifications",
215
+ description: "Vos notifications",
216
+ icon: "Bell",
217
+ path: "#",
218
+ order: 998,
219
+ type: "icon",
220
+ position: "end",
221
+ componentExport: "NotificationButton",
222
+ },
223
+ {
224
+ title: "Compte",
225
+ description: "Gérer votre compte",
226
+ icon: "User",
227
+ path: "#",
228
+ order: 999,
229
+ type: "icon",
230
+ position: "end",
231
+ componentExport: "AccountButton",
232
+ },
233
+ {
234
+ title: "Theme",
235
+ description: "Changer le thème",
236
+ icon: "Palette",
237
+ path: "#",
238
+ order: 9999,
239
+ type: "icon",
240
+ position: "end",
241
+ componentExport: "ThemeSwitcherButton",
242
+ },
167
243
  ],
168
244
  account: [
169
245
  {
@@ -219,5 +295,33 @@ const authBuildConfig = {
219
295
  },
220
296
  ],
221
297
  },
298
+ storage: {
299
+ buckets: [
300
+ {
301
+ name: "app",
302
+ public: false,
303
+ description: "Private user files and documents /{userId}/...",
304
+ maxFileSize: 100 * 1024 * 1024, // 100MB
305
+ customAccessControl: (userId, filePath) => {
306
+ // Users can only access files in their own folder (app/{userId}/...)
307
+ return filePath.startsWith(`${userId}/`);
308
+ },
309
+ },
310
+ {
311
+ name: "avatar",
312
+ public: true,
313
+ description: "Public user avatar images",
314
+ allowedMimeTypes: [
315
+ "image/jpeg",
316
+ "image/jpg",
317
+ "image/png",
318
+ "image/webp",
319
+ "image/gif",
320
+ ],
321
+ maxFileSize: 5242880, // 5MB
322
+ fileSizeLimit: "5MB",
323
+ },
324
+ ],
325
+ },
222
326
  };
223
327
  export default authBuildConfig;
@@ -0,0 +1,18 @@
1
+ import type { User } from "@supabase/supabase-js";
2
+ interface AccountButtonProps {
3
+ item: {
4
+ path: string;
5
+ title: string;
6
+ };
7
+ user?: User | null;
8
+ accountMenu?: Array<{
9
+ title: string;
10
+ description?: string;
11
+ icon?: string;
12
+ path: string;
13
+ }>;
14
+ onLogout?: () => void | Promise<void>;
15
+ }
16
+ export declare const AccountButton: ({ user, accountMenu, onLogout, }: AccountButtonProps) => import("react/jsx-runtime").JSX.Element;
17
+ export {};
18
+ //# sourceMappingURL=AccountButton.d.ts.map
@@ -0,0 +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;AAGlD,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,4CAoHpB,CAAC"}
@@ -0,0 +1,40 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { Button, Link } from "@lastbrain/ui";
4
+ import { Avatar } from "@lastbrain/ui";
5
+ import { Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, } from "@lastbrain/ui";
6
+ import * as LucideIcons from "lucide-react";
7
+ // Fonction pour récupérer l'icône Lucide
8
+ const getIcon = (iconName) => {
9
+ if (!iconName)
10
+ return null;
11
+ const Icon = LucideIcons[iconName];
12
+ return Icon ? Icon : null;
13
+ };
14
+ export const AccountButton = ({ user, accountMenu = [], onLogout, }) => {
15
+ if (!user)
16
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "block md:hidden", children: [_jsx(Button, { as: Link, href: "/signin", radius: "full", isIconOnly: true, variant: "light", color: "primary", children: _jsx(LucideIcons.LogIn, { size: 16 }) }), _jsx(Button, { as: Link, href: "/signup", radius: "full", isIconOnly: true, variant: "flat", className: "ml-2", color: "secondary", children: _jsx(LucideIcons.UserPlus2, { size: 16 }) })] }), _jsxs("div", { className: "hidden md:block", children: [_jsx(Button, { as: Link, href: "/signin", startContent: _jsx(LucideIcons.LogIn, { size: 16 }), variant: "light", color: "primary", children: "Se connecter" }), _jsx(Button, { as: Link, href: "/signup", variant: "flat", className: "ml-2", color: "secondary", startContent: _jsx(LucideIcons.UserPlus2, { size: 16 }), children: "S'inscrire" })] })] }));
17
+ return (_jsxs(Dropdown, { children: [_jsx(DropdownTrigger, { children: _jsx(Avatar, { size: "sm", src: `/api/storage/${user?.user_metadata.avatar}`, title: user.email, fallback: _jsx(LucideIcons.User2, { size: 18 }), classNames: {
18
+ base: "bg-white/0",
19
+ icon: "text-default-700",
20
+ } }) }), _jsx(DropdownMenu, { items: [
21
+ {
22
+ key: "hello",
23
+ label: `Bonjour ${user?.user_metadata?.full_name || user.email}`,
24
+ isReadOnly: true,
25
+ },
26
+ ...accountMenu.map((item) => ({
27
+ key: item.path,
28
+ label: item.title,
29
+ description: item.description,
30
+ icon: item.icon,
31
+ isLogout: item.path.includes("signout") || item.path.includes("logout"),
32
+ href: item.path.includes("signout") || item.path.includes("logout")
33
+ ? undefined
34
+ : item.path,
35
+ })),
36
+ ], children: (item) => {
37
+ const Icon = item.icon ? getIcon(item.icon) : null;
38
+ 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));
39
+ } })] }));
40
+ };
@@ -0,0 +1,18 @@
1
+ import { type UserNotification } from "@lastbrain/ui";
2
+ import type { User } from "@supabase/supabase-js";
3
+ interface NotificationButtonProps {
4
+ item: {
5
+ path: string;
6
+ title: string;
7
+ };
8
+ user?: User | null;
9
+ notifications?: UserNotification[];
10
+ unreadCount?: number;
11
+ notificationsLoading?: boolean;
12
+ onMarkAsRead?: (id: string) => void;
13
+ onMarkAllAsRead?: () => void;
14
+ onDeleteNotification?: (id: string) => void;
15
+ }
16
+ export declare const NotificationButton: ({ user, notifications, unreadCount, notificationsLoading, onMarkAsRead, onMarkAllAsRead, onDeleteNotification, }: NotificationButtonProps) => import("react/jsx-runtime").JSX.Element | null;
17
+ export {};
18
+ //# sourceMappingURL=NotificationButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationButton.d.ts","sourceRoot":"","sources":["../../src/components/NotificationButton.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAElD,UAAU,uBAAuB;IAC/B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,aAAa,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,oBAAoB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAED,eAAO,MAAM,kBAAkB,GAAI,kHAQhC,uBAAuB,mDAazB,CAAC"}
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Notification } from "@lastbrain/ui";
4
+ export const NotificationButton = ({ user, notifications = [], unreadCount = 0, notificationsLoading = false, onMarkAsRead = () => { }, onMarkAllAsRead = () => { }, onDeleteNotification = () => { }, }) => {
5
+ if (!user)
6
+ return null;
7
+ return (_jsx(Notification, { notifications: notifications, unreadCount: unreadCount, loading: notificationsLoading, onMarkAsRead: onMarkAsRead, onMarkAllAsRead: onMarkAllAsRead, onDelete: onDeleteNotification }));
8
+ };
@@ -0,0 +1,9 @@
1
+ interface ThemeSwitcherButtonProps {
2
+ item: {
3
+ path: string;
4
+ title: string;
5
+ };
6
+ }
7
+ export declare const ThemeSwitcherButton: (_props: ThemeSwitcherButtonProps) => import("react/jsx-runtime").JSX.Element;
8
+ export {};
9
+ //# sourceMappingURL=ThemeSwitcherButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemeSwitcherButton.d.ts","sourceRoot":"","sources":["../../src/components/ThemeSwitcherButton.tsx"],"names":[],"mappings":"AAIA,UAAU,wBAAwB;IAChC,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,eAAO,MAAM,mBAAmB,GAAI,QAAQ,wBAAwB,4CAEnE,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { ThemeSwitcher } from "@lastbrain/ui";
4
+ export const ThemeSwitcherButton = (_props) => {
5
+ return _jsx(ThemeSwitcher, {});
6
+ };
package/dist/index.d.ts CHANGED
@@ -8,6 +8,9 @@ export { ReglagePage } from "./web/auth/reglage.js";
8
8
  export { AdminUsersPage } from "./web/admin/users.js";
9
9
  export { default as UserPage } from "./web/admin/users/[id].js";
10
10
  export { UserDetailPage } from "./web/admin/user-detail.js";
11
+ export { AccountButton } from "./components/AccountButton.js";
12
+ export { NotificationButton } from "./components/NotificationButton.js";
13
+ export { ThemeSwitcherButton } from "./components/ThemeSwitcherButton.js";
11
14
  export { Doc } from "./components/Doc.js";
12
15
  export { Doc as AuthModuleDoc } from "./components/Doc.js";
13
16
  export { default as authBuildConfig } from "./auth.build.config.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,GAAG,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAG5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAG1E,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,GAAG,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -9,6 +9,10 @@ export { ReglagePage } from "./web/auth/reglage.js";
9
9
  export { AdminUsersPage } from "./web/admin/users.js";
10
10
  export { default as UserPage } from "./web/admin/users/[id].js";
11
11
  export { UserDetailPage } from "./web/admin/user-detail.js";
12
+ // Header Components
13
+ export { AccountButton } from "./components/AccountButton.js";
14
+ export { NotificationButton } from "./components/NotificationButton.js";
15
+ export { ThemeSwitcherButton } from "./components/ThemeSwitcherButton.js";
12
16
  // Documentation
13
17
  export { Doc } from "./components/Doc.js";
14
18
  export { Doc as AuthModuleDoc } from "./components/Doc.js";
@@ -1 +1 @@
1
- {"version":3,"file":"user-detail.d.ts","sourceRoot":"","sources":["../../../src/web/admin/user-detail.tsx"],"names":[],"mappings":"AAwBA,UAAU,aAAa;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAaD,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,2CA8UrB"}
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;AAiCD,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,2CA0frB"}
@@ -1,7 +1,7 @@
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 { Card, CardHeader, CardBody, Tabs, Tab, Avatar, Chip, Button, Input, Textarea, Select, SelectItem, Spinner, addToast, } from "@lastbrain/ui";
4
+ import { Card, CardHeader, CardBody, Tabs, Tab, Avatar, Chip, Button, Input, Textarea, Select, SelectItem, Spinner, addToast, Snippet, } from "@lastbrain/ui";
5
5
  import { User, Bell, Settings } from "lucide-react";
6
6
  import { useAuth } from "@lastbrain/core";
7
7
  import * as LucideIcons from "lucide-react";
@@ -97,11 +97,32 @@ export function UserDetailPage({ userId, moduleUserTabs = [], }) {
97
97
  }
98
98
  const isAdmin = Array.isArray(userProfile.raw_app_meta_data?.roles) &&
99
99
  userProfile.raw_app_meta_data.roles.includes("admin");
100
- return (_jsxs("div", { className: "mt-4 space-y-6", children: [_jsx(Card, { children: _jsxs(CardHeader, { className: "flex gap-4", children: [_jsx(Avatar, { src: userProfile.avatar_url, name: userProfile.full_name || userProfile.email, size: "lg" }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("h1", { className: "text-2xl font-bold", children: userProfile.full_name || userProfile.email }), _jsx("p", { className: "text-gray-500", children: userProfile.email }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Chip, { color: isAdmin ? "danger" : "primary", size: "sm", children: isAdmin ? "Administrateur" : "Utilisateur" }), _jsxs(Chip, { color: "default", size: "sm", children: ["ID: ", 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: _jsx("div", { className: "space-y-4 mt-4", children: _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("div", { children: [_jsx("h3", { className: "font-semibold mb-2", children: "Informations personnelles" }), _jsxs("div", { className: "space-y-2 text-sm", children: [_jsxs("p", { children: [_jsx("span", { className: "font-medium", children: "Nom complet:" }), " ", userProfile.full_name || "Non renseigné"] }), _jsxs("p", { children: [_jsx("span", { className: "font-medium", children: "Email:" }), " ", userProfile.email] }), _jsxs("p", { children: [_jsx("span", { className: "font-medium", children: "Date de cr\u00E9ation:" }), " ", userProfile.created_at
101
- ? new Date(userProfile.created_at).toLocaleDateString()
102
- : "N/A"] }), _jsxs("p", { children: [_jsx("span", { className: "font-medium", children: "Derni\u00E8re connexion:" }), " ", userProfile.last_sign_in_at
103
- ? new Date(userProfile.last_sign_in_at).toLocaleDateString()
104
- : "N/A"] })] })] }), _jsxs("div", { children: [_jsx("h3", { className: "font-semibold mb-2", children: "R\u00F4les et permissions" }), _jsx("div", { className: "space-y-2", children: _jsx(Chip, { color: isAdmin ? "danger" : "default", children: isAdmin ? "Administrateur" : "Utilisateur standard" }) })] })] }) }) }, "profile"), _jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(Bell, { size: 16 }), _jsx("span", { children: "Notifications" })] }), children: _jsxs("div", { className: "space-y-4 mt-4", children: [_jsx("h3", { className: "font-semibold", children: "Envoyer une notification" }), _jsxs("div", { className: "space-y-4", children: [_jsx(Input, { label: "Titre de la notification", placeholder: "Ex: Nouveau message important", value: notificationTitle, onChange: (e) => setNotificationTitle(e.target.value), maxLength: 100 }), _jsx(Textarea, { label: "Message", placeholder: "Contenu de la notification...", value: notificationMessage, onChange: (e) => setNotificationMessage(e.target.value), maxLength: 500, minRows: 3 }), _jsxs(Select, { label: "Type de notification", selectedKeys: [notificationType], onSelectionChange: (keys) => setNotificationType(Array.from(keys)[0]), children: [_jsx(SelectItem, { children: "Information" }, "info"), _jsx(SelectItem, { children: "Avertissement" }, "warning"), _jsx(SelectItem, { children: "Danger" }, "danger"), _jsx(SelectItem, { children: "Succ\u00E8s" }, "success")] }), _jsx(Button, { color: "primary", onPress: handleSendNotification, isLoading: sendingNotification, startContent: _jsx(Bell, { size: 16 }), isDisabled: !notificationTitle.trim() || !notificationMessage.trim(), children: "Envoyer la notification" })] })] }) }, "notifications"), _jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(Settings, { size: 16 }), _jsx("span", { children: "Param\u00E8tres" })] }), children: _jsxs("div", { className: "space-y-4 mt-4", children: [_jsx("h3", { className: "font-semibold", children: "Actions administrateur" }), _jsxs("div", { className: "space-y-3 space-x-5", children: [_jsx(Button, { color: "warning", variant: "bordered", size: "sm", children: "R\u00E9initialiser le mot de passe" }), _jsx(Button, { color: "danger", variant: "bordered", size: "sm", children: "Suspendre le compte" }), _jsx(Button, { color: "secondary", variant: "bordered", size: "sm", children: "Promouvoir en administrateur" })] }), _jsxs("div", { className: "mt-6 p-4 bg-gray-50 dark:bg-gray-800 rounded-lg", children: [_jsx("h4", { className: "font-medium mb-2", children: "M\u00E9tadonn\u00E9es techniques" }), _jsx("pre", { className: "text-xs text-gray-600 dark:text-gray-400 overflow-auto", children: JSON.stringify({
100
+ return (_jsxs("div", { className: "max-w-[calc(100vw-2rem)] 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
+ ? `/api/storage/${userProfile.avatar_sizes?.large || userProfile.avatar_url}`
102
+ : undefined, name: userProfile.full_name || userProfile.email, size: "lg" }), _jsxs("div", { className: "w-full flex flex-col gap-1", children: [_jsxs("div", { className: "w-full flex flex-col md:flex-row justify-between", children: [_jsx("h1", { className: "text-xl font-bold", children: userProfile.full_name || userProfile.email }), _jsxs("p", { className: "text-sm text-default-500 ", children: [_jsx("span", { className: "", children: "Derni\u00E8re connexion:" }), " ", userProfile.last_sign_in_at
103
+ ? new Date(userProfile.last_sign_in_at).toLocaleDateString()
104
+ : "N/A", " ", "\u00E0", " ", userProfile.last_sign_in_at
105
+ ? new Date(userProfile.last_sign_in_at).toLocaleTimeString()
106
+ : "N/A"] })] }), _jsx("p", { className: "text-gray-500", children: userProfile.email }), _jsxs("div", { className: "flex flex-col md:flex-row md:items-center gap-2", children: [_jsx(Chip, { variant: "flat", color: isAdmin ? "danger" : "primary", size: "sm", children: isAdmin ? "Administrateur" : "Utilisateur" }), _jsx(Snippet, { color: "default", size: "sm", symbol: "#", children: userId })] })] })] }) }), _jsx(Card, { children: _jsx(CardBody, { children: _jsxs(Tabs, { "aria-label": "Options utilisateur", color: "primary", variant: "underlined", children: [_jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(User, { size: 16 }), _jsx("span", { children: "Profil" })] }), children: _jsxs("div", { className: "space-y-6 mt-4", children: [_jsx(Card, { children: _jsxs(CardBody, { children: [_jsxs("h3", { className: "font-semibold text-lg mb-4 flex items-center gap-2", children: [_jsx(User, { size: 18 }), "Identit\u00E9"] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Nom complet" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.full_name || "Non renseigné" })] }), userProfile.profile?.first_name && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Pr\u00E9nom" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.first_name })] })), userProfile.profile?.last_name && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Nom" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.last_name })] })), _jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Email" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.email })] }), userProfile.profile?.phone && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "T\u00E9l\u00E9phone" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.phone })] }))] }), userProfile.profile?.bio && (_jsxs("div", { className: "mt-4", children: [_jsx("span", { className: "text-default-500 text-sm", children: "Bio" }), _jsx("p", { className: "font-medium mt-1 text-sm", children: userProfile.profile.bio })] }))] }) }), (userProfile.profile?.company ||
107
+ userProfile.profile?.website ||
108
+ userProfile.profile?.location) && (_jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: "Informations professionnelles" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [userProfile.profile?.company && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Entreprise" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.company })] })), userProfile.profile?.website && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Site web" }), _jsx("p", { className: "font-medium mt-1", children: _jsx("a", { href: userProfile.profile.website, target: "_blank", rel: "noopener noreferrer", className: "text-primary hover:underline", children: userProfile.profile.website }) })] })), userProfile.profile?.location && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Localisation" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.location })] }))] })] }) })), (userProfile.profile?.language ||
109
+ userProfile.profile?.timezone) && (_jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: "Pr\u00E9f\u00E9rences" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [userProfile.profile?.language && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Langue" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.language.toUpperCase() })] })), userProfile.profile?.timezone && (_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Fuseau horaire" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.profile.timezone })] }))] })] }) })), _jsx(Card, { children: _jsxs(CardBody, { children: [_jsx("h3", { className: "font-semibold text-lg mb-4", children: "Informations du compte" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [_jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "R\u00F4le" }), _jsx("div", { className: "mt-2", children: _jsx(Chip, { variant: "flat", color: isAdmin ? "danger" : "default", size: "sm", children: isAdmin
110
+ ? "Administrateur"
111
+ : "Utilisateur standard" }) })] }), _jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Date de cr\u00E9ation" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.created_at
112
+ ? new Date(userProfile.created_at).toLocaleDateString("fr-FR", {
113
+ year: "numeric",
114
+ month: "long",
115
+ day: "numeric",
116
+ })
117
+ : "N/A" })] }), _jsxs("div", { children: [_jsx("span", { className: "text-default-500", children: "Derni\u00E8re connexion" }), _jsx("p", { className: "font-medium mt-1", children: userProfile.last_sign_in_at
118
+ ? new Date(userProfile.last_sign_in_at).toLocaleDateString("fr-FR", {
119
+ year: "numeric",
120
+ month: "long",
121
+ day: "numeric",
122
+ hour: "2-digit",
123
+ minute: "2-digit",
124
+ })
125
+ : "Jamais" })] })] })] }) })] }) }, "profile"), _jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(Bell, { size: 16 }), _jsx("span", { children: "Notifications" })] }), children: _jsxs("div", { className: "space-y-4 mt-4", children: [_jsx("h3", { className: "font-semibold", children: "Envoyer une notification" }), _jsxs("div", { className: "space-y-4", children: [_jsx(Input, { label: "Titre de la notification", placeholder: "Ex: Nouveau message important", value: notificationTitle, onChange: (e) => setNotificationTitle(e.target.value), maxLength: 100 }), _jsx(Textarea, { label: "Message", placeholder: "Contenu de la notification...", value: notificationMessage, onChange: (e) => setNotificationMessage(e.target.value), maxLength: 500, minRows: 3 }), _jsxs(Select, { label: "Type de notification", selectedKeys: [notificationType], onSelectionChange: (keys) => setNotificationType(Array.from(keys)[0]), children: [_jsx(SelectItem, { children: "Information" }, "info"), _jsx(SelectItem, { children: "Avertissement" }, "warning"), _jsx(SelectItem, { children: "Danger" }, "danger"), _jsx(SelectItem, { children: "Succ\u00E8s" }, "success")] }), _jsx(Button, { color: "primary", onPress: handleSendNotification, isLoading: sendingNotification, startContent: _jsx(Bell, { size: 16 }), isDisabled: !notificationTitle.trim() || !notificationMessage.trim(), children: "Envoyer la notification" })] })] }) }, "notifications"), _jsx(Tab, { title: _jsxs("div", { className: "flex items-center space-x-2", children: [_jsx(Settings, { size: 16 }), _jsx("span", { children: "Param\u00E8tres" })] }), children: _jsxs("div", { className: "space-y-4 mt-4", children: [_jsx("h3", { className: "font-semibold", children: "Actions administrateur" }), _jsxs("div", { className: "space-y-3 space-x-5", children: [_jsx(Button, { color: "warning", variant: "bordered", size: "sm", children: "R\u00E9initialiser le mot de passe" }), _jsx(Button, { color: "danger", variant: "bordered", size: "sm", children: "Suspendre le compte" }), _jsx(Button, { color: "secondary", variant: "bordered", size: "sm", children: "Promouvoir en administrateur" })] }), _jsxs("div", { className: "mt-6 p-4 bg-gray-50 dark:bg-gray-800 rounded-lg", children: [_jsx("h4", { className: "font-medium mb-2", children: "M\u00E9tadonn\u00E9es techniques" }), _jsx("pre", { className: "text-xs text-gray-600 dark:text-gray-400 overflow-auto", children: JSON.stringify({
105
126
  app_metadata: userProfile.raw_app_meta_data,
106
127
  user_metadata: userProfile.raw_user_meta_data,
107
128
  }, null, 2) })] })] }) }, "settings"), moduleUserTabs.map((tab) => {
@@ -1 +1 @@
1
- {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/web/admin/users.tsx"],"names":[],"mappings":"AAuCA,wBAAgB,cAAc,4CAuO7B"}
1
+ {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/web/admin/users.tsx"],"names":[],"mappings":"AA6CA,wBAAgB,cAAc,4CAmP7B"}
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useCallback, useEffect, useState, useId } from "react";
4
- import { Card, CardBody, CardHeader, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Spinner, Input, Button, Pagination, Avatar, } from "@lastbrain/ui";
5
- import { Users, Search, RefreshCw, Eye } from "lucide-react";
4
+ import { Card, CardBody, CardHeader, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Spinner, Chip, Input, Button, Pagination, Avatar, } from "@lastbrain/ui";
5
+ import { Search, RefreshCw, Eye, Users2 } from "lucide-react";
6
6
  import { useRouter } from "next/navigation";
7
7
  export function AdminUsersPage() {
8
8
  const router = useRouter();
@@ -76,15 +76,15 @@ export function AdminUsersPage() {
76
76
  if (error && users.length === 0) {
77
77
  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
78
  }
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(Users, { 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) => {
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) => {
80
80
  if (e.key === "Enter") {
81
81
  handleSearch();
82
82
  }
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, { "aria-label": "Users table", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: "USER" }), _jsx(TableColumn, { children: "EMAIL" }), _jsx(TableColumn, { children: "LAST SIGN IN" }), _jsx(TableColumn, { children: "CREATED" }), _jsx(TableColumn, { children: "ACTIONS" })] }), _jsx(TableBody, { children: users.map((user) => {
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) => {
84
84
  const displayName = user.full_name || user.email;
85
- return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Avatar, { src: user.avatar_url
85
+ 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
86
  ? `/api/storage/${user.avatar_url}`
87
- : 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("span", { className: "text-small", children: user.last_sign_in_at
87
+ : 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
88
  ? formatDate(user.last_sign_in_at)
89
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
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"] })] })) })] })] }));
@@ -174,21 +174,21 @@ export function ProfilePage() {
174
174
  if (isLoading) {
175
175
  return (_jsx("div", { className: "flex justify-center items-center min-h-[400px]", children: _jsx(Spinner, { size: "lg", label: "Loading profile..." }) }));
176
176
  }
177
- 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(User, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: "Edit Profile" })] }), _jsx("form", { onSubmit: handleSubmit, children: _jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx("h3", { className: "text-lg font-semibold", children: "Photo de profil" }) }), _jsx(Divider, {}), _jsx(CardBody, { 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
- profile.avatar_url ||
179
- null, initialAvatarSizes: (() => {
180
- const sizes = currentUser?.user_metadata
181
- ?.avatar_sizes;
182
- if (!sizes)
183
- return null;
184
- return {
185
- small: sizes.small ?? null,
186
- medium: sizes.medium ?? null,
187
- large: sizes.large ?? null,
188
- };
189
- })(), onUploaded: (urls) => {
190
- setProfile((prev) => ({ ...prev, avatar_url: urls.large }));
191
- }, onDeleted: () => {
192
- setProfile((prev) => ({ ...prev, avatar_url: "" }));
193
- } }) }) })] }), _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" })] })] }) })] }));
177
+ 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(User, { className: "w-8 h-8" }), _jsx("h1", { className: "text-3xl font-bold", children: "Edit Profile" })] }), _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
+ profile.avatar_url ||
179
+ null, initialAvatarSizes: (() => {
180
+ const sizes = currentUser?.user_metadata
181
+ ?.avatar_sizes;
182
+ if (!sizes)
183
+ return null;
184
+ return {
185
+ small: sizes.small ?? null,
186
+ medium: sizes.medium ?? null,
187
+ large: sizes.large ?? null,
188
+ };
189
+ })(), onUploaded: (urls) => {
190
+ setProfile((prev) => ({ ...prev, avatar_url: urls.large }));
191
+ }, onDeleted: () => {
192
+ setProfile((prev) => ({ ...prev, avatar_url: "" }));
193
+ } }) }), _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" })] })] }) })] }));
194
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lastbrain/module-auth",
3
- "version": "0.1.16",
3
+ "version": "0.1.19",
4
4
  "description": "Module d'authentification complet pour LastBrain avec Supabase",
5
5
  "private": false,
6
6
  "type": "module",
@@ -31,6 +31,7 @@
31
31
  "dependencies": {
32
32
  "@lastbrain/core": "^0.1.0",
33
33
  "@lastbrain/ui": "^0.1.4",
34
+ "@supabase/supabase-js": "^2.86.0",
34
35
  "lucide-react": "^0.554.0",
35
36
  "react": "^19.0.0",
36
37
  "react-dom": "^19.0.0"