// hooks/useAuth.ts import { AUTH_INFO_KEY, AUTH_REFRESH_FAILED_EVENT, } from '@/constants/system' import { useRouter } from '@/i18n/navigation' import { BaseAPIResponse } from '@/models/api/common' import { useGetUrlLoginMutation } from '@/share/layout/end-user/header/hook' import { useMutation, useQuery } from '@tanstack/react-query' import { AxiosError } from 'axios' import { useCallback } from 'react' import { AuthInfoBase, AuthInfoBaseResponse, AuthInfoFullSchema, LogoutRequest, } from './auth.schema' import authApi from './auth.service' export const authKeys = { all: ['auth'] as const, verifyToken: (token?: string) => [...authKeys.all, token, 'verifyToken'] as const, parseToken: (token: string) => [...authKeys.all, token, 'parseToken'] as const, } export function useVerifyToken(token: string) { return useQuery({ queryKey: authKeys.verifyToken(token), queryFn: () => authApi.verifyToken(token), retry: false, }) } export function useParseToken(token: string) { return useQuery({ queryKey: authKeys.parseToken(token), queryFn: () => authApi.parseToken(token), retry: false, }) } const clearAuthAndLogout = () => { localStorage.removeItem(AUTH_INFO_KEY) } export const useRefresh = ( onSuccessCallback: (data: AuthInfoBase) => void, onErrorCallback: () => void ) => { return useMutation< AuthInfoBaseResponse, AxiosError >({ mutationFn: () => authApi.refresh(), onSuccess: (data) => onSuccessCallback(data.data), onError: () => { clearAuthAndLogout() onErrorCallback() }, }) } export const useLogout = (onSuccess: () => void) => { const mutate = useGetUrlLoginMutation() return useMutation({ mutationFn: (body) => authApi.logout(body), onSuccess: () => { onSuccess() mutate.mutate() }, }) } export const useTokenRefresh = () => { const router = useRouter() const refreshToken = useCallback(async (): Promise => { const savedAuthInfoLocal = localStorage.getItem(AUTH_INFO_KEY) if (!savedAuthInfoLocal) { throw new Error('Cannot find auth information to refresh') } const authInfo = JSON.parse(savedAuthInfoLocal) try { const newAuthInfo = await authApi.refresh() const newAuthInfoFull = AuthInfoFullSchema.parse({ ...newAuthInfo.data, user_info: authInfo.user_info, }) localStorage.setItem(AUTH_INFO_KEY, JSON.stringify(newAuthInfoFull)) return newAuthInfo } catch (e) { if ( e instanceof AxiosError && e.response?.status === 401 && typeof window !== 'undefined' ) { window.dispatchEvent(new CustomEvent(AUTH_REFRESH_FAILED_EVENT)) } throw e } }, []) const refreshTokenWithRetry = useCallback( async (onSuccess?: () => void) => { try { await refreshToken() onSuccess?.() } catch (refreshError) { clearAuthAndLogout() throw refreshError } }, // eslint-disable-next-line react-hooks/exhaustive-deps [router] ) return { refreshToken, refreshTokenWithRetry, clearAuthAndLogout, } }