import React, { createContext, useContext, useState, useEffect, useCallback } from 'react' import { trpc } from './trpc-client' import { useNavigate } from '@tanstack/react-router' import type { User as SharedUser, AuthStateCore } from '@packages/shared' // Auth user — serialized view of the shared User (optional name, no createdAt) type User = Pick & Partial> & { mobile: string | null profileImage?: string | null } interface AuthState extends AuthStateCore { user: User | null userDetails: any | null } interface AuthContextType extends AuthState { login: (token: string, user: User) => void loginWithToken: (token: string, user: User) => void register: (token: string, user: User) => void logout: () => void updateUser: (user: User) => void updateUserDetails: (details: any) => void } const AuthContext = createContext(undefined) export function AuthProvider({ children }: { children: React.ReactNode }) { const [state, setState] = useState({ user: null, userDetails: null, isAuthenticated: false, isLoading: true, token: null, }) const navigate = useNavigate() // On mount, check for stored token useEffect(() => { const storedToken = localStorage.getItem('auth_token') const storedUserId = localStorage.getItem('user_id') if (storedToken && storedUserId) { setState((prev) => ({ ...prev, token: storedToken, isAuthenticated: true, })) } else { setState((prev) => ({ ...prev, isLoading: false })) } }, []) // Fetch user data when token is available const { data: selfData } = trpc.user.user.getSelfData.useQuery(undefined, { enabled: !!state.token && state.isAuthenticated, retry: 1, }) useEffect(() => { if (selfData?.data?.user) { setState((prev) => ({ ...prev, user: selfData.data.user, userDetails: selfData.data.user, isLoading: false, })) } else if (selfData === undefined && state.token) { // Token might be invalid } }, [selfData, state.token]) const login = useCallback((token: string, user: User) => { localStorage.setItem('auth_token', token) localStorage.setItem('user_id', String(user.id)) setState({ user, userDetails: user, isAuthenticated: true, isLoading: false, token, }) }, []) const loginWithToken = useCallback((token: string, user: User) => { login(token, user) }, [login]) const register = useCallback((token: string, user: User) => { login(token, user) }, [login]) const logout = useCallback(() => { localStorage.removeItem('auth_token') localStorage.removeItem('user_id') setState({ user: null, userDetails: null, isAuthenticated: false, isLoading: false, token: null, }) navigate({ to: '/login' }) }, [navigate]) const updateUser = useCallback((user: User) => { setState((prev) => ({ ...prev, user })) }, []) const updateUserDetails = useCallback((details: any) => { setState((prev) => ({ ...prev, userDetails: details })) }, []) return ( {children} ) } export function useAuth() { const context = useContext(AuthContext) if (!context) { throw new Error('useAuth must be used within AuthProvider') } return context }