CognxSafeTrack
feat: backlog P0→P3 — toast system, payments, tenant isolation, feedback handler, i18n parity
6dd9bad | export const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3001'; | |
| export const ah = (token: string, orgId?: string | null): Record<string, string> => { | |
| const headers: Record<string, string> = { | |
| 'Authorization': `Bearer ${token}`, | |
| 'Content-Type': 'application/json' | |
| }; | |
| if (orgId) headers['x-organization-id'] = orgId; | |
| return headers; | |
| }; | |
| export const api = { | |
| async request(path: string, options: any = {}, token: string | null = null, orgId: string | null = null) { | |
| const url = path.startsWith('http') ? path : `${API_URL}${path}`; | |
| const headers = { | |
| ...ah(token || '', orgId), | |
| ...(options.headers || {}) | |
| }; | |
| const res = await fetch(url, { ...options, headers }); | |
| if (res.status === 401) { | |
| // Global 401 handling: Clear session and redirect to login | |
| sessionStorage.clear(); | |
| window.location.href = '/login'; | |
| throw new Error('Unauthorized'); | |
| } | |
| if (!res.ok) { | |
| const error = await res.json().catch(() => ({ error: 'Unknown error' })); | |
| throw new Error(error.error || `Request failed with status ${res.status}`); | |
| } | |
| return res.json(); | |
| }, | |
| get(path: string, token: string | null, orgId: string | null = null) { | |
| return this.request(path, { method: 'GET' }, token, orgId); | |
| }, | |
| post(path: string, body: any, token: string | null, orgId: string | null = null) { | |
| return this.request(path, { method: 'POST', body: JSON.stringify(body) }, token, orgId); | |
| }, | |
| put(path: string, body: any, token: string | null, orgId: string | null = null) { | |
| return this.request(path, { method: 'PUT', body: JSON.stringify(body) }, token, orgId); | |
| }, | |
| patch(path: string, body: any, token: string | null, orgId: string | null = null) { | |
| return this.request(path, { method: 'PATCH', body: JSON.stringify(body) }, token, orgId); | |
| }, | |
| delete(path: string, token: string | null, orgId: string | null = null) { | |
| return this.request(path, { method: 'DELETE' }, token, orgId); | |
| }, | |
| async upload(path: string, formData: FormData, token: string | null, orgId: string | null = null) { | |
| // Omit Content-Type so the browser sets multipart boundary automatically | |
| const url = path.startsWith('http') ? path : `${API_URL}${path}`; | |
| const headers: Record<string, string> = { 'Authorization': `Bearer ${token || ''}` }; | |
| if (orgId) headers['x-organization-id'] = orgId; | |
| const res = await fetch(url, { method: 'POST', headers, body: formData }); | |
| if (res.status === 401) { sessionStorage.clear(); window.location.href = '/login'; throw new Error('Unauthorized'); } | |
| if (!res.ok) { const e = await res.json().catch(() => ({ error: 'Unknown error' })); throw new Error(e.error || `Upload failed with status ${res.status}`); } | |
| return res.json(); | |
| } | |
| }; | |