Task A (#254): Leaflet click-to-add custom POIs - sessionId.ts: getOrCreateSessionId() from localStorage - types/customPoi.ts: CustomPoi, CustomPoiCreate, CustomPoiUpdate - hooks/useCustomPois.ts: useCustomPois / useAddCustomPoi / useUpdateCustomPoi / useDeleteCustomPoi (TanStack Query, X-Session-Id header) - CustomPoiLayer.tsx: LayerGroup with CircleMarker (green/red/gray by weight), popup with edit/delete - CustomPoiToggleButton.tsx: crosshair mode toggle button - CustomPoiAddModal.tsx: modal form (name, 26 categories, weight -5..+5, notes) - CustomPoiEditModal.tsx: same form for editing existing POI - SiteMap.tsx: MapClickHandler (useMapEvents), integrated all custom POI components - page.tsx: useCustomPois hook + passes customPois + parcelCad to SiteMap Task B (#114): ScoreBreakdownStackedBar - ScoreBreakdownStackedBar.tsx: horizontal stacked bar by category with positive/negative split, toggle between category and factor views, custom POIs highlighted orange with dashed outline - OverviewTab.tsx: renders ScoreBreakdownStackedBar below ScoreBreakdownPanel Requires backend PR with /api/v1/custom-pois endpoints merged before POI CRUD works.
14 lines
410 B
TypeScript
14 lines
410 B
TypeScript
/**
|
|
* Session ID utility for custom POI auth.
|
|
* Stored in localStorage under "session_id" key.
|
|
* Returns empty string during SSR (window not available).
|
|
*/
|
|
export function getOrCreateSessionId(): string {
|
|
if (typeof window === "undefined") return "";
|
|
let id = localStorage.getItem("session_id");
|
|
if (!id) {
|
|
id = crypto.randomUUID();
|
|
localStorage.setItem("session_id", id);
|
|
}
|
|
return id;
|
|
}
|