@@ -121,6 +121,9 @@ export default function Authorities({ onViewReports }: { onViewReports?: () => v
121121 } ) ;
122122
123123 setAuthorities ( mapped as AuthAccount [ ] ) ;
124+
125+ // Update persistent local cache
126+ localStorage . setItem ( "admin:authorities:cache" , JSON . stringify ( mapped ) ) ;
124127 } catch ( err ) {
125128 console . error ( "Dashboard fetch error:" , err ) ;
126129 toast . error ( "Failed to load authorities." ) ;
@@ -130,6 +133,17 @@ export default function Authorities({ onViewReports }: { onViewReports?: () => v
130133 } ;
131134
132135 useEffect ( ( ) => {
136+ // Initial hydration from local storage
137+ const cached = localStorage . getItem ( "admin:authorities:cache" ) ;
138+ if ( cached ) {
139+ try {
140+ setAuthorities ( JSON . parse ( cached ) ) ;
141+ setLoading ( false ) ;
142+ } catch ( e ) {
143+ console . error ( "Failed to parse authorities cache" , e ) ;
144+ }
145+ }
146+
133147 void fetchAuthorities ( ) ;
134148
135149 const channel = supabase . channel ( 'admin-auth-rt' )
@@ -220,24 +234,55 @@ export default function Authorities({ onViewReports }: { onViewReports?: () => v
220234 const handleAssignDept = async ( ) => {
221235 if ( ! assigningAuth || ! selectedNewDept ) return ;
222236
223- const updatedCats = assigningAuth . categories . includes ( selectedNewDept )
224- ? assigningAuth . categories
225- : [ ...assigningAuth . categories , selectedNewDept ] ;
226-
227- // Attempt pushing sync to profile metadata
228- const { error } = await ( supabase as any ) . from ( 'profiles' ) . update ( {
229- categories : updatedCats ,
230- department : selectedNewDept
231- } ) . eq ( "id" , assigningAuth . id ) ;
232-
233- if ( error ) {
234- toast . error ( "Failed to assign department in database. Refreshing..." ) ;
235- } else {
236- toast . success ( `Assigned ${ selectedNewDept } to ${ assigningAuth . name } ` ) ;
237- }
238-
239- void fetchAuthorities ( ) ;
237+ const workerId = assigningAuth . id ;
238+ const previousAuthorities = [ ...authorities ] ;
239+
240+ // 1. Optimistic UI update
241+ setAuthorities ( prev => prev . map ( a =>
242+ a . id === workerId ? { ...a , categories : [ selectedNewDept ] } : a
243+ ) ) ;
244+ const currentAssigningName = assigningAuth . name ;
240245 handleCloseAssignModal ( ) ;
246+
247+ try {
248+ const { data : { session } } = await supabase . auth . getSession ( ) ;
249+ if ( ! session ) {
250+ toast . error ( "Session expired." ) ;
251+ setAuthorities ( previousAuthorities ) ;
252+ return ;
253+ }
254+
255+ const apiUrl = process . env . NEXT_PUBLIC_API_URL || "https://api.vihaan.perkkk.dev" ;
256+ const response = await fetch ( `${ apiUrl } /api/admin/authorities` , {
257+ method : "PATCH" ,
258+ headers : {
259+ "Content-Type" : "application/json" ,
260+ "Authorization" : `Bearer ${ session . access_token } `
261+ } ,
262+ body : JSON . stringify ( {
263+ authority_id : workerId ,
264+ department : selectedNewDept
265+ } )
266+ } ) ;
267+
268+ if ( ! response . ok ) {
269+ throw new Error ( "Failed to update department in database" ) ;
270+ }
271+
272+ toast . success ( `Assigned ${ selectedNewDept } to ${ currentAssigningName } ` ) ;
273+
274+ // Update persistent cache
275+ localStorage . setItem ( "admin:authorities:cache" , JSON . stringify (
276+ authorities . map ( a => a . id === workerId ? { ...a , categories : [ selectedNewDept ] } : a )
277+ ) ) ;
278+
279+ // Refresh in background
280+ void fetchAuthorities ( ) ;
281+ } catch ( e : any ) {
282+ console . error ( "Assignment failed:" , e ) ;
283+ toast . error ( e . message || "Failed to assign department" ) ;
284+ setAuthorities ( previousAuthorities ) ;
285+ }
241286 } ;
242287
243288 useEffect ( ( ) => {
@@ -336,12 +381,18 @@ export default function Authorities({ onViewReports }: { onViewReports?: () => v
336381
337382
338383 return (
339- < div className = { styles . dashboardContainer } ref = { containerRef } >
340- < div className = { styles . header } >
341- < h1 className = { styles . title } style = { { display :'flex' , alignItems :'center' , gap : 8 } } >
342- < ShieldCheck size = { 28 } /> Authorities
343- </ h1 >
344- < p className = { styles . subtitle } > Manage registered authority accounts.</ p >
384+ < div className = { styles . dashboardContainer } ref = { containerRef } style = { { paddingRight : 40 } } >
385+ < div className = { styles . header } style = { { display : 'flex' , justifyContent : 'space-between' , alignItems : 'flex-start' } } >
386+ < div >
387+ < h1 className = { styles . title } style = { { display :'flex' , alignItems :'center' , gap : 8 } } >
388+ < ShieldCheck size = { 28 } /> Authorities
389+ </ h1 >
390+ < p className = { styles . subtitle } > Supervise and monitor authority level accounts.</ p >
391+ </ div >
392+ < div style = { { display : 'flex' , gap : '16px' , alignItems : 'center' , marginTop : 8 } } >
393+ { ! loading && < span className = { `${ styles . cPill } ${ styles . resolved } ` } style = { { padding : '6px 12px' , fontSize : 11 , fontWeight : 700 } } > Live Sync Active</ span > }
394+ { loading && < span className = { `${ styles . cPill } ${ styles . pending } ` } style = { { padding : '6px 12px' , fontSize : 11 , fontWeight : 700 } } > Updating Cache...</ span > }
395+ </ div >
345396 </ div >
346397
347398 { /* 4-Item KPI Metrics Matrix */ }
0 commit comments