"use client"; import Cookies from "js-cookie"; import React, { createContext, Dispatch, ReactNode, SetStateAction, useCallback, useContext, useEffect, useMemo, useState, } from "react"; import { useRouter } from "next/navigation"; import { ILoginResponse, IUser, UserSchema } from "../lib/api/types"; import { COOKIE_KEYS } from "../lib/shared/cookies"; interface UserContextType { user: IUser | null; accessToken: string | null; isAuthenticated: boolean; isLoading: boolean; setAuthState: (data: ILoginResponse) => void; logout: () => void; setUser: Dispatch>; } const UserContext = createContext(undefined); interface UserProviderProps { children: ReactNode; } export const UserProvider: React.FC = ({ children }) => { const [user, setUser] = useState(null); const [accessToken, setAccessToken] = useState(null); const [isLoading, setIsLoading] = useState(true); const router = useRouter(); const logout = useCallback(() => { setUser(null); setAccessToken(null); Cookies.remove(COOKIE_KEYS.access_token); Cookies.remove(COOKIE_KEYS.refresh_token); Cookies.remove(COOKIE_KEYS.user); window.location.href = "/auth/sign-in"; }, [router]); useEffect(() => { try { const tokenFromCookie = Cookies.get(COOKIE_KEYS.access_token); const userJson = Cookies.get(COOKIE_KEYS.user); if (tokenFromCookie && userJson) { const userFromCookie = JSON.parse(userJson); const validation = UserSchema.safeParse(userFromCookie); if (validation.success) { setUser(validation.data); setAccessToken(tokenFromCookie); } else { console.warn("Invalid user data in cookie:", validation.error); logout(); } } } catch (e) { console.error("Failed to parse user data from cookies", e); logout(); } finally { setIsLoading(false); } }, [logout]); const setAuthState = useCallback((data: ILoginResponse) => { setAccessToken(data.access_token); setUser(data.user); Cookies.set(COOKIE_KEYS.access_token, data.access_token); Cookies.set(COOKIE_KEYS.refresh_token, data.refresh_token); Cookies.set(COOKIE_KEYS.user, JSON.stringify(data.user)); }, []); const value = useMemo( () => ({ user, accessToken, isAuthenticated: !!accessToken, isLoading, setAuthState, logout, setUser, }), [user, accessToken, isLoading, setAuthState, logout, setUser], ); return {children}; }; export const useUser = (): UserContextType => { const context = useContext(UserContext); if (context === undefined) { throw new Error("useUser must be used within a UserProvider"); } return context; };