diff --git a/src/contexts/AuthContext.tsx b/src/contexts/AuthContext.tsx index 3833121..4dd931c 100644 --- a/src/contexts/AuthContext.tsx +++ b/src/contexts/AuthContext.tsx @@ -39,20 +39,45 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { .then(r => r.ok ? r.json() : null) .then((data: { access_token?: string } | null) => { if (data?.access_token) { - const s: AuthSession = { ...session, token: data.access_token } - setSession(s) - localStorage.setItem('hotelsync-session', JSON.stringify(s)) + const tok = data.access_token + setSession(cur => { + if (!cur) return null + const s: AuthSession = { ...cur, token: tok } + localStorage.setItem('hotelsync-session', JSON.stringify(s)) + return s + }) } else { - setSession(null) - localStorage.removeItem('hotelsync-session') + // Guard: if login() set a fresh token while refresh was in-flight — keep it + setSession(cur => { + if (cur?.token) return cur + localStorage.removeItem('hotelsync-session') + return null + }) } }) .catch(() => { - setSession(null) - localStorage.removeItem('hotelsync-session') + // Guard: same race-condition protection + setSession(cur => { + if (cur?.token) return cur + localStorage.removeItem('hotelsync-session') + return null + }) }) }, []) // eslint-disable-line react-hooks/exhaustive-deps + // Keep React state in sync when api.ts refreshes the token (e.g. after 401 auto-refresh) + useEffect(() => { + const handler = (e: Event) => { + const { token } = (e as CustomEvent<{ token: string }>).detail + setSession(cur => { + if (!cur) return cur + return { ...cur, token } + }) + } + window.addEventListener('hotelsync:token-updated', handler) + return () => window.removeEventListener('hotelsync:token-updated', handler) + }, []) + const login = async (email: string, password: string): Promise => { try { const { access_token, user } = await api.auth.login(email, password) diff --git a/src/lib/api.ts b/src/lib/api.ts index d715bbb..44cfce0 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -30,6 +30,8 @@ function saveToken(token: string) { const parsed = JSON.parse(s) as Record parsed.token = token localStorage.setItem('hotelsync-session', JSON.stringify(parsed)) + // Notify AuthContext so React state stays in sync (WS reconnects with fresh token) + window.dispatchEvent(new CustomEvent('hotelsync:token-updated', { detail: { token } })) } catch { // ignore }