import { authFetch, buildApiError, buildApiUrl } from './client'; const normalizeDigits = (value: string) => value .replace(/[۰-۹]/g, (digit) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(digit))) .replace(/[٠-٩]/g, (digit) => String("٠١٢٣٤٥٦٧٨٩".indexOf(digit))) // --- Auth Endpoints --- export const loginWithPassword = async (mobile: string, password: string) => { const normalizedMobile = normalizeDigits(mobile) const response = await authFetch('/api/users/login/', { method: 'POST', body: JSON.stringify({ mobile: normalizedMobile, password }) }); if (!response.ok) throw await buildApiError(response); return response.json(); }; export interface SendOtpResponse { detail: string expires_in_seconds: number expires_at?: string | null } export const sendOtp = async (mobile: string, mode: string): Promise => { const normalizedMobile = normalizeDigits(mobile) const response = await authFetch('/api/users/otp/send/', { method: 'POST', body: JSON.stringify({ mobile: normalizedMobile, mode }) }); if (!response.ok) throw await buildApiError(response); return response.json(); }; export const loginWithOtp = async (mobile: string, otp: string) => { const normalizedMobile = normalizeDigits(mobile) const normalizedOtp = normalizeDigits(otp) const response = await authFetch('/api/users/otp/login/', { method: 'POST', body: JSON.stringify({ mobile: normalizedMobile, code: normalizedOtp }) }); if (!response.ok) throw await buildApiError(response); return response.json(); }; export const registerWithOtp = async ( mobile: string, code: string, password: string, re_password: string, first_name = "", last_name = "", ) => { const normalizedMobile = normalizeDigits(mobile) const normalizedCode = normalizeDigits(code) const response = await authFetch("/api/users/register/", { method: "POST", body: JSON.stringify({ mobile: normalizedMobile, code: normalizedCode, password, re_password, first_name, last_name, }), }) if (!response.ok) throw await buildApiError(response) return response.json() } export const resetPasswordWithOtp = async ( mobile: string, code: string, password: string, re_password: string, ) => { const normalizedMobile = normalizeDigits(mobile) const normalizedCode = normalizeDigits(code) const response = await authFetch("/api/users/password/reset/", { method: "POST", body: JSON.stringify({ mobile: normalizedMobile, code: normalizedCode, password, re_password, }), }) if (!response.ok) throw await buildApiError(response) return response.json() } export const changePassword = async ( old_password: string, new_password: string, re_password: string, ) => { const response = await authFetch("/api/users/password/change/", { method: "PATCH", body: JSON.stringify({ old_password, new_password, re_password }), }) if (!response.ok) throw await buildApiError(response) return response.json() } export const startGoogleLogin = () => { window.location.assign(buildApiUrl("/api/users/oauth/google/start/")); }; export type GoogleOAuthFlowResponse = | { status: "authenticated"; access: string; refresh: string; } | { status: "collect_mobile"; email: string; first_name: string; last_name: string; avatar_url: string; resolution: "new_account" | "existing_email_claim"; mobile_hint?: string | null; } | { status: "claim_required"; mobile: string; detail?: string; email: string; resolution: "new_account" | "existing_email_claim" | "existing_mobile_claim"; mobile_hint?: string | null; }; export const getGoogleOAuthFlow = async (flow: string): Promise => { const response = await authFetch(`/api/users/oauth/google/flow/?flow=${encodeURIComponent(flow)}`, { method: "GET", }); if (!response.ok) throw await buildApiError(response); return response.json(); }; export const completeGoogleOAuthSignup = async ( flow: string, mobile: string, ): Promise => { const normalizedMobile = normalizeDigits(mobile) const response = await authFetch("/api/users/oauth/google/complete/", { method: "POST", body: JSON.stringify({ flow, mobile: normalizedMobile }), }); if (!response.ok) throw await buildApiError(response); return response.json(); }; export const sendGoogleOAuthClaimOtp = async (flow: string) => { const response = await authFetch("/api/users/oauth/google/claim/send-otp/", { method: "POST", body: JSON.stringify({ flow }), }); if (!response.ok) throw await buildApiError(response); return response.json(); }; export const verifyGoogleOAuthClaim = async ( flow: string, code: string, ): Promise => { const normalizedCode = normalizeDigits(code) const response = await authFetch("/api/users/oauth/google/claim/verify/", { method: "POST", body: JSON.stringify({ flow, code: normalizedCode }), }); if (!response.ok) throw await buildApiError(response); return response.json(); }; export const logoutUser = async (refreshToken: string) => { const response = await authFetch('/api/users/logout/', { method: 'POST', body: JSON.stringify({ refresh: refreshToken }) }); if (!response.ok) throw new Error("Logout failed"); return response.json(); }; // --- Profile Endpoints --- export const getUserProfile = async () => { const response = await authFetch('/api/users/me/', { method: 'GET' }); if (!response.ok) throw new Error('Failed to fetch profile'); return response.json(); }; export const updateUserProfile = async (data: Record) => { const response = await authFetch('/api/users/me/', { method: 'PATCH', body: JSON.stringify(data) }); if (!response.ok) throw new Error('Failed to update profile'); return response.json(); }; export const updateProfilePicture = async (file: File) => { const formData = new FormData(); formData.append('profile_picture', file); const response = await authFetch('/api/users/profile/picture/', { method: 'POST', body: formData }); if (!response.ok) throw new Error('Failed to update profile picture'); return response.json(); }; export const removeProfilePicture = async () => { const response = await authFetch(`/api/users/profile/picture/`, { method: 'DELETE', }); if (!response.ok) throw new Error('Failed to remove profile picture'); return response.json(); }; export interface SearchedUser { id: number | string; first_name: string; last_name: string; mobile: string; profile_picture: string | null; } export const searchUserByExactMobile = async (mobile: string): Promise => { try { const response = await authFetch(`/api/users/search/?mobile=${encodeURIComponent(normalizeDigits(mobile))}`); if (!response.ok) return null; // Returns null on 404 or other errors return await response.json(); } catch (error) { return null; } };