import api from './api'; export interface User { id: string; firstName: string; lastName: string; email: string; mobile: string | null; role: string; walletBalance: number; charityDonationTotal: number; hasPassword?: boolean; password?: string; currentPassword?: string; createdAt: string; updatedAt: string; pets?: unknown[]; orders?: unknown[]; } export interface AuthResponse { success: boolean; data: { user: User; accessToken: string; refreshToken?: string; }; } interface ApiErr { response?: { status?: number; data?: { message?: string | string[]; }; }; } export class AuthService { private static instance: AuthService; private constructor() {} public static getInstance(): AuthService { if (!AuthService.instance) { AuthService.instance = new AuthService(); } return AuthService.instance; } /** * Send SMS verification code (OTP) */ public async sendOtp(phoneNumber: string): Promise<{ success: boolean; message: string }> { try { const response = await api.post('/auth/send-otp', { phoneNumber }); return response.data; } catch (error) { const err = error as ApiErr; const message = err.response?.data?.message || 'خطا در ارسال کد تایید'; throw new Error(Array.isArray(message) ? message[0] : message); } } /** * Verify SMS verification code and login/register */ public async verifyOtp(phoneNumber: string, code: string): Promise { try { const response = await api.post('/auth/verify-otp', { phoneNumber, code }); const { data } = response.data; if (data?.accessToken) { localStorage.setItem('accessToken', data.accessToken); } if (data?.refreshToken) { localStorage.setItem('refreshToken', data.refreshToken); } return response.data; } catch (error) { const err = error as ApiErr; const message = err.response?.data?.message || 'کد تایید نامعتبر است'; throw new Error(Array.isArray(message) ? message[0] : message); } } /** * Register with email/mobile and password */ public async register(data: Record): Promise { try { const response = await api.post('/auth/register', data); const { data: resData } = response.data; if (resData?.accessToken) { localStorage.setItem('accessToken', resData.accessToken); } if (resData?.refreshToken) { localStorage.setItem('refreshToken', resData.refreshToken); } return response.data; } catch (error) { const err = error as ApiErr; const message = err.response?.data?.message || 'خطا در ثبت‌نام'; throw new Error(Array.isArray(message) ? message[0] : message); } } /** * Login with mobile and password */ public async login(mobile: string, password: string): Promise { try { const response = await api.post('/auth/login', { mobile, password }); const { data } = response.data; if (data?.accessToken) { localStorage.setItem('accessToken', data.accessToken); } if (data?.refreshToken) { localStorage.setItem('refreshToken', data.refreshToken); } return response.data; } catch (error) { const err = error as ApiErr; const message = err.response?.data?.message || 'نام کاربری یا رمز عبور اشتباه است'; throw new Error(Array.isArray(message) ? message[0] : message); } } /** * Refresh auth tokens using the stored refresh token */ public async refreshAuthToken(): Promise { try { const refreshToken = typeof window !== 'undefined' ? localStorage.getItem('refreshToken') : null; if (!refreshToken) return null; const response = await api.post('/auth/refresh-token', { refreshToken }, { hideErrorToast: true } as unknown as import('axios').AxiosRequestConfig); const { data } = response.data; if (data?.accessToken) { localStorage.setItem('accessToken', data.accessToken); } if (data?.refreshToken) { localStorage.setItem('refreshToken', data.refreshToken); } return data?.accessToken || null; } catch { this.logout(); return null; } } /** * Get current user profile */ public async getProfile(): Promise { try { const response = await api.get('/users/profile', { hideErrorToast: true } as unknown as import('axios').AxiosRequestConfig); return response.data; } catch (error) { const err = error as ApiErr; if (err.response?.status === 401 || err.response?.status === 403) { return null; } const message = err.response?.data?.message || 'خطا در دریافت اطلاعات کاربری'; throw new Error(Array.isArray(message) ? message[0] : message); } } /** * Update current user profile */ public async updateProfile(profileData: Partial): Promise { try { const response = await api.patch('/users/profile', profileData); return response.data; } catch (error) { const err = error as ApiErr; const message = err.response?.data?.message || 'خطا در ویرایش اطلاعات کاربری'; throw new Error(Array.isArray(message) ? message[0] : message); } } /** * Logout user and clear tokens */ public logout(): void { if (typeof window !== 'undefined') { try { const token = localStorage.getItem('accessToken'); if (token) { api.post('/auth/logout').catch(() => {}); } } catch {} localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); } } } export const authService = AuthService.getInstance();