import { useSession, signIn, signOut } from 'next-auth/react' import { useCallback, useMemo } from 'react' import { AuthUser, UserRole } from './types' import { hasPermission, hasRole, hasAnyPermission, hasAllPermissions } from './permissions' interface UseAuthReturn { // User state user: AuthUser | null isAuthenticated: boolean isLoading: boolean // Auth actions login: (provider?: string, options?: { callbackUrl?: string }) => Promise logout: (options?: { callbackUrl?: string }) => Promise loginWithCredentials: (email: string, password: string, callbackUrl?: string) => Promise // Permission checks can: (permission: string) => boolean canAny: (permissions: string[]) => boolean canAll: (permissions: string[]) => boolean is: (role: UserRole) => boolean isAtLeast: (role: UserRole) => boolean // Session management refreshSession: () => Promise } export function useAuth(): UseAuthReturn { const { data: session, status, update } = useSession() const isLoading = status === 'loading' const isAuthenticated = status === 'authenticated' const user: AuthUser | null = useMemo(() => { if (!session?.user) return null return { id: session.user.id, email: session.user.email!, name: session.user.name, image: session.user.image, role: session.user.role || UserRole.USER, emailVerified: session.user.emailVerified, } }, [session]) const login = useCallback( async (provider?: string, options?: { callbackUrl?: string }) => { await signIn(provider, { callbackUrl: options?.callbackUrl || '/' }) }, [] ) const logout = useCallback(async (options?: { callbackUrl?: string }) => { await signOut({ callbackUrl: options?.callbackUrl || '/' }) }, []) const loginWithCredentials = useCallback( async (email: string, password: string, callbackUrl?: string) => { const result = await signIn('credentials', { email, password, redirect: false, }) if (result?.error) { throw new Error(result.error) } if (callbackUrl) { window.location.href = callbackUrl } }, [] ) const can = useCallback( (permission: string): boolean => { if (!user) return false return hasPermission(user.role, permission) }, [user] ) const canAny = useCallback( (permissions: string[]): boolean => { if (!user) return false return hasAnyPermission(user.role, permissions) }, [user] ) const canAll = useCallback( (permissions: string[]): boolean => { if (!user) return false return hasAllPermissions(user.role, permissions) }, [user] ) const is = useCallback( (role: UserRole): boolean => { if (!user) return false return user.role === role }, [user] ) const isAtLeast = useCallback( (role: UserRole): boolean => { if (!user) return false return hasRole(user.role, role) }, [user] ) const refreshSession = useCallback(async () => { await update() }, [update]) return { user, isAuthenticated, isLoading, login, logout, loginWithCredentials, can, canAny, canAll, is, isAtLeast, refreshSession, } } // Hook for checking a specific permission export function usePermission(permission: string): boolean { const { can } = useAuth() return can(permission) } // Hook for checking a specific role export function useRole(role: UserRole): boolean { const { isAtLeast } = useAuth() return isAtLeast(role) } // Hook for requiring authentication (with redirect) export function useRequireAuth(options?: { redirectTo?: string }) { const { isAuthenticated, isLoading } = useAuth() if (!isLoading && !isAuthenticated && typeof window !== 'undefined') { const redirectTo = options?.redirectTo || '/auth/signin' window.location.href = `${redirectTo}?callbackUrl=${encodeURIComponent(window.location.pathname)}` } return { isAuthenticated, isLoading } }