| const BASE = import.meta.env?.VITE_API_URL ?? ''; |
|
|
| const req = async (path, opts = {}) => { |
| const token = localStorage.getItem('casa_token'); |
| const headers = { ...(opts.headers || {}) }; |
| if (token) headers['Authorization'] = `Bearer ${token}`; |
| if (opts.json) { |
| headers['Content-Type'] = 'application/json'; |
| opts.body = JSON.stringify(opts.json); |
| delete opts.json; |
| } |
| const r = await fetch(`${BASE}${path}`, { ...opts, headers }); |
| if (!r.ok) { |
| const e = await r.json().catch(() => ({ detail: r.statusText })); |
| throw new Error(e.detail || 'Request failed'); |
| } |
| return r.json(); |
| }; |
|
|
| const fd = (obj) => { |
| const f = new FormData(); |
| Object.entries(obj).forEach(([k,v]) => v != null && f.append(k, typeof v === 'object' ? JSON.stringify(v) : String(v))); |
| return f; |
| }; |
|
|
| export const api = { |
| |
| health: () => req('/health'), |
| |
| |
| register: (b) => req('/api/auth/register', { method:'POST', json:b }), |
| login: (b) => req('/api/auth/login', { method:'POST', json:b }), |
| me: () => req('/api/auth/me'), |
| logout: () => req('/api/auth/logout', { method:'POST' }), |
| |
| |
| saveDesign: (d) => req('/api/auth/save-design', { method:'POST', json:{ design:d } }), |
| savedDesigns: () => req('/api/auth/saved-designs'), |
| getDesign: (id) => req(`/api/designs/${id}`), |
| getPublicDesigns: (params) => req('/api/designs', { method:'GET', json:params }), |
| likeDesign: (id) => req(`/api/designs/${id}/like`, { method:'POST' }), |
| addComment: (id, comment) => req(`/api/designs/${id}/comments`, { method:'POST', json:comment }), |
| getComments: (id) => req(`/api/designs/${id}/comments`), |
| |
| |
| analyzeRoom: (f) => { |
| const form = new FormData(); |
| form.append('file', f); |
| return req('/api/rooms/analyze', { method:'POST', body:form }); |
| }, |
| |
| |
| generateDesign: (p) => req('/api/designs/generate', { method:'POST', body:fd(p) }), |
| explanation: (p) => req('/api/design-explanation', { method:'POST', body:fd(p) }), |
| wallFinish: (p) => req('/api/wall-finish', { method:'POST', body:fd(p) }), |
| |
| |
| styleQuiz: (answers) => req('/api/quiz/submit', { method:'POST', json:{ answers } }), |
| getQuizQuestions: () => req('/api/quiz/questions'), |
| moodBoard: (p) => req('/api/mood-board', { method:'POST', body:fd(p) }), |
| budgetBreakdown: (p) => req('/api/budget-breakdown', { method:'POST', body:fd(p) }), |
| |
| |
| getCatalog: (params) => { |
| const query = new URLSearchParams(params).toString(); |
| return req(`/api/catalog${query ? '?' + query : ''}`); |
| }, |
| getCategories: () => req('/api/catalog/categories'), |
| getBrands: () => req('/api/catalog/brands'), |
| getCatalogItem: (id) => req(`/api/catalog/${id}`), |
| |
| |
| exportDesign: (designId, format) => req('/api/export/pdf', { method:'POST', json:{ design_id:designId, format } }), |
| getExportStatus: (exportId) => req(`/api/export/status/${exportId}`), |
| |
| |
| getDesignStats: () => req('/api/stats/designs'), |
| |
| |
| generate3DModel: (designData) => req('/api/designs/3d', { method:'POST', json:designData }), |
| |
| |
| styleTransfer: (image, style) => { |
| const form = new FormData(); |
| form.append('image', image); |
| form.append('style', style); |
| return req('/api/style-transfer', { method:'POST', body:form }); |
| }, |
| |
| |
| getItemReviews: (itemId) => req(`/api/catalog/${itemId}/reviews`), |
| submitReview: (itemId, rating, comment) => |
| req(`/api/catalog/${itemId}/reviews`, { method:'POST', json:{ rating, comment } }), |
| }; |