'use client'; import { create } from 'zustand'; import api from '@/lib/api'; import { clearImpersonation } from '@/lib/impersonation'; import type { User, AuthResponse } from '@/types'; export interface RegisterData { phone: string; password: string; firstName: string; lastName: string; email?: string; } /** Either the user is fully authenticated, or a phone OTP is required next. */ export type AuthResult = | { status: 'authenticated' } | { status: 'verify'; phone: string }; interface VerificationRequired { requiresVerification: true; phone: string; } interface AuthState { user: User | null; isLoading: boolean; isAuthenticated: boolean; /** Password login by mobile. May require OTP verification. */ login: (phone: string, password: string) => Promise; /** Register by mobile — always returns a verify step. */ register: (data: RegisterData) => Promise<{ phone: string }>; /** Send a one-time login code to a mobile number. */ requestOtp: (phone: string) => Promise; /** Verify a one-time code (completes registration or OTP login). */ verifyOtp: (phone: string, code: string) => Promise; logout: () => void; loadUser: () => Promise; setUser: (user: User) => void; } function persistAuth(data: AuthResponse) { localStorage.setItem('accessToken', data.accessToken); localStorage.setItem('refreshToken', data.refreshToken); } export const useAuthStore = create((set) => ({ user: null, isLoading: true, isAuthenticated: false, login: async (phone, password) => { const { data } = await api.post( '/auth/login', { phone, password }, ); if ('requiresVerification' in data) { return { status: 'verify', phone: data.phone }; } persistAuth(data); set({ user: data.user, isAuthenticated: true }); return { status: 'authenticated' }; }, register: async (registerData) => { const { data } = await api.post('/auth/register', registerData); return { phone: data.phone }; }, requestOtp: async (phone) => { await api.post('/auth/otp/request', { phone }); }, verifyOtp: async (phone, code) => { const { data } = await api.post('/auth/otp/verify', { phone, code }); persistAuth(data); set({ user: data.user, isAuthenticated: true }); }, logout: () => { localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); clearImpersonation(); set({ user: null, isAuthenticated: false }); }, loadUser: async () => { try { const token = localStorage.getItem('accessToken'); if (!token) { set({ isLoading: false }); return; } const { data } = await api.get('/users/me'); set({ user: data, isAuthenticated: true, isLoading: false }); } catch { set({ user: null, isAuthenticated: false, isLoading: false }); } }, setUser: (user) => set({ user }), }));