import { api } from "@/services/api"; import type { LoginPayload, LoginResponse, OtpResponse, SignupPayload, SignupResponse, } from "@/types/auth"; import type { Result } from "@/utils/result"; import { extractApiError } from "@/utils/result"; import { useQuery, useQueryClient } from "@tanstack/react-query"; function setCookie(name: string, value: string, days: number) { const expires = new Date(); expires.setDate(expires.getDate() + days); document.cookie = `${name}=${value}; path=/; expires=${expires.toUTCString()}; SameSite=Lax`; } function getCookie(name: string): string | undefined { return document.cookie .split("; ") .find((row) => row.startsWith(`${name}=`)) ?.split("=")[1]; } const useAuth = () => { const queryClient = useQueryClient(); const hasToken = !!getCookie("auth-token"); const authQuery = useQuery( api.auth.getMyInfo.queryOptions({ enabled: hasToken, retry: false, refetchOnMount: false, refetchOnReconnect: false, staleTime: 10 * 60 * 1000, refetchOnWindowFocus: false, }), ); const companyQuery = useQuery( api.companies.getInfo.queryOptions({ enabled: !!authQuery.data?.id, retry: false, staleTime: 10 * 60 * 1000, refetchOnWindowFocus: false, }), ); const isPending = authQuery.isPending && hasToken; const isAuthenticated = hasToken && !!authQuery.data && !authQuery.isError; const login = async ( payload: LoginPayload, ): Promise> => { try { const res = await api.auth.login.call(payload); setCookie("auth-token", res.token, 7); setCookie("refresh-token", res.refreshToken, 7); await authQuery.refetch(); return { success: true, data: res }; } catch (err) { return { success: false, error: extractApiError(err) }; } }; const signup = async ( payload: SignupPayload, ): Promise> => { try { const res = await api.auth.createUser.call(payload); setCookie("auth-token", res.token, 7); setCookie("refresh-token", res.refreshToken, 7); await authQuery.refetch(); const otpCode = res.otp?.split(" ")?.[6] ?? ""; localStorage.setItem("otp", otpCode); localStorage.setItem("otp-phone", payload.phoneNumber); localStorage.setItem("otp-email", payload.email); api.auth.sendOTP .call({ phone: payload.phoneNumber, otp: otpCode }) .catch(() => { }); return { success: true, data: res }; } catch (err) { return { success: false, error: extractApiError(err) }; } }; const setPassword = async (data: { newPassword: string; confirmPassword: string; }): Promise> => { try { const userId = authQuery.data?.id ?? ""; const email = localStorage.getItem("otp-email") ?? ""; const verificationCode = localStorage.getItem("otp") ?? ""; await api.auth.setPassword.call({ newPassword: data.newPassword, confirmPassword: data.confirmPassword, userId, email, verificationCode, }); ["userId", "otp", "otp-phone", "otp-email"].forEach((k) => localStorage.removeItem(k), ); await queryClient.invalidateQueries({ queryKey: api.auth.getMyInfo.queryKey(), }); return { success: true, data: undefined }; } catch (err) { return { success: false, error: extractApiError(err) }; } }; const verifyOTP = async (otp: string): Promise> => { try { const phone = localStorage.getItem("otp-phone") ?? ""; const res = await api.auth.verifyOTP.call({ phone, otp }); return { success: true, data: res }; } catch (err) { return { success: false, error: extractApiError(err) }; } }; const sendOTP = async (otp: string): Promise> => { try { const phone = localStorage.getItem("otp-phone") ?? ""; const res = await api.auth.sendOTP.call({ phone, otp }); return { success: true, data: res }; } catch (err) { return { success: false, error: extractApiError(err) }; } }; const generateVerificationCode = async ( type: string, ): Promise> => { try { const email = localStorage.getItem("otp-email") ?? ""; const phoneNumber = localStorage.getItem("otp-phone") ?? ""; const res = await api.auth.generateVerificationCode.call({ email, phoneNumber, type, }); return { success: true, data: res }; } catch (err) { return { success: false, error: extractApiError(err) }; } }; const logout = async () => { try { await api.auth.logout.call(); } catch { // proceed with client-side cleanup even if server call fails } [ "auth-token", "refresh-token", "auth-user", "current-position-id", "selected-position-id", ].forEach((name) => { document.cookie = `${name}=; Max-Age=0; path=/`; }); localStorage.clear(); queryClient.clear(); }; return { isPending, isAuthenticated, user: isAuthenticated ? (authQuery.data ?? null) : null, company: isAuthenticated ? (companyQuery.data ?? null) : null, customer: isAuthenticated ? (companyQuery.data ?? null) : null, login, signup, setPassword, verifyOTP, sendOTP, generateVerificationCode, logout, authQuery, companyQuery, customerQuery: companyQuery, }; }; export default useAuth;