Publish curated GeoIntel source snapshot
This commit is contained in:
commit
0aae654d6e
764 files changed
+169154
No files matched your search
@@ -0,0 +1,195 @@
|
||||
import { useEffect, useMemo, useState, type FormEvent } from 'react'
|
||||
import type { AreaRead, ProjectRead } from '../../types'
|
||||
|
||||
const AREA_CATALOG_PAGE_SIZE = 12
|
||||
|
||||
function projectDisplayName(project: ProjectRead | null): string {
|
||||
if (project?.name === 'Belgium and North Sea Workbench') {
|
||||
return 'België en Belgische Noordzee'
|
||||
}
|
||||
if (project?.name === 'Kempen Regional Workbench') {
|
||||
return 'Kempen · volledige regio'
|
||||
}
|
||||
if (project?.name === 'Mol Municipality Workbench') {
|
||||
return 'Mol · lokale historische werkruimte'
|
||||
}
|
||||
return project?.name ?? 'Geen werkruimte actief'
|
||||
}
|
||||
|
||||
interface AreaFormState {
|
||||
name: string
|
||||
geometry: string
|
||||
crs: string
|
||||
}
|
||||
|
||||
interface AreaPanelProps {
|
||||
areas: AreaRead[]
|
||||
selectedProject: ProjectRead | null
|
||||
selectedProjectId: string | null
|
||||
loadingAreas: boolean
|
||||
areaForm: AreaFormState
|
||||
selectedMapAreaId: string
|
||||
onCreateArea: (event: FormEvent<HTMLFormElement>) => void
|
||||
onUpdateAreaForm: (areaForm: AreaFormState) => void
|
||||
onSelectMapArea: (areaId: string) => void
|
||||
}
|
||||
|
||||
export function AreaPanel({
|
||||
areas,
|
||||
selectedProject,
|
||||
selectedProjectId,
|
||||
loadingAreas,
|
||||
areaForm,
|
||||
selectedMapAreaId,
|
||||
onCreateArea,
|
||||
onUpdateAreaForm,
|
||||
onSelectMapArea,
|
||||
}: AreaPanelProps): JSX.Element {
|
||||
const [catalogOpen, setCatalogOpen] = useState(false)
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [page, setPage] = useState(1)
|
||||
const selectedArea = areas.find((area) => area.id === selectedMapAreaId)
|
||||
const filteredAreas = useMemo(() => {
|
||||
const query = searchQuery.trim().toLocaleLowerCase('nl-BE')
|
||||
if (!query) return areas
|
||||
return areas.filter((area) => area.name.toLocaleLowerCase('nl-BE').includes(query))
|
||||
}, [areas, searchQuery])
|
||||
const pageCount = Math.max(1, Math.ceil(filteredAreas.length / AREA_CATALOG_PAGE_SIZE))
|
||||
const visibleAreas = filteredAreas.slice(
|
||||
(page - 1) * AREA_CATALOG_PAGE_SIZE,
|
||||
page * AREA_CATALOG_PAGE_SIZE,
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setPage((current) => Math.min(current, pageCount))
|
||||
}, [pageCount])
|
||||
|
||||
useEffect(() => {
|
||||
setSearchQuery('')
|
||||
setPage(1)
|
||||
setCatalogOpen(false)
|
||||
}, [selectedProjectId])
|
||||
|
||||
return (
|
||||
<section data-testid="area-panel">
|
||||
<div className="panel-title-row">
|
||||
<div>
|
||||
<p className="eyebrow">Geografisch bereik</p>
|
||||
<h2>Gebieden</h2>
|
||||
</div>
|
||||
<span className="count-pill">{areas.length}</span>
|
||||
</div>
|
||||
<p className="muted">{projectDisplayName(selectedProject)}</p>
|
||||
|
||||
<div className="data-selection-summary data-selection-summary-area">
|
||||
<span>Getoond op de kaart</span>
|
||||
<strong>{selectedArea?.name ?? 'Geen gebied geselecteerd'}</strong>
|
||||
<small>{selectedArea?.area_m2 ? `${(selectedArea.area_m2 / 1_000_000).toLocaleString('nl-BE', { maximumFractionDigits: 2 })} km2` : 'Kies een gemeente, gewest, zeezone of teken een eigen selectie.'}</small>
|
||||
</div>
|
||||
|
||||
<details className="data-panel-form-block">
|
||||
<summary>Eigen gebied toevoegen (GeoJSON)</summary>
|
||||
<form className="compact-form" onSubmit={onCreateArea}>
|
||||
<label>
|
||||
Naam
|
||||
<input
|
||||
value={areaForm.name}
|
||||
onChange={(event) => onUpdateAreaForm({ ...areaForm, name: event.target.value })}
|
||||
placeholder="Naam van het gebied"
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
CRS
|
||||
<input
|
||||
value={areaForm.crs}
|
||||
onChange={(event) => onUpdateAreaForm({ ...areaForm, crs: event.target.value })}
|
||||
placeholder="EPSG:4326"
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
GeoJSON-geometrie
|
||||
<textarea
|
||||
value={areaForm.geometry}
|
||||
onChange={(event) => onUpdateAreaForm({ ...areaForm, geometry: event.target.value })}
|
||||
rows={4}
|
||||
/>
|
||||
</label>
|
||||
<button className="primary-action" type="submit" disabled={!selectedProjectId}>
|
||||
Gebied toevoegen
|
||||
</button>
|
||||
</form>
|
||||
</details>
|
||||
|
||||
{loadingAreas ? <p>Gebieden laden...</p> : null}
|
||||
{areas.length === 0 ? <p>Nog geen gebieden beschikbaar.</p> : null}
|
||||
<details
|
||||
className="data-panel-list-block area-catalog-disclosure"
|
||||
onToggle={(event) => setCatalogOpen(event.currentTarget.open)}
|
||||
>
|
||||
<summary>{areas.length} beschikbare gemeenten en regiogrenzen</summary>
|
||||
{catalogOpen ? (
|
||||
<>
|
||||
<div className="catalog-browser-toolbar">
|
||||
<label className="catalog-search-field">
|
||||
Zoek gemeente of regio
|
||||
<input
|
||||
type="search"
|
||||
value={searchQuery}
|
||||
onChange={(event) => {
|
||||
setSearchQuery(event.target.value)
|
||||
setPage(1)
|
||||
}}
|
||||
placeholder="Bijvoorbeeld Brussel, Namen of Noordzee"
|
||||
/>
|
||||
</label>
|
||||
<div className="catalog-pagination" aria-label="Paginering van gebieden">
|
||||
<span>{filteredAreas.length} gevonden</span>
|
||||
<button
|
||||
className="secondary-action"
|
||||
type="button"
|
||||
disabled={page === 1}
|
||||
onClick={() => setPage((current) => Math.max(1, current - 1))}
|
||||
>
|
||||
Vorige
|
||||
</button>
|
||||
<strong>{page} / {pageCount}</strong>
|
||||
<button
|
||||
className="secondary-action"
|
||||
type="button"
|
||||
disabled={page === pageCount}
|
||||
onClick={() => setPage((current) => Math.min(pageCount, current + 1))}
|
||||
>
|
||||
Volgende
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{visibleAreas.length > 0 ? (
|
||||
<ul className="entity-list">
|
||||
{visibleAreas.map((area) => (
|
||||
<li className={selectedMapAreaId === area.id ? 'entity-card entity-card-active' : 'entity-card'} key={area.id}>
|
||||
<strong>{area.name}</strong>
|
||||
<div className="entity-meta">
|
||||
<span>{area.area_m2 ? `${(area.area_m2 / 1_000_000).toLocaleString('nl-BE', { maximumFractionDigits: 2 })} km2` : 'Oppervlakte onbekend'}</span>
|
||||
<span>{area.geometry?.type ?? area.geometry_type ?? 'Geometrie onbekend'}</span>
|
||||
</div>
|
||||
<button
|
||||
className="secondary-action"
|
||||
type="button"
|
||||
onClick={() => onSelectMapArea(area.id)}
|
||||
disabled={!area.geometry}
|
||||
data-testid={`area-show-${area.id}`}
|
||||
>
|
||||
{selectedMapAreaId === area.id ? 'Op kaart' : 'Toon op kaart'}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p className="muted">Geen gebied gevonden voor deze zoekterm.</p>
|
||||
)}
|
||||
</>
|
||||
) : null}
|
||||
</details>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user