Files
ArchiTools/src/modules/geoportal/v2/geoportal-v2.tsx
T
Claude VM 68355efbba fix(geoportal-v2): UAT click deep-links to eterra.live + revert debug
UAT click previously console.logged only. gis-api search response
doesn't include bbox/centroid, so ArchiTools can't fitBounds locally.
Reuse the deep-link pattern (already used by Export GeoPackage) →
open eterra.live/harta?siruta=X in a new tab. eterra.live has its own
/api/geoportal/uat-bounds + flyTo wired.

Future: add GET /api/v1/uat/:siruta/bounds to gis-api so ArchiTools
can fitBounds inline without leaving the page.

Also reverts the session.debug diagnostic (Marius confirmed
hasRefreshToken=true + expiresIn=293 after attaching offline_access
scope mapping to Authentik provider pk=6 — root cause fixed,
diagnostic no longer needed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 23:59:47 +03:00

89 lines
2.8 KiB
TypeScript

"use client";
import { useRef, useState, useCallback } from "react";
import dynamic from "next/dynamic";
import { BasemapSwitcher, type BasemapId } from "./basemap-switcher";
import { SearchBar, type FeatureHit, type UatHit } from "./search-bar";
import {
FeatureInfoPanel,
type ClickedFeatureLite,
} from "./feature-info-panel";
import type { MapViewerHandle } from "./map-viewer";
const MapViewer = dynamic(
() => import("./map-viewer").then((m) => ({ default: m.MapViewer })),
{
ssr: false,
loading: () => (
<div className="flex h-full items-center justify-center bg-muted/30">
<p className="text-sm text-muted-foreground">Se încarcă harta</p>
</div>
),
},
);
export function GeoportalV2() {
const mapRef = useRef<MapViewerHandle>(null);
const [basemap, setBasemap] = useState<BasemapId>("liberty");
const [clicked, setClicked] = useState<ClickedFeatureLite | null>(null);
const handleFeatureClick = useCallback((f: ClickedFeatureLite | null) => {
setClicked(f);
}, []);
const handleUatSelect = useCallback((uat: UatHit) => {
// gis-api search doesn't return UAT bounds today, so we can't flyTo
// server-side. Workaround: deep-link to eterra.live/harta which has
// bbox lookup (their /api/geoportal/uat-bounds + flyTo). Future:
// add GET /api/v1/uat/:siruta/bounds to gis-api and fitBounds here.
const url = `https://eterra.live/harta?siruta=${encodeURIComponent(uat.siruta)}`;
window.open(url, "_blank", "noopener,noreferrer");
}, []);
const handleFeatureSelect = useCallback((f: FeatureHit) => {
// Show panel directly (feature ID is known)
setClicked({
id: f.id,
siruta: "",
cadastralRef: f.cadastralRef,
layerId: f.layerId,
areaValue: f.areaValue,
});
}, []);
return (
<div className="absolute inset-0">
<MapViewer
ref={mapRef}
basemap={basemap}
onFeatureClick={handleFeatureClick}
className="h-full w-full"
/>
{/* Top-left: search */}
<div className="absolute left-3 top-3 z-10 flex flex-col gap-2">
<SearchBar
onUatSelect={handleUatSelect}
onFeatureSelect={handleFeatureSelect}
/>
</div>
{/* Top-right: basemap + panel */}
<div className="absolute right-14 top-3 z-10 flex flex-col items-end gap-2">
<BasemapSwitcher value={basemap} onChange={setBasemap} />
{clicked && (
<FeatureInfoPanel
feature={clicked}
onClose={() => setClicked(null)}
/>
)}
</div>
{/* Bottom-right: cutover badge (visible until full rollout) */}
<div className="pointer-events-none absolute bottom-2 right-2 z-10 rounded bg-primary/90 px-2 py-0.5 text-[10px] font-medium text-primary-foreground shadow">
gis.ac · v2
</div>
</div>
);
}