@lastbrain/module-auth 0.1.10 → 0.1.13

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.
@@ -1,129 +1,153 @@
1
- import React from "react";
1
+ "use client";
2
+
3
+ import { Card, CardBody, CardHeader } from "@lastbrain/ui";
4
+ import { Chip } from "@lastbrain/ui";
5
+ import { Snippet } from "@lastbrain/ui";
6
+ import { Alert } from "@lastbrain/ui";
7
+ import { TableStructure } from "@lastbrain/ui";
2
8
  import {
3
- Card,
4
- CardBody,
5
- CardHeader,
6
- Snippet,
7
- Chip,
8
- TableStructure,
9
- } from "@lastbrain/ui";
9
+ FileText,
10
+ Zap,
11
+ Database,
12
+ Package,
13
+ BookOpen,
14
+ AlertTriangle,
15
+ } from "lucide-react";
10
16
 
11
- export function AuthModuleDoc() {
17
+ /**
18
+ * Documentation component for @lastbrain/module-auth
19
+ * Auto-generated from module-auth.build.config.ts
20
+ *
21
+ * To regenerate this file, run:
22
+ * pnpm update:module-docs
23
+ */
24
+ export function Doc() {
12
25
  return (
13
- <div className="space-y-6">
14
- {/* Header */}
15
- <div className="flex items-start justify-between">
16
- <div>
17
- <h2 className="text-3xl font-bold mb-2">Module Auth</h2>
18
- <p className="text-slate-600 dark:text-slate-400">
19
- Authentification complète avec gestion des profils utilisateur
20
- </p>
21
- </div>
22
- <Chip color="primary" variant="flat">
23
- v0.1.0
24
- </Chip>
25
- </div>
26
-
27
- {/* Author */}
26
+ <div className="container mx-auto p-6 space-y-6">
28
27
  <Card>
29
28
  <CardHeader>
30
- <h3 className="text-xl font-semibold">📝 Informations</h3>
31
- </CardHeader>
32
- <CardBody className="space-y-2">
33
- <div>
34
- <span className="font-semibold">Auteur:</span> LastBrain Team
35
- </div>
36
29
  <div>
37
- <span className="font-semibold">Package:</span>{" "}
38
- @lastbrain/module-auth
30
+ <h1 className="text-3xl font-bold mb-2">📦 Module auth</h1>
31
+ <p className="text-slate-600 dark:text-slate-400">
32
+ @lastbrain/module-auth
33
+ </p>
39
34
  </div>
40
- <div>
41
- <span className="font-semibold">Dernière mise à jour:</span> 21
42
- novembre 2025
35
+ </CardHeader>
36
+ <CardBody>
37
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
38
+ <div>
39
+ <p className="text-sm text-slate-600 dark:text-slate-400">
40
+ Package
41
+ </p>
42
+ <code className="text-sm font-semibold">
43
+ @lastbrain/module-auth
44
+ </code>
45
+ </div>
46
+ <div>
47
+ <p className="text-sm text-slate-600 dark:text-slate-400">Slug</p>
48
+ <code className="text-sm font-semibold">module-auth</code>
49
+ </div>
50
+ <div>
51
+ <p className="text-sm text-slate-600 dark:text-slate-400">Type</p>
52
+ <code className="text-sm font-semibold">Module LastBrain</code>
53
+ </div>
43
54
  </div>
44
55
  </CardBody>
45
56
  </Card>
46
57
 
47
- {/* Pages disponibles */}
48
58
  <Card>
49
59
  <CardHeader>
50
- <h3 className="text-xl font-semibold">📄 Pages Disponibles</h3>
60
+ <h2 className="text-2xl font-semibold flex items-center gap-2">
61
+ <FileText size={24} />
62
+ Pages Disponibles
63
+ </h2>
51
64
  </CardHeader>
52
- <CardBody className="space-y-3">
65
+ <CardBody className="space-y-4">
53
66
  <div>
54
- <h4 className="font-semibold mb-2">Pages Publiques</h4>
67
+ <h3 className="text-lg font-semibold mb-2">Pages Publiques</h3>
55
68
  <div className="space-y-2">
56
- <div className="flex items-center gap-2">
69
+ <div className="flex items-start gap-2">
57
70
  <Chip size="sm" color="success" variant="flat">
58
71
  GET
59
72
  </Chip>
60
73
  <code className="text-sm">/signin</code>
61
- <span className="text-slate-600 dark:text-slate-400">
62
- - Connexion
74
+ <span className="text-sm text-slate-600 dark:text-slate-400">
75
+ - SignInPage
63
76
  </span>
64
77
  </div>
65
- <div className="flex items-center gap-2">
78
+ <div className="flex items-start gap-2">
66
79
  <Chip size="sm" color="success" variant="flat">
67
80
  GET
68
81
  </Chip>
69
82
  <code className="text-sm">/signup</code>
70
- <span className="text-slate-600 dark:text-slate-400">
71
- - Inscription
83
+ <span className="text-sm text-slate-600 dark:text-slate-400">
84
+ - SignUpPage
72
85
  </span>
73
86
  </div>
74
- <div className="flex items-center gap-2">
87
+ <div className="flex items-start gap-2">
75
88
  <Chip size="sm" color="success" variant="flat">
76
89
  GET
77
90
  </Chip>
78
91
  <code className="text-sm">/reset-password</code>
79
- <span className="text-slate-600 dark:text-slate-400">
80
- - Réinitialisation mot de passe
92
+ <span className="text-sm text-slate-600 dark:text-slate-400">
93
+ - ResetPassword
81
94
  </span>
82
95
  </div>
83
96
  </div>
84
97
  </div>
85
98
  <div>
86
- <h4 className="font-semibold mb-2">Pages Protégées (Auth)</h4>
99
+ <h3 className="text-lg font-semibold mb-2">
100
+ Pages Protégées (Auth)
101
+ </h3>
87
102
  <div className="space-y-2">
88
- <div className="flex items-center gap-2">
103
+ <div className="flex items-start gap-2">
89
104
  <Chip size="sm" color="primary" variant="flat">
90
105
  GET
91
106
  </Chip>
92
- <code className="text-sm">/auth/dashboard</code>
93
- <span className="text-slate-600 dark:text-slate-400">
94
- - Tableau de bord
107
+ <code className="text-sm">/dashboard</code>
108
+ <span className="text-sm text-slate-600 dark:text-slate-400">
109
+ - DashboardPage
95
110
  </span>
96
111
  </div>
97
- <div className="flex items-center gap-2">
112
+ <div className="flex items-start gap-2">
98
113
  <Chip size="sm" color="primary" variant="flat">
99
114
  GET
100
115
  </Chip>
101
- <code className="text-sm">/auth/profile</code>
102
- <span className="text-slate-600 dark:text-slate-400">
103
- - Profil utilisateur
116
+ <code className="text-sm">/folder</code>
117
+ <span className="text-sm text-slate-600 dark:text-slate-400">
118
+ - FolderPage
104
119
  </span>
105
120
  </div>
106
- <div className="flex items-center gap-2">
121
+ <div className="flex items-start gap-2">
107
122
  <Chip size="sm" color="primary" variant="flat">
108
123
  GET
109
124
  </Chip>
110
- <code className="text-sm">/auth/reglage</code>
111
- <span className="text-slate-600 dark:text-slate-400">
112
- - Paramètres
125
+ <code className="text-sm">/reglage</code>
126
+ <span className="text-sm text-slate-600 dark:text-slate-400">
127
+ - ReglagePage
128
+ </span>
129
+ </div>
130
+ <div className="flex items-start gap-2">
131
+ <Chip size="sm" color="primary" variant="flat">
132
+ GET
133
+ </Chip>
134
+ <code className="text-sm">/profile</code>
135
+ <span className="text-sm text-slate-600 dark:text-slate-400">
136
+ - ProfilePage
113
137
  </span>
114
138
  </div>
115
139
  </div>
116
140
  </div>
117
141
  <div>
118
- <h4 className="font-semibold mb-2">Pages Admin</h4>
142
+ <h3 className="text-lg font-semibold mb-2">Pages Admin</h3>
119
143
  <div className="space-y-2">
120
- <div className="flex items-center gap-2">
121
- <Chip size="sm" color="danger" variant="flat">
144
+ <div className="flex items-start gap-2">
145
+ <Chip size="sm" color="secondary" variant="flat">
122
146
  GET
123
147
  </Chip>
124
- <code className="text-sm">/admin/users</code>
125
- <span className="text-slate-600 dark:text-slate-400">
126
- - Gestion des utilisateurs
148
+ <code className="text-sm">/users</code>
149
+ <span className="text-sm text-slate-600 dark:text-slate-400">
150
+ - AdminUsersPage
127
151
  </span>
128
152
  </div>
129
153
  </div>
@@ -131,176 +155,220 @@ export function AuthModuleDoc() {
131
155
  </CardBody>
132
156
  </Card>
133
157
 
134
- {/* Routes API */}
135
158
  <Card>
136
159
  <CardHeader>
137
- <h3 className="text-xl font-semibold">🔌 Routes API</h3>
160
+ <h2 className="text-2xl font-semibold flex items-center gap-2">
161
+ <Zap size={24} />
162
+ API Routes
163
+ </h2>
138
164
  </CardHeader>
139
- <CardBody className="space-y-2">
140
- <div className="flex items-center gap-2">
141
- <Chip size="sm" color="warning" variant="flat">
142
- POST
143
- </Chip>
144
- <code className="text-sm">/api/auth/signin</code>
145
- <span className="text-slate-600 dark:text-slate-400">
146
- - Authentification
147
- </span>
148
- </div>
149
- <div className="flex items-center gap-2">
150
- <Chip size="sm" color="warning" variant="flat">
151
- POST
152
- </Chip>
153
- <code className="text-sm">/api/auth/signup</code>
154
- <span className="text-slate-600 dark:text-slate-400">
155
- - Création de compte
156
- </span>
165
+ <CardBody className="space-y-4">
166
+ <div>
167
+ <h3 className="text-lg font-semibold mb-2">
168
+ <code>/api/auth/signin</code>
169
+ </h3>
170
+ <div className="flex gap-2">
171
+ <Chip size="sm" color="success" variant="flat">
172
+ GET
173
+ </Chip>
174
+ <Chip size="sm" color="primary" variant="flat">
175
+ POST
176
+ </Chip>
177
+ <Chip size="sm" color="warning" variant="flat">
178
+ PUT
179
+ </Chip>
180
+ <Chip size="sm" color="danger" variant="flat">
181
+ DELETE
182
+ </Chip>
183
+ </div>
157
184
  </div>
158
- <div className="flex items-center gap-2">
159
- <Chip size="sm" color="warning" variant="flat">
160
- POST
161
- </Chip>
162
- <code className="text-sm">/api/auth/signout</code>
163
- <span className="text-slate-600 dark:text-slate-400">
164
- - Déconnexion
165
- </span>
185
+ <div>
186
+ <h3 className="text-lg font-semibold mb-2">
187
+ <code>/api/auth/profile</code>
188
+ </h3>
189
+ <div className="flex gap-2">
190
+ <Chip size="sm" color="success" variant="flat">
191
+ GET
192
+ </Chip>
193
+ <Chip size="sm" color="primary" variant="flat">
194
+ POST
195
+ </Chip>
196
+ <Chip size="sm" color="warning" variant="flat">
197
+ PUT
198
+ </Chip>
199
+ <Chip size="sm" color="danger" variant="flat">
200
+ DELETE
201
+ </Chip>
202
+ </div>
166
203
  </div>
167
- <div className="flex items-center gap-2">
168
- <Chip size="sm" color="warning" variant="flat">
169
- POST
170
- </Chip>
171
- <code className="text-sm">/api/auth/reset-password</code>
172
- <span className="text-slate-600 dark:text-slate-400">
173
- - Réinitialisation
174
- </span>
204
+ <div>
205
+ <h3 className="text-lg font-semibold mb-2">
206
+ <code>/api/auth/me</code>
207
+ </h3>
208
+ <div className="flex gap-2">
209
+ <Chip size="sm" color="success" variant="flat">
210
+ GET
211
+ </Chip>
212
+ <Chip size="sm" color="primary" variant="flat">
213
+ POST
214
+ </Chip>
215
+ <Chip size="sm" color="warning" variant="flat">
216
+ PUT
217
+ </Chip>
218
+ <Chip size="sm" color="danger" variant="flat">
219
+ DELETE
220
+ </Chip>
221
+ </div>
175
222
  </div>
176
- </CardBody>
177
- </Card>
178
-
179
- {/* Structure */}
180
- <Card>
181
- <CardHeader>
182
- <h3 className="text-xl font-semibold">📁 Structure</h3>
183
- </CardHeader>
184
- <CardBody>
185
- <Snippet
186
- symbol=""
187
- color="default"
188
- size="sm"
189
- hideSymbol
190
- hideCopyButton
191
- >
192
- <div className="flex flex-col gap-1 text-xs font-mono">
193
- <span>module-auth/</span>
194
- <span>├── src/</span>
195
- <span>│ ├── web/</span>
196
- <span>│ │ ├── signin/</span>
197
- <span>│ │ ├── signup/</span>
198
- <span>│ │ ├── dashboard/</span>
199
- <span>│ │ ├── profile/</span>
200
- <span>│ │ └── reglage/</span>
201
- <span>│ ├── api/</span>
202
- <span>│ │ ├── signin.ts</span>
203
- <span>│ │ ├── signup.ts</span>
204
- <span>│ │ ├── signout.ts</span>
205
- <span>│ │ └── reset-password.ts</span>
206
- <span>│ ├── components/</span>
207
- <span>│ │ └── Doc.tsx</span>
208
- <span>│ └── auth.build.config.ts</span>
209
- <span>└── supabase/</span>
210
- <span> └── migrations/</span>
211
- <span> └── 20251112000000_user_init.sql</span>
223
+ <div>
224
+ <h3 className="text-lg font-semibold mb-2">
225
+ <code>/api/admin/users</code>
226
+ </h3>
227
+ <div className="flex gap-2">
228
+ <Chip size="sm" color="success" variant="flat">
229
+ GET
230
+ </Chip>
231
+ <Chip size="sm" color="primary" variant="flat">
232
+ POST
233
+ </Chip>
234
+ <Chip size="sm" color="warning" variant="flat">
235
+ PUT
236
+ </Chip>
237
+ <Chip size="sm" color="danger" variant="flat">
238
+ DELETE
239
+ </Chip>
212
240
  </div>
213
- </Snippet>
241
+ </div>
214
242
  </CardBody>
215
243
  </Card>
216
244
 
217
- {/* Tables de données */}
218
245
  <Card>
219
246
  <CardHeader>
220
- <h3 className="text-xl font-semibold">🗄️ Tables de Données</h3>
247
+ <h2 className="text-2xl font-semibold flex items-center gap-2">
248
+ <Database size={24} />
249
+ Base de Données
250
+ </h2>
221
251
  </CardHeader>
222
- <CardBody className="space-y-4">
252
+ <CardBody className="space-y-6">
223
253
  <TableStructure
224
254
  tableName="user_profil"
225
255
  title="user_profil"
226
- description="Profil étendu des utilisateurs (prénom, nom, téléphone, avatar, bio, etc.)"
256
+ description="Table user_profil du module auth"
227
257
  />
228
258
  <TableStructure
229
259
  tableName="user_address"
230
260
  title="user_address"
231
- description="Adresses des utilisateurs (livraison, facturation)"
261
+ description="Table user_address du module auth"
232
262
  />
233
263
  <TableStructure
234
264
  tableName="user_notifications"
235
265
  title="user_notifications"
236
- description="Préférences de notifications (email, SMS, push)"
266
+ description="Table user_notifications du module auth"
237
267
  />
238
268
  </CardBody>
239
269
  </Card>
240
270
 
241
- {/* Installation */}
242
271
  <Card>
243
272
  <CardHeader>
244
- <h3 className="text-xl font-semibold">📦 Installation</h3>
273
+ <h2 className="text-2xl font-semibold flex items-center gap-2">
274
+ <Package size={24} />
275
+ Installation
276
+ </h2>
245
277
  </CardHeader>
246
278
  <CardBody className="space-y-4">
247
279
  <div className="flex flex-col gap-2">
248
- <Snippet symbol="" color="default" size="sm">
280
+ <h3 className="text-lg font-semibold mb-2">Ajouter le module</h3>
281
+ <Snippet symbol="" hideSymbol className="text-sm mb-2">
249
282
  pnpm lastbrain add-module auth
250
283
  </Snippet>
251
- <Snippet symbol="" color="default" size="sm">
284
+ <Snippet symbol="" hideSymbol className="text-sm mb-2">
252
285
  pnpm build:modules
253
286
  </Snippet>
254
- <Snippet symbol="" color="default" size="sm">
287
+ </div>
288
+
289
+ <div className="flex flex-col gap-2">
290
+ <h3 className="text-lg font-semibold mb-2">
291
+ Appliquer les migrations
292
+ </h3>
293
+ <Snippet symbol="" hideSymbol className="text-sm mb-2">
294
+ cd apps/votre-app
295
+ </Snippet>
296
+ <Snippet symbol="" hideSymbol className="text-sm mb-2">
255
297
  supabase migration up
256
298
  </Snippet>
257
299
  </div>
300
+ </CardBody>
301
+ </Card>
258
302
 
259
- {/* Danger Zone */}
260
- <div className="border-2 border-danger rounded-lg p-4 mt-6">
261
- <h4 className="text-lg font-semibold text-danger mb-3">
262
- ⚠️ Danger Zone
263
- </h4>
264
- <p className="text-sm text-slate-600 dark:text-slate-400 mb-3">
265
- La suppression du module supprimera toutes les pages, routes API
266
- et migrations associées. Cette action est irréversible.
303
+ <Card>
304
+ <CardHeader>
305
+ <h2 className="text-2xl font-semibold flex items-center gap-2">
306
+ <BookOpen size={24} />
307
+ Utilisation
308
+ </h2>
309
+ </CardHeader>
310
+ <CardBody className="space-y-4">
311
+ <Alert color="default" className="mb-4">
312
+ <p className="text-sm">
313
+ 📝 <strong>Section à compléter par l'auteur du module</strong>
267
314
  </p>
268
- <div className="flex flex-col gap-2">
269
- <Snippet symbol="" color="danger" size="sm">
270
- pnpm lastbrain remove-module auth
271
- </Snippet>
272
- <Snippet symbol="" color="danger" size="sm">
273
- pnpm build:modules
274
- </Snippet>
275
- </div>
315
+ <p className="text-sm text-slate-600 dark:text-slate-400 mt-2">
316
+ Ajoutez ici des exemples d'utilisation, des configurations
317
+ spécifiques, et toute information utile pour les développeurs
318
+ utilisant ce module.
319
+ </p>
320
+ </Alert>
321
+
322
+ <div>
323
+ <h3 className="text-lg font-semibold mb-2">
324
+ Exemple d'utilisation
325
+ </h3>
326
+ <Alert color="primary" className="p-4 mb-4">
327
+ <pre className="whitespace-pre-wrap">{`// Importez les composants depuis le module
328
+ import { SignInPage } from "@lastbrain/module-auth";
329
+
330
+ // Utilisez-les dans votre application
331
+ <SignInPage />`}</pre>
332
+ </Alert>
276
333
  </div>
277
334
  </CardBody>
278
335
  </Card>
279
336
 
280
- {/* Utilisation */}
281
337
  <Card>
282
338
  <CardHeader>
283
- <h3 className="text-xl font-semibold">💡 Utilisation</h3>
339
+ <h2 className="text-2xl font-semibold flex items-center gap-2 text-danger">
340
+ <AlertTriangle size={24} />
341
+ Danger Zone
342
+ </h2>
284
343
  </CardHeader>
285
- <CardBody className="space-y-3">
286
- <div>
287
- <h4 className="font-semibold mb-2">Hooks disponibles</h4>
288
- <Snippet symbol="" color="default" size="sm">
289
- import {"{ useAuthSession }"} from "@lastbrain/module-auth";
344
+ <CardBody className="space-y-4">
345
+ <Alert color="danger" className="mb-4">
346
+ <p className="text-sm font-semibold">
347
+ Cette action est irréversible
348
+ </p>
349
+ <p className="text-sm mt-2">
350
+ La suppression du module supprimera toutes les pages, routes API
351
+ et migrations associées.
352
+ </p>
353
+ </Alert>
354
+
355
+ <div className="flex flex-col gap-2">
356
+ <h3 className="text-lg font-semibold mb-2">Supprimer le module</h3>
357
+ <Snippet
358
+ symbol=""
359
+ hideSymbol
360
+ color="danger"
361
+ className="text-sm mb-2"
362
+ >
363
+ pnpm lastbrain remove-module auth
290
364
  </Snippet>
291
- </div>
292
- <div>
293
- <h4 className="font-semibold mb-2 mt-4">Exemple d'utilisation</h4>
294
- <Snippet symbol="" color="default" size="sm" hideSymbol>
295
- <div className="flex flex-col gap-1">
296
- <span>const {"{ session, user }"} = useAuthSession();</span>
297
- <span>
298
- if (!session) return &lt;p&gt;Non connecté&lt;/p&gt;;
299
- </span>
300
- <span>
301
- return &lt;div&gt;Bonjour {"{user.email}"}&lt;/div&gt;;
302
- </span>
303
- </div>
365
+ <Snippet
366
+ symbol=""
367
+ hideSymbol
368
+ color="danger"
369
+ className="text-sm mb-2"
370
+ >
371
+ pnpm build:modules
304
372
  </Snippet>
305
373
  </div>
306
374
  </CardBody>
package/src/index.ts CHANGED
@@ -3,11 +3,14 @@ export { SignInPage } from "./web/public/SignInPage.js";
3
3
  export { SignUpPage } from "./web/public/SignUpPage.js";
4
4
  export { ResetPassword } from "./web/public/ResetPassword.js";
5
5
  export { DashboardPage } from "./web/auth/dashboard.js";
6
+ export { FolderPage } from "./web/auth/folder.js";
6
7
  export { ProfilePage } from "./web/auth/profile.js";
7
8
  export { ReglagePage } from "./web/auth/reglage.js";
8
9
  export { AdminUsersPage } from "./web/admin/users.js";
9
10
  export { default as UserPage } from "./web/admin/users/[id].js";
11
+ export { UserDetailPage } from "./web/admin/user-detail.js";
10
12
  // Documentation
11
- export { AuthModuleDoc } from "./components/Doc.js";
13
+ export { Doc } from "./components/Doc.js";
14
+ export { Doc as AuthModuleDoc } from "./components/Doc.js";
12
15
  // Configuration de build (utilisée par les scripts)
13
16
  export { default as authBuildConfig } from "./auth.build.config.js";
@@ -20,6 +20,14 @@ import {
20
20
  } from "@lastbrain/ui";
21
21
  import { User, Bell, Settings, Save } from "lucide-react";
22
22
  import { useAuth } from "@lastbrain/core";
23
+ import * as LucideIcons from "lucide-react";
24
+
25
+ interface ModuleUserTab {
26
+ key: string;
27
+ title: string;
28
+ icon?: string;
29
+ component: React.ComponentType<{ userId: string }>;
30
+ }
23
31
 
24
32
  interface UserProfile {
25
33
  id: string;
@@ -34,12 +42,17 @@ interface UserProfile {
34
42
 
35
43
  interface UserDetailPageProps {
36
44
  userId: string;
45
+ moduleUserTabs?: ModuleUserTab[];
37
46
  }
38
47
 
39
- export function UserDetailPage({ userId }: UserDetailPageProps) {
48
+ export function UserDetailPage({
49
+ userId,
50
+ moduleUserTabs = [],
51
+ }: UserDetailPageProps) {
40
52
  const { user: _currentUser } = useAuth();
41
53
  const [userProfile, setUserProfile] = useState<UserProfile | null>(null);
42
54
  const [loading, setLoading] = useState(true);
55
+ // Les onglets modules sont passés via props (injection serveur)
43
56
  const [notificationTitle, setNotificationTitle] = useState("");
44
57
  const [notificationMessage, setNotificationMessage] = useState("");
45
58
  const [notificationType, setNotificationType] = useState("info");
@@ -179,6 +192,8 @@ export function UserDetailPage({ userId }: UserDetailPageProps) {
179
192
  {/* Tabs */}
180
193
  <Card>
181
194
  <CardBody>
195
+ {/* moduleUserTabs injectés (debug retiré) */}
196
+
182
197
  <Tabs
183
198
  aria-label="Options utilisateur"
184
199
  color="primary"
@@ -340,6 +355,28 @@ export function UserDetailPage({ userId }: UserDetailPageProps) {
340
355
  </div>
341
356
  </div>
342
357
  </Tab>
358
+ {/* Tabs dynamiques depuis les modules */}
359
+ {moduleUserTabs.map((tab) => {
360
+ const TabComponent = tab.component;
361
+ const IconComponent = tab.icon
362
+ ? (LucideIcons as any)[tab.icon]
363
+ : null;
364
+
365
+ return (
366
+ <Tab
367
+ key={tab.key}
368
+ title={
369
+ <div className="flex items-center space-x-2">
370
+ {IconComponent && <IconComponent size={16} />}
371
+ <span>{tab.title}</span>
372
+ </div>
373
+ }
374
+ >
375
+ <TabComponent userId={userId} />
376
+ </Tab>
377
+ );
378
+ })}
379
+ {/* Pas d'état de chargement : injection directe */}
343
380
  </Tabs>
344
381
  </CardBody>
345
382
  </Card>