const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'https://api.approagency.ir/api'; interface ApiOptions extends RequestInit { token?: string; } // Simple in-memory cache for ongoing requests const pendingRequests = new Map(); class ApiClient { private async request( endpoint: string, options: ApiOptions = {} ): Promise { const { token, ...fetchOptions } = options; const headers: Record = { ...(options.headers as Record || {}), }; // Don't set Content-Type for FormData (browser will set it automatically with boundary) if (!(options.body instanceof FormData)) { headers['Content-Type'] = 'application/json'; } if (token) { headers['Authorization'] = `Bearer ${token}`; } // Create a unique key for this request const requestKey = `${fetchOptions.method || 'GET'}-${endpoint}-${JSON.stringify(options.body)}`; // Check if there's already a pending request with the same key if (pendingRequests.has(requestKey)) { console.log('Deduplicating request:', endpoint); return pendingRequests.get(requestKey); } // Make the request const promise = fetch(`${API_BASE_URL}${endpoint}`, { ...fetchOptions, headers, }).then(async (response) => { if (!response.ok) { const error = await response.json().catch(() => ({})); throw new Error(error.message || 'API request failed'); } return response.json(); }).finally(() => { // Clean up after request completes pendingRequests.delete(requestKey); }); // Store the promise pendingRequests.set(requestKey, promise); return promise; } async post(endpoint: string, data: any, token?: string): Promise { const body = data instanceof FormData ? data : JSON.stringify(data); return this.request(endpoint, { method: 'POST', body, token, }); } async get(endpoint: string, token?: string): Promise { return this.request(endpoint, { method: 'GET', token, }); } async put(endpoint: string, data: any, token?: string): Promise { const body = data instanceof FormData ? data : JSON.stringify(data); return this.request(endpoint, { method: 'PUT', body, token, }); } async patch(endpoint: string, data: any, token?: string): Promise { const body = data instanceof FormData ? data : JSON.stringify(data); return this.request(endpoint, { method: 'PATCH', body, token, }); } async delete(endpoint: string, data?: any, token?: string): Promise { const options: ApiOptions = { method: 'DELETE', token, }; if (data) { options.body = data instanceof FormData ? data : JSON.stringify(data); if (!(data instanceof FormData)) { options.headers = { 'Content-Type': 'application/json', }; } } return this.request(endpoint, options); } async deleteWithBody(endpoint: string, data: any, token?: string): Promise { return this.delete(endpoint, data, token); } } export const apiClient = new ApiClient();