@@ -3,11 +3,10 @@ import { SiteHeader } from '@/components/site-header';
33import { AppTabs } from '@/components/app-tabs' ;
44import { BottomNav } from '@/components/bottom-nav' ;
55import { AssistantBubble } from '@/components/assistant/assistant-bubble' ;
6- import { stackServerApp } from '@/lib/stack-server' ;
76import { redirect } from 'next/navigation' ;
8- import { getServerSession } from 'next-auth/next' ;
9- import { authOptions } from '@/lib/auth-options' ; // ton NextAuth config
7+ import { resolveUser } from '@/lib/api/with-auth' ;
108import { isAdminRole } from '@/lib/nav-apps' ;
9+ import { UserAccessProvider } from '@/contexts/user-access-context' ;
1110import type React from 'react' ;
1211
1312// Dashboard authentifié : rendu à la demande (jamais prérendu au build).
@@ -20,79 +19,15 @@ export default async function DashboardLayout({
2019 children : React . ReactNode ;
2120} ) {
2221 // ===============================
23- // 1. Essayer Stack Auth
22+ // 1. Résolution unifiée Stack / Authentik (rôle + permission planning ;
23+ // les comptes Authentik lisent leurs accès dans la table locale `users`).
2424 // ===============================
25- const stackUser = await stackServerApp . getUser ( ) ;
26-
27- let user : {
28- id : string ;
29- email : string ;
30- name : string ;
31- image ?: string ;
32- role : string ;
33- planningPermission : string ;
34- provider : 'stack' | 'authentik' ;
35- } | null = null ;
36-
37- if ( stackUser ) {
38- // Utilisateur Stack Auth trouvé
39- user = {
40- id : stackUser . id ,
41- email : stackUser . primaryEmail ?? '' ,
42- name : stackUser . displayName ?? stackUser . primaryEmail ?? '' ,
43- image : stackUser . profileImageUrl ?? undefined ,
44- role :
45- stackUser . serverMetadata ?. role ||
46- stackUser . clientReadOnlyMetadata ?. role ||
47- stackUser . clientMetadata ?. role ||
48- 'user' ,
49- planningPermission :
50- stackUser . serverMetadata ?. planningPermission ||
51- stackUser . clientReadOnlyMetadata ?. planningPermission ||
52- stackUser . clientMetadata ?. planningPermission ||
53- 'reader' ,
54- provider : 'stack' ,
55- } ;
56-
57- /*console.log('✅ Dashboard - Stack Auth utilisateur:', user.email, '- Rôle:', user.role);*/
58- } else {
59- // ===============================
60- // 2. Essayer NextAuth / Authentik
61- // ===============================
62- const session = await getServerSession ( authOptions ) ;
63-
64- if ( session ?. user ?. email ) {
65- // Déterminer le rôle à partir des groupes Authentik
66- const groups : string [ ] = ( session . user . groups || [ ] ) as string [ ] ;
67- // Admin = groupe Developers (ou authentik Admins). Sans groupe = étudiant.
68- const isAdmin = groups . includes ( 'Developers' ) || groups . includes ( 'authentik Admins' ) ;
69-
70- user = {
71- id : session . user . id ?? '' ,
72- email : session . user . email ?? '' ,
73- name : session . user . name ?? session . user . email ?? '' ,
74- image : session . user . image ?? undefined ,
75- role : isAdmin ? 'Admin' : 'user' ,
76- planningPermission : 'reader' , // par défaut pour Authentik
77- provider : 'authentik' ,
78- } ;
79-
80- console . log (
81- '✅ Dashboard - NextAuth/Authentik utilisateur connecté:' ,
82- user . email ,
83- 'Role:' ,
84- user . role
85- ) ;
86- }
87- }
25+ const user = await resolveUser ( ) ;
8826
8927 // ===============================
9028 // 3. Pas de session détectée → rediriger vers login
9129 // ===============================
9230 if ( ! user ) {
93- console . log (
94- '⛔ Dashboard - Aucun utilisateur connecté, redirection vers /login'
95- ) ;
9631 redirect ( '/login' ) ;
9732 }
9833
@@ -111,36 +46,51 @@ export default async function DashboardLayout({
11146 // ===============================
11247 const isStudent = ! isAdminRole ( user . role ) ;
11348
49+ // Accès unifié exposé aux Client Components (pages planning/settings…) :
50+ // remplace useUser() de Stack, qui renvoie null pour les comptes Authentik.
51+ const access = {
52+ email : user . email ,
53+ name : user . name ,
54+ image : user . image ?? null ,
55+ role : user . role ,
56+ planningPermission : user . planningPermission ,
57+ provider : user . provider ,
58+ } ;
59+
11460 // Étudiant : shell minimal (juste le header pour le menu/déconnexion). La
11561 // navigation est la navbar PARTAGÉE z01-student-nav (sidebar desktop / bottom
11662 // mobile, rendue dans la landing) — identique sur hub/émargement/01deck. On
11763 // réserve l'espace : padding gauche (sidebar desktop) / bas (barre mobile).
11864 if ( isStudent ) {
11965 return (
120- < div className = "fixed inset-0 flex flex-col overflow-hidden" >
121- < SiteHeader />
122- < div className = "flex flex-1 flex-col min-h-0 overflow-auto" > { children } </ div >
123- </ div >
66+ < UserAccessProvider value = { access } >
67+ < div className = "fixed inset-0 flex flex-col overflow-hidden" >
68+ < SiteHeader />
69+ < div className = "flex flex-1 flex-col min-h-0 overflow-auto" > { children } </ div >
70+ </ div >
71+ </ UserAccessProvider >
12472 ) ;
12573 }
12674
12775 // Admin : shell complet (sidebar + onglets + bottom-nav).
12876 return (
129- < div className = "fixed inset-0 flex overflow-hidden" >
130- < AppSidebar user = { user } />
131- < div className = "flex flex-1 flex-col min-w-0 overflow-hidden" >
132- < SiteHeader />
133- < AppTabs />
134- < div className = "flex flex-1 flex-col min-h-0 overflow-auto pb-14 md:pb-0" >
135- < div className = "@container/main flex flex-1 flex-col gap-2" >
136- { children }
77+ < UserAccessProvider value = { access } >
78+ < div className = "fixed inset-0 flex overflow-hidden" >
79+ < AppSidebar user = { user } />
80+ < div className = "flex flex-1 flex-col min-w-0 overflow-hidden" >
81+ < SiteHeader />
82+ < AppTabs />
83+ < div className = "flex flex-1 flex-col min-h-0 overflow-auto pb-14 md:pb-0" >
84+ < div className = "@container/main flex flex-1 flex-col gap-2" >
85+ { children }
86+ </ div >
13787 </ div >
13888 </ div >
89+ < BottomNav user = { user } />
90+ { ( user . role === 'Admin' || user . role === 'Super Admin' ) && (
91+ < AssistantBubble userId = { user . email } />
92+ ) }
13993 </ div >
140- < BottomNav user = { user } />
141- { ( user . role === 'Admin' || user . role === 'Super Admin' ) && (
142- < AssistantBubble userId = { user . email } />
143- ) }
144- </ div >
94+ </ UserAccessProvider >
14595 ) ;
14696}
0 commit comments