Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | 4x 4x 4x 4x 4x 4x | import React, {
createContext,
useContext,
useState,
useCallback,
useEffect,
useRef,
} from 'react';
import { router, type Href } from 'expo-router';
import { StoredAuthSession, UserSummary } from '@/models/auth';
import {
clearSession as clearStoredSession,
hydrateSession,
setSession as persistSession,
subscribeToSession,
} from '@/services/sessionManager';
interface AuthContextType {
token: string | null;
refreshToken: string | null;
user: UserSummary | null;
isHydrating?: boolean;
setSession: (
accessToken: string,
refreshToken: string,
user: UserSummary,
) => Promise<void>;
clearAuth: () => Promise<void>;
}
const AuthContext = createContext<AuthContextType | null>(null);
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [token, setToken] = useState<string | null>(null);
const [refreshToken, setRefreshToken] = useState<string | null>(null);
const [user, setUser] = useState<UserSummary | null>(null);
const [isHydrating, setIsHydrating] = useState(true);
const previousSessionRef = useRef<StoredAuthSession | null>(null);
const applySession = useCallback((session: StoredAuthSession | null) => {
setToken(session?.access_token ?? null);
setRefreshToken(session?.refresh_token ?? null);
setUser(session?.user ?? null);
}, []);
useEffect(() => {
let mounted = true;
const unsubscribe = subscribeToSession((session) => {
Iif (!mounted) return;
const previousSession = previousSessionRef.current;
previousSessionRef.current = session;
applySession(session);
Iif (!isHydrating && previousSession && !session) {
router.replace('/' as Href);
}
});
void (async () => {
const session = await hydrateSession();
Iif (!mounted) return;
previousSessionRef.current = session;
applySession(session);
setIsHydrating(false);
})();
return () => {
mounted = false;
unsubscribe();
};
}, [applySession]);
const setSession = useCallback(
async (accessToken: string, refresh: string, userSummary: UserSummary) => {
await persistSession({
access_token: accessToken,
refresh_token: refresh,
user: userSummary,
});
},
[],
);
const clearAuth = useCallback(() => {
return clearStoredSession();
}, []);
return (
<AuthContext.Provider
value={{ token, refreshToken, user, isHydrating, setSession, clearAuth }}
>
{children}
</AuthContext.Provider>
);
}
export function useAuth(): AuthContextType {
const ctx = useContext(AuthContext);
Iif (!ctx) throw new Error('useAuth must be used within AuthProvider');
return ctx;
}
|