import { URL_CONSTANTS } from "@/constants/URLS"; import type { AuthUser, ChangePasswordPayload, CheckAvailabilityPayload, CheckAvailabilityResponse, ForgotPasswordRequestPayload, ForgotPasswordVerifyPayload, GenerateVerificationCodePayload, LoginPayload, LoginResponse, OtpPayload, OtpResponse, ResetLinkAccount, ResetTicket, ResolveResetLinkPayload, SendContactOtpPayload, SendContactOtpResponse, SetPasswordPayload, SignupPayload, SignupResponse, UpdateAccountNamePayload, UpdateContactPayload, UpdateContactResponse, } from "@/types/auth"; import { client } from "@/utils/api"; import { unwrap } from "@/utils/endpoint"; import { ApiResponse } from "@edr/types"; export const authService = { login: async (body: LoginPayload) => { const res = await client.post( URL_CONSTANTS.AUTH.LOGIN, body, ); return res.data; }, createUser: async (body: SignupPayload) => { const res = await client.post>( URL_CONSTANTS.USERS.SIGN_UP, body, ); return res.data; }, getMyInfo: async () => { const res = await client.get(URL_CONSTANTS.USERS.ME); return res.data; }, generateVerificationCode: async (body: GenerateVerificationCodePayload) => { const res = await client.patch>( URL_CONSTANTS.USERS.GENERATE_VERIFICATION_CODE, body, ); return res.data.data; }, setPassword: async (body: SetPasswordPayload) => { const res = await client.patch>( URL_CONSTANTS.USERS.SET_PASSWORD, body, ); return res.data.data; }, // The three calls below drive the unauthenticated forgot-password flow. // Responses under /api/auth are *flattened* by the API's response // interceptor ({ success, ...payload }), so there is no `.data.data` here. requestPasswordReset: async (body: ForgotPasswordRequestPayload) => { await client.post(URL_CONSTANTS.AUTH.FORGOT_PASSWORD_REQUEST, body); }, verifyPasswordResetOtp: async (body: ForgotPasswordVerifyPayload) => { const res = await client.post( URL_CONSTANTS.AUTH.FORGOT_PASSWORD_VERIFY, body, ); return { userId: res.data.userId, verificationCode: res.data.verificationCode }; }, /** * Validate a staff-issued reset link before showing the password form, and * pick up the ticket it carries. Rejected links (expired, already spent) fail * here rather than after the customer has typed a new password. */ resolveResetLink: async (body: ResolveResetLinkPayload) => { const res = await client.post( URL_CONSTANTS.AUTH.FORGOT_PASSWORD_RESOLVE_LINK, body, ); return res.data; }, /** * Spend the reset ticket. Distinct from `setPassword` above, which the * authenticated post-signup flow drives through `useAuth` — this one carries * its own userId/verificationCode and never touches the session. */ resetPassword: async (body: SetPasswordPayload) => { await client.patch(URL_CONSTANTS.USERS.SET_PASSWORD, body); }, checkAvailability: async (params: CheckAvailabilityPayload) => { const res = await client.get( URL_CONSTANTS.USERS.CHECK_AVAILABILITY, { params }, ); return res.data; }, sendOTP: async (body: OtpPayload) => { const res = await client.post>( URL_CONSTANTS.OTP.SEND, body, ); return res.data.data; }, verifyOTP: async (body: OtpPayload) => { const res = await client.post>( URL_CONSTANTS.OTP.VERIFY, body, ); return res.data.data; }, /** * Change the signed-in user's password via IAM's own route: it verifies the * old password with argon and owns the credential write (deactivating the * previous one), so this app never touches password material. */ changePassword: async (body: ChangePasswordPayload) => { await client.patch(URL_CONSTANTS.AUTH.CHANGE_PASSWORD, body); }, // The three calls below manage the signed-in user's own account record // (`/api/me`), which is what OTPs and SMS notifications are delivered to. // Changing phone/email is OTP-gated server-side: the code goes to the NEW // value, and the write only lands once it is verified. sendContactOtp: async (body: SendContactOtpPayload) => { const res = await client.post>( URL_CONSTANTS.ACCOUNT.CONTACT_OTP, body, ); return unwrap(res.data); }, updateContact: async (body: UpdateContactPayload) => { const res = await client.patch>( URL_CONSTANTS.ACCOUNT.CONTACT, body, ); return unwrap(res.data); }, updateAccountName: async (body: UpdateAccountNamePayload) => { const res = await client.patch>( URL_CONSTANTS.ACCOUNT.NAME, body, ); return unwrap(res.data); }, refreshToken: async () => { const refreshTokenCookie = document.cookie .split("; ") .find((row) => row.startsWith("refresh-token=")) ?.split("=")[1]; const res = await client.post>( URL_CONSTANTS.AUTH.REFRESH_TOKEN, { refreshToken: refreshTokenCookie }, ); return res.data.data; }, logout: async () => { const res = await client.patch>( URL_CONSTANTS.AUTH.LOGOUT, ); return res.data.data; }, };