import axios from 'axios'; import { LoginRequest } from '../types/auth'; import { CreateJuniorRequest, JuniorTheme } from '../types/junior'; import { CreateTaskRequest, TaskStatus, TaskSubmission } from '../types/task'; const API_BASE_URL = 'https://zod.life'; const AUTH_TOKEN = btoa('zod-digital:Zod2025'); // Base64 encode credentials // Helper function to get auth header const getAuthHeader = () => { const token = localStorage.getItem('accessToken'); return token ? `Bearer ${token}` : `Basic ${AUTH_TOKEN}`; }; export const apiClient = axios.create({ baseURL: API_BASE_URL, headers: { 'Content-Type': 'application/json', 'x-client-id': 'web-client', }, }); // Add request interceptor to include current auth header apiClient.interceptors.request.use((config) => { config.headers.Authorization = getAuthHeader(); return config; }); // Add response interceptor to handle errors apiClient.interceptors.response.use( (response) => response, (error) => { const errorMessage = error.response?.data?.message || error.response?.data?.error || error.message || 'An unexpected error occurred'; console.error('API Error:', { status: error.response?.status, message: errorMessage, data: error.response?.data, }); // Throw error with meaningful message throw new Error(errorMessage); }, ); // Auth API export const authApi = { register: (countryCode: string, phoneNumber: string) => { // Ensure phone number is in the correct format (remove any non-digit characters) const cleanPhoneNumber = phoneNumber.replace(/\D/g, ''); return apiClient.post('/api/auth/register/otp', { countryCode: countryCode.startsWith('+') ? countryCode : `+${countryCode}`, phoneNumber: cleanPhoneNumber, }); }, verifyOtp: (countryCode: string, phoneNumber: string, otp: string) => apiClient.post('/api/auth/register/verify', { countryCode, phoneNumber, otp }), setEmail: (email: string) => { // Use the stored token from localStorage const storedToken = localStorage.getItem('accessToken'); if (!storedToken) { throw new Error('No access token found'); } return apiClient.post('/api/auth/register/set-email', { email }); }, setPasscode: (passcode: string) => { // Use the stored token from localStorage const storedToken = localStorage.getItem('accessToken'); if (!storedToken) { throw new Error('No access token found'); } return apiClient.post('/api/auth/register/set-passcode', { passcode }); }, login: ({ grantType, email, password, appleToken, googleToken }: LoginRequest) => apiClient.post('/api/auth/login', { grantType, email, password, appleToken, googleToken, fcmToken: 'web-client-token', // Required by API signature: 'web-login', // Required by API }), }; // Juniors API export const juniorsApi = { createJunior: (data: CreateJuniorRequest) => apiClient.post('/api/juniors', data), getJuniors: (page = 1, size = 10) => apiClient.get(`/api/juniors?page=${page}&size=${size}`), getJunior: (juniorId: string) => apiClient.get(`/api/juniors/${juniorId}`), setTheme: (data: JuniorTheme) => apiClient.post('/api/juniors/set-theme', data), getQrCode: (juniorId: string) => apiClient.get(`/api/juniors/${juniorId}/qr-code`), validateQrCode: (token: string) => apiClient.get(`/api/juniors/qr-code/${token}/validate`), }; // Document API export const documentApi = { upload: (file: File, documentType: string) => { const formData = new FormData(); formData.append('document', file); formData.append('documentType', documentType); return apiClient.post('/api/document', formData, { headers: { 'Content-Type': 'multipart/form-data', }, }); }, }; // Tasks API export const tasksApi = { createTask: (data: CreateTaskRequest) => apiClient.post('/api/tasks', data), getTasks: (status: TaskStatus, page = 1, size = 10, juniorId?: string) => { const url = new URL('/api/tasks', API_BASE_URL); url.searchParams.append('status', status); url.searchParams.append('page', page.toString()); url.searchParams.append('size', size.toString()); if (juniorId) url.searchParams.append('juniorId', juniorId); return apiClient.get(url.pathname + url.search); }, getTaskById: (taskId: string) => apiClient.get(`/api/tasks/${taskId}`), submitTask: (taskId: string, data: TaskSubmission) => apiClient.patch(`/api/tasks/${taskId}/submit`, data), approveTask: (taskId: string) => apiClient.patch(`/api/tasks/${taskId}/approve`), rejectTask: (taskId: string) => apiClient.patch(`/api/tasks/${taskId}/reject`), };