const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://45.93.137.91/api'; async function apiFetch(endpoint, options = {}) { const token = typeof window !== 'undefined' ? localStorage.getItem('token') : null; const headers = { 'Content-Type': 'application/json', ...(token && { Authorization: `Bearer ${token}` }), ...options.headers, }; console.log('[API] Request:', `${API_BASE}${endpoint}`, options.method || 'GET'); const res = await fetch(`${API_BASE}${endpoint}`, { ...options, headers, }); console.log('[API] Response:', res.status, endpoint); if (!res.ok && res.status !== 206) { const text = await res.text().catch(() => ''); console.error('[API] Error:', res.status, text); throw new Error(`API ${res.status}: ${text || res.statusText}`); } const text = await res.text(); if (!text) return null; try { const json = JSON.parse(text); if (json && typeof json === 'object' && 'data' in json) { return json.data; } return json; } catch { return text; } } // Raw fetch for auth (no token, returns full response for status code handling) async function authFetch(endpoint, body) { console.log('[Auth] Request:', `${API_BASE}${endpoint}`); const res = await fetch(`${API_BASE}${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); console.log('[Auth] Response status:', res.status, endpoint); const text = await res.text(); let data = null; try { data = text ? JSON.parse(text) : null; if (data && typeof data === 'object' && 'data' in data) { data = data.data; } } catch { data = text; } return { status: res.status, data, ok: res.ok || res.status === 206 }; } // ─── Rent Properties ─── export async function getRentProperties() { return apiFetch('/RentProperties/GetRentProperties'); } export async function getRentProperty(id) { const items = await apiFetch('/RentProperties/GetRentProperties'); if (!Array.isArray(items)) return items; return items.find(p => p.id == id) || items[0]; } export async function getRentPropertyLocations(params = {}) { const qs = new URLSearchParams(); if (params.maxOffset != null) qs.set('maxOffset', params.maxOffset); if (params.minOffset != null) qs.set('minOffset', params.minOffset); const query = qs.toString(); return apiFetch(`/RentProperties/GetRentPropertiesLocations${query ? `?${query}` : ''}`); } // ─── Sale Properties ─── export async function getSaleProperties() { return apiFetch('/SaleProperties/GetSaleProperties'); } export async function getSaleProperty(id) { const items = await apiFetch('/SaleProperties/GetSaleProperties'); if (!Array.isArray(items)) return items; return items.find(p => p.id == id) || items[0]; } // ─── Properties (generic) ─── export async function getProperty(id) { return apiFetch(`/Properties/Get/${id}`); } // ─── Recommendations ─── export async function getRecommendations() { return apiFetch('/Recommendations/GetRecommendations'); } export async function getTopRecommendations(count = 10) { return apiFetch(`/Recommendations/GetTopRecommendations?count=${count}`); } // ─── Reservations ─── export async function getReservations() { return apiFetch('/Reservations/GetReservations'); } export async function getReservation(id) { return apiFetch(`/Reservations/GetReservation?id=${id}`); } export async function checkAvailability(propertyId, fromDate = null, toDate = null) { const qs = new URLSearchParams(); if (fromDate) qs.set('fromDate', fromDate); if (toDate) qs.set('toDate', toDate); const query = qs.toString(); return apiFetch(`/Reservations/GetAvailable/${propertyId}${query ? `?${query}` : ''}`); } export async function bookReservation(data) { return apiFetch('/Reservations/Book', { method: 'POST', body: JSON.stringify(data), }); } // ─── Terms ─── export async function getTerms() { return apiFetch('/Terms/GetTerms'); } // ─── Auth ─── export async function loginWithEmail(credential, password) { return authFetch('/Auth/LogInWithEmail', { credential, password, device: 0, appVersion: '1.0', }); } export async function loginWithPhone(credential, password) { return authFetch('/Auth/LogInWithPhoneNumber', { credential, password, device: 0, appVersion: '1.0', }); } export async function sendEmailOTP() { console.log('[Auth] Sending email OTP...'); return apiFetch('/Auth/SendEmailOTP', { method: 'POST' }); } export async function sendPhoneOTP() { console.log('[Auth] Sending phone OTP...'); return apiFetch('/Auth/SendPhoneNumberOTP', { method: 'POST' }); } export async function verifyEmail(code) { console.log('[Auth] Verifying email with code:', code); return authFetch(`/Auth/VerifyEmail?code=${encodeURIComponent(code)}`, {}); } export async function verifyPhone(code) { console.log('[Auth] Verifying phone with code:', code); return authFetch(`/Auth/VerifyPhoneNumber?code=${encodeURIComponent(code)}`, {}); } // Helpers export function isEmail(value) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value); } export function isPhoneNumber(value) { return /^\+?\d{7,15}$/.test(value.replace(/[\s\-()]/g, '')); }