78 lines
1.9 KiB
TypeScript
78 lines
1.9 KiB
TypeScript
"use client"
|
|
|
|
import { createContext, useContext, useState, useEffect, ReactNode, useCallback } from "react"
|
|
import { useRouter } from "next/navigation"
|
|
import type { User } from "@/types"
|
|
|
|
interface UserContextValue {
|
|
user: User | null
|
|
loading: boolean
|
|
error: string | null
|
|
logout: () => Promise<void>
|
|
updateAvatar: (url: string) => void
|
|
}
|
|
|
|
const UserContext = createContext<UserContextValue | null>(null)
|
|
|
|
export function UserProvider({ children }: { children: ReactNode }) {
|
|
const router = useRouter()
|
|
const [user, setUser] = useState<User | null>(null)
|
|
const [loading, setLoading] = useState(true)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
const fetchUser = useCallback(async () => {
|
|
try {
|
|
const res = await fetch("/api/auth/me")
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
const u = data.user
|
|
setUser({
|
|
id: u.id,
|
|
name: `${u.firstName} ${u.lastName}`,
|
|
email: u.email,
|
|
role: u.role,
|
|
active: true,
|
|
avatar: u.avatar,
|
|
createdAt: new Date().toISOString(),
|
|
})
|
|
} else {
|
|
setUser(null)
|
|
}
|
|
} catch {
|
|
setUser(null)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
fetchUser()
|
|
}, [fetchUser])
|
|
|
|
const logout = useCallback(async () => {
|
|
try {
|
|
await fetch("/api/auth/logout", { method: "POST" })
|
|
} catch {
|
|
// Proceed with client-side logout even if API fails
|
|
}
|
|
setUser(null)
|
|
router.push("/login")
|
|
}, [router])
|
|
|
|
const updateAvatar = useCallback((url: string) => {
|
|
setUser((prev) => (prev ? { ...prev, avatar: url } : prev))
|
|
}, [])
|
|
|
|
return (
|
|
<UserContext.Provider value={{ user, loading, error, logout, updateAvatar }}>
|
|
{children}
|
|
</UserContext.Provider>
|
|
)
|
|
}
|
|
|
|
export function useUser() {
|
|
const ctx = useContext(UserContext)
|
|
if (!ctx) throw new Error("useUser must be used within UserProvider")
|
|
return ctx
|
|
}
|