import { useEffect, useState, useCallback } from "react"; import * as Y from "yjs"; import type { YjsState } from "~/lib/use-yjs"; interface WaypointData { lat: number; lon: number; name?: string; } function getWaypointsFromYjs(waypoints: Y.Array>): WaypointData[] { return waypoints.toArray().map((yMap) => ({ lat: yMap.get("lat") as number, lon: yMap.get("lon") as number, name: yMap.get("name") as string | undefined, })); } interface WaypointSidebarProps { yjs: YjsState; routeStats?: { distance?: number; elevationGain?: number; elevationLoss?: number; }; } export function WaypointSidebar({ yjs, routeStats }: WaypointSidebarProps) { const [waypoints, setWaypoints] = useState([]); useEffect(() => { const update = () => setWaypoints(getWaypointsFromYjs(yjs.waypoints)); yjs.waypoints.observeDeep(update); update(); return () => yjs.waypoints.unobserveDeep(update); }, [yjs.waypoints]); const deleteWaypoint = useCallback( (index: number) => { yjs.doc.transact(() => yjs.waypoints.delete(index, 1), "local"); }, [yjs.doc, yjs.waypoints], ); const moveWaypoint = useCallback( (from: number, to: number) => { if (from === to || from < 0 || to < 0) return; const item = yjs.waypoints.get(from); if (!item) return; const data = { lat: item.get("lat") as number, lon: item.get("lon") as number, name: item.get("name") as string | undefined }; yjs.doc.transact(() => { yjs.waypoints.delete(from, 1); const yMap = new Y.Map(); yMap.set("lat", data.lat); yMap.set("lon", data.lon); if (data.name) yMap.set("name", data.name); yjs.waypoints.insert(to, [yMap]); }, "local"); }, [yjs.waypoints, yjs.doc], ); return (

Waypoints ({waypoints.length})

{waypoints.length === 0 ? (

Click on the map to add waypoints

) : (
    {waypoints.map((wp, i) => (
  • {i + 1}

    {wp.name ?? `${wp.lat.toFixed(4)}, ${wp.lon.toFixed(4)}`}

    {i > 0 && ( )} {i < waypoints.length - 1 && ( )}
  • ))}
)}
{routeStats && routeStats.distance !== undefined && (

{(routeStats.distance / 1000).toFixed(1)} km

Distance

{routeStats.elevationGain !== undefined && (

↑ {routeStats.elevationGain} m

Ascent

)} {routeStats.elevationLoss !== undefined && (

↓ {routeStats.elevationLoss} m

Descent

)}
)}
); }