Phase 1 : seed CoastalPoints + frontend React complet

Backend :
- SeedCoastalPointsCommand : 29 points Antilles (idempotent)
  Martinique, Guadeloupe, Sainte-Lucie, Barbade, Saint-Martin

Frontend :
- api/client.js : wrapper fetch pour spots, observations, feedback
- SargassesMap : MapLibre GL JS, marqueurs spots, couche observations
  GeoJSON avec rechargement bbox dynamique à chaque mouvement carte
- SpotPanel : Spot Mode (score/niveau/distance/trend), bouton feedback
  terrain anonyme, gestion état loading/error/null
- App.jsx : composition map + panel, état selectedSpot
- vite.config.js : proxy /api → Symfony dev, build → backend/public/spa

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gwadaking
2026-04-01 03:17:43 -04:00
parent 4af5e62465
commit 0c1deb93cb
15 changed files with 1369 additions and 306 deletions

View File

@@ -0,0 +1,39 @@
const BASE_URL = import.meta.env.VITE_API_URL ?? '/api';
async function get(path, params = {}) {
const url = new URL(BASE_URL + path, window.location.origin);
Object.entries(params).forEach(([k, v]) => v !== undefined && url.searchParams.set(k, v));
const res = await fetch(url.toString(), {
headers: { Accept: 'application/json' },
});
if (!res.ok) throw new Error(`API error ${res.status}: ${path}`);
return res.json();
}
async function post(path, body) {
const res = await fetch(BASE_URL + path, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify(body),
});
if (!res.ok) throw new Error(`API error ${res.status}: ${path}`);
return res.json();
}
export const api = {
spots: {
list: () => get('/spots'),
get: (id) => get(`/spots/${id}`),
score: (id, at) => get(`/spots/${id}/score`, { at }),
},
observations: {
list: (bbox, date, source) => get('/observations', { bbox, date, source }),
get: (id) => get(`/observations/${id}`),
},
feedback: {
create: (data) => post('/feedback', data),
},
};