All files / src/contexts AuthContext.tsx

70.37% Statements 19/27
75% Branches 3/4
77.77% Functions 7/9
70.37% Lines 19/27

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                          4x       7x 7x     7x                 7x 7x 7x     7x 3x     2x 2x         3x     7x                     7x 1x 1x       1x 1x     7x                              
import { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react'
import { api } from '../api/client'
import type { AuthProfile, PasskeyUser } from '../api/types'
 
interface AuthContextType {
  user: PasskeyUser | null
  profile: AuthProfile | null
  isAdmin: boolean
  isLoading: boolean
  logout: () => Promise<void>
  refreshSession: () => Promise<void>
}
 
const AuthContext = createContext<AuthContextType | null>(null)
 
// eslint-disable-next-line react-refresh/only-export-components -- Hook is tightly coupled to provider
export function useAuth() {
  const context = useContext(AuthContext)
  Iif (!context) {
    throw new Error('useAuth must be used within an AuthProvider')
  }
  return context
}
 
// eslint-disable-next-line react-refresh/only-export-components -- Safe variant for mode-conditional usage
export function useOptionalAuth() {
  return useContext(AuthContext)
}
 
export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<PasskeyUser | null>(null)
  const [profile, setProfile] = useState<AuthProfile | null>(null)
  const [isLoading, setIsLoading] = useState(true)
 
  // Restore session on mount
  useEffect(() => {
    api.auth
      .me()
      .then((data) => {
        setUser(data.user)
        setProfile(data.profile)
      })
      .catch(() => {
        // Not logged in
      })
      .finally(() => setIsLoading(false))
  }, [])
 
  const refreshSession = useCallback(async () => {
    try {
      const data = await api.auth.me()
      setUser(data.user)
      setProfile(data.profile)
    } catch {
      setUser(null)
      setProfile(null)
    }
  }, [])
 
  const logout = useCallback(async () => {
    try {
      await api.auth.logout()
    } catch {
      // Ignore errors on logout
    }
    setUser(null)
    setProfile(null)
  }, [])
 
  return (
    <AuthContext.Provider
      value={{
        user,
        profile,
        isAdmin: user?.is_admin ?? false,
        isLoading,
        logout,
        refreshSession,
      }}
    >
      {children}
    </AuthContext.Provider>
  )
}
 
← Back to Dashboard