export const api = { root: () => (window.WNW_API?.root?.replace(/\/$/, '') || ''), nonce: () => (window.WNW_API?.nonce || ''), async wpFetch(path: string, options: RequestInit = {}) { const url = /^https?:\/\//.test(path) ? path : api.root() + path; const headers = new Headers(options.headers || {}); if (!headers.has('X-WP-Nonce') && api.nonce()) headers.set('X-WP-Nonce', api.nonce()); if (!headers.has('Accept')) headers.set('Accept', 'application/json'); if (options.body && !headers.has('Content-Type')) headers.set('Content-Type', 'application/json'); const res = await fetch(url, { credentials: 'include', ...options, headers }); if (!res.ok) { let responseData: any = null; try { const text = await res.text(); responseData = text ? JSON.parse(text) : null; } catch { /* ignore JSON parse errors */ } if (window.WNW_API?.isDev) { console.error('[WooNooW] API error', { url, status: res.status, statusText: res.statusText, data: responseData }); } // Create error with response data attached (for error handling utility to extract) const err: any = new Error(res.statusText); err.response = { status: res.status, statusText: res.statusText, data: responseData }; throw err; } try { return await res.json(); } catch { return await res.text(); } }, async get(path: string, params?: Record) { const usp = new URLSearchParams(); if (params) { for (const [k, v] of Object.entries(params)) { if (v == null) continue; usp.set(k, String(v)); } } const qs = usp.toString(); return api.wpFetch(path + (qs ? `?${qs}` : '')); }, async post(path: string, body?: any) { return api.wpFetch(path, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: body != null ? JSON.stringify(body) : undefined, }); }, async put(path: string, body?: any) { return api.wpFetch(path, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: body != null ? JSON.stringify(body) : undefined, }); }, async del(path: string) { return api.wpFetch(path, { method: 'DELETE' }); }, }; export type CreateOrderPayload = { items: { product_id: number; qty: number }[]; billing?: Record; shipping?: Record; status?: string; payment_method?: string; }; export const OrdersApi = { list: (params?: Record) => api.get('/orders', params), get: (id: number) => api.get(`/orders/${id}`), create: (payload: CreateOrderPayload) => api.post('/orders', payload), update: (id: number, payload: any) => api.wpFetch(`/orders/${id}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }), payments: async () => api.get('/payments'), shippings: async () => api.get('/shippings'), countries: () => api.get('/countries'), }; export const ProductsApi = { search: (search: string, limit = 10) => api.get('/products/search', { search, limit }), list: (params?: { page?: number; per_page?: number }) => api.get('/products', { params }), categories: () => api.get('/products/categories'), }; export const CustomersApi = { search: (search: string) => api.get('/customers/search', { search }), searchByEmail: (email: string) => api.get('/customers/search', { email }), }; export async function getMenus() { // Prefer REST; fall back to localized snapshot try { const res = await fetch(`${(window as any).WNW_API}/menus`, { credentials: 'include' }); if (!res.ok) throw new Error('menus fetch failed'); return (await res.json()).items || []; } catch { return ((window as any).WNW_WC_MENUS?.items) || []; } }