'use client' import { ReactNode, useEffect, useState } from 'react' import { useDjangoCSRClient, Auth } from 'mizan/client/react' import type { RouterAdapter } from '../adapters/router' import type { InitialAuth } from '../hydration' import { AuthContext } from './AuthContext' import { ConfigContext } from './ConfigContext' import { StylesContext } from './StylesContext' import { RouterContext } from './RouterContext' import { AllauthConfig } from '../config' import { AuthClassNames } from '../styles/types' import { createAPI } from '../api' export interface AllauthContextProps { children: ReactNode /** Router adapter for navigation */ router: RouterAdapter /** Optional initial auth state from getInitialAuth() - if not provided, fetches client-side */ hydration?: InitialAuth /** Library configuration (basePath, routes) */ allauthConfig?: Partial /** CSS class names for styling components */ classNames?: AuthClassNames } /** * Core AllauthContext - sets up all contexts for the allauth library. * * IMPORTANT: AllauthContext must be wrapped by DjangoContext, which provides * user data via useUser(). The typical setup is: * * ```tsx * * * {children} * * * ``` * * If hydration is provided (from SSR), uses it immediately. * If not provided, fetches initial auth state client-side using the CSR client. * * For Next.js apps, use NextAllauthContext instead which handles the router automatically. */ export function AllauthContext({ children, router, hydration, allauthConfig, classNames, }: AllauthContextProps) { const client = useDjangoCSRClient(Auth.SESSION) const [initialAuth, setInitialAuth] = useState(hydration ?? null) const [loading, setLoading] = useState(!hydration) useEffect(() => { if (hydration) return // Already have SSR hydration const fetchInitialAuth = async () => { try { const authRequest = async (method: string, path: string, data?: any, headers?: Record) => { const resp = await client.request(method, `/_allauth/browser/v1${path}`, data, headers) if (resp.status >= 500) { throw new Error(`Allauth request failed: ${resp.status} ${resp.statusText}`) } return resp.json() } const api = createAPI((method, path, data?, headers?) => authRequest(method, path, { ...(data as object), client: 'browser' }, headers) ) const [config, auth] = await Promise.all([ api.getConfig(), api.session.getStatus(), ]) setInitialAuth({ config, auth }) } catch (e) { console.error('[AllauthContext] Failed to fetch initial auth:', e) setInitialAuth({ config: { status: 200, data: {} }, auth: { status: 401, data: {} }, }) } finally { setLoading(false) } } fetchInitialAuth() }, [client, hydration]) if (loading || !initialAuth) { return null } return ( {children} ) }