113 lines
3.5 KiB
TypeScript
113 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Map from "@/components/Map";
|
|
import Editor from "@/components/Editor";
|
|
import BackgroundLayersPanel from "@/components/BackgroundLayersPanel";
|
|
import { ApiError } from "@/api/http";
|
|
import { fetchGeometriesByBBox, saveGeometryBatchChanges } from "@/api/geometries";
|
|
import {
|
|
FeatureCollection,
|
|
useEditorState,
|
|
} from "@/lib/useEditorState";
|
|
import {
|
|
BackgroundLayerId,
|
|
BackgroundLayerVisibility,
|
|
DEFAULT_BACKGROUND_LAYER_VISIBILITY,
|
|
HIDDEN_BACKGROUND_LAYER_VISIBILITY,
|
|
} from "@/lib/backgroundLayers";
|
|
|
|
const EMPTY_FC: FeatureCollection = { type: "FeatureCollection", features: [] };
|
|
|
|
export default function Page() {
|
|
const [mode, setMode] = useState<"idle" | "draw" | "select" | "add-point">("idle");
|
|
const [initialData, setInitialData] = useState<FeatureCollection>(EMPTY_FC);
|
|
const [isSaving, setIsSaving] = useState(false);
|
|
const [backgroundVisibility, setBackgroundVisibility] = useState<BackgroundLayerVisibility>(
|
|
() => ({ ...DEFAULT_BACKGROUND_LAYER_VISIBILITY })
|
|
);
|
|
|
|
const editor = useEditorState(initialData);
|
|
|
|
useEffect(() => {
|
|
async function loadInitial() {
|
|
try {
|
|
const data = await fetchGeometriesByBBox({
|
|
minLng: -180,
|
|
minLat: -90,
|
|
maxLng: 180,
|
|
maxLat: 90,
|
|
});
|
|
setInitialData(data);
|
|
} catch (err) {
|
|
console.error("Load initial data failed", err);
|
|
}
|
|
}
|
|
|
|
loadInitial();
|
|
}, []);
|
|
|
|
const handleSave = async () => {
|
|
const payload = editor.buildPayload();
|
|
if (!payload.length) return;
|
|
setIsSaving(true);
|
|
try {
|
|
await saveGeometryBatchChanges(payload);
|
|
editor.clearChanges();
|
|
} catch (err) {
|
|
if (err instanceof ApiError) {
|
|
console.error("Save failed", err.body);
|
|
return;
|
|
}
|
|
console.error("Save error", err);
|
|
} finally {
|
|
setIsSaving(false);
|
|
}
|
|
};
|
|
|
|
const handleToggleBackgroundLayer = (id: BackgroundLayerId) => {
|
|
setBackgroundVisibility((prev) => ({
|
|
...prev,
|
|
[id]: !prev[id],
|
|
}));
|
|
};
|
|
|
|
const handleShowAllBackgroundLayers = () => {
|
|
setBackgroundVisibility({ ...DEFAULT_BACKGROUND_LAYER_VISIBILITY });
|
|
};
|
|
|
|
const handleHideAllBackgroundLayers = () => {
|
|
setBackgroundVisibility({ ...HIDDEN_BACKGROUND_LAYER_VISIBILITY });
|
|
};
|
|
|
|
return (
|
|
<div style={{ display: "flex", minHeight: "100vh" }}>
|
|
<Editor
|
|
mode={mode}
|
|
setMode={setMode}
|
|
onUndo={editor.undo}
|
|
onSave={handleSave}
|
|
isSaving={isSaving}
|
|
changesCount={editor.changeCount}
|
|
undoStack={editor.undoStack}
|
|
/>
|
|
|
|
<Map
|
|
mode={mode}
|
|
draft={editor.draft}
|
|
onCreateFeature={editor.createFeature}
|
|
onDeleteFeature={editor.deleteFeature}
|
|
onUpdateFeature={editor.updateFeature}
|
|
backgroundVisibility={backgroundVisibility}
|
|
/>
|
|
|
|
<BackgroundLayersPanel
|
|
visibility={backgroundVisibility}
|
|
onToggleLayer={handleToggleBackgroundLayer}
|
|
onShowAll={handleShowAllBackgroundLayers}
|
|
onHideAll={handleHideAllBackgroundLayers}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|