"use client"; import { type CSSProperties, useMemo, useState } from "react"; import { Feature } from "@/uhm/lib/editor/state/useEditorState"; import { GeometryPreset, GeometryTypeGroupId, GeometryTypeOption, findGeometryTypeOption, groupGeometryTypeOptions, } from "@/uhm/lib/map/geo/geometryTypeOptions"; import { normalizeGeoTypeKey } from "@/uhm/lib/map/geo/geoTypeMap"; import type { GeometryMetaFormState } from "@/uhm/lib/editor/session/sessionTypes"; type Props = { selectedFeatures: Feature[]; entityTypeOptions: GeometryTypeOption[]; geometryMetaForm: GeometryMetaFormState; onGeometryMetaFormChange: (key: keyof GeometryMetaFormState, value: string) => void; isEntitySubmitting: boolean; onApplyGeometryMetadata: () => Promise<{ ok: boolean; error?: string }>; changeCount: number; }; export default function SelectedGeometryPanel({ selectedFeatures, entityTypeOptions, geometryMetaForm, onGeometryMetaFormChange, isEntitySubmitting, onApplyGeometryMetadata, changeCount, }: Props) { const [collapsed, setCollapsed] = useState(false); const [geoApplyFeedback, setGeoApplyFeedback] = useState< | { kind: "ok" | "error"; text: string; signature: string; } | null >(null); const geoMetaSignature = useMemo(() => { return [ geometryMetaForm.type_key, geometryMetaForm.time_start, geometryMetaForm.time_end, geometryMetaForm.binding, ].join("|"); }, [ geometryMetaForm.binding, geometryMetaForm.time_end, geometryMetaForm.time_start, geometryMetaForm.type_key, ]); const handleApplyGeoMeta = async () => { setGeoApplyFeedback(null); const result = await onApplyGeometryMetadata(); if (result.ok) { setGeoApplyFeedback({ kind: "ok", text: "đã apply thành công", signature: geoMetaSignature }); } else if (result.error) { setGeoApplyFeedback({ kind: "error", text: result.error, signature: geoMetaSignature }); } }; const visibleGeoApplyFeedback = geoApplyFeedback && geoApplyFeedback.signature === geoMetaSignature ? geoApplyFeedback : null; if (!selectedFeatures || selectedFeatures.length === 0) return null; const representativeFeature = selectedFeatures[0]; const groupedGeometryTypeOptions = groupGeometryTypeOptions(entityTypeOptions); const featureGeometryPreset = resolveFeatureGeometryPreset(representativeFeature); const allowedGroupIds = getAllowedGroupIdsForPreset(featureGeometryPreset); const groupedGeoTypeOptions = groupedGeometryTypeOptions.filter((group) => allowedGroupIds.includes(group.id) ); const selectedTypeOption = findGeometryTypeOption(geometryMetaForm.type_key); const hasCurrentVisibleTypeOption = groupedGeoTypeOptions.some((group) => group.options.some((option) => option.value === geometryMetaForm.type_key) ); return (
Geometry property
{collapsed ? null : (
Thuộc tính GEO
Các giá trị này thuộc về GEO đang chọn, không phụ thuộc entity.
Loại GEO
{selectedTypeOption ? (
Đang chọn: {selectedTypeOption.label} ({selectedTypeOption.groupLabel})
) : geometryMetaForm.type_key ? (
Đang chọn: {geometryMetaForm.type_key}
) : null} onGeometryMetaFormChange("time_start", event.target.value)} placeholder="time_start" disabled={isEntitySubmitting} style={entityInputStyle} /> onGeometryMetaFormChange("time_end", event.target.value)} placeholder="time_end" disabled={isEntitySubmitting} style={entityInputStyle} /> {/* onGeometryMetaFormChange("binding", event.target.value)}*/} {/* placeholder="binding (geometry ids, comma separated)"*/} {/* disabled={isEntitySubmitting}*/} {/* style={entityInputStyle}*/} {/*/>*/} {visibleGeoApplyFeedback ? (
{visibleGeoApplyFeedback.text}
) : null}
{changeCount > 0 ? (
Thay đổi sẽ vào lịch sử khi Commit.
) : null}
)}
); } const entityInputStyle: CSSProperties = { width: "100%", borderRadius: "6px", border: "1px solid #334155", background: "#111827", color: "#f8fafc", padding: "6px 8px", fontSize: "13px", }; const primaryGeometryButtonStyle: CSSProperties = { border: "none", borderRadius: "6px", padding: "7px 8px", cursor: "pointer", background: "#0f766e", color: "#ffffff", fontWeight: 600, }; function PlusIcon() { return ( ); } function MinusIcon() { return ( ); } function resolveFeatureGeometryPreset(feature: Feature): GeometryPreset { const explicitPreset = normalizeGeometryPreset(feature.properties.geometry_preset); if (explicitPreset) return explicitPreset; const semanticType = normalizeTypeId(feature.properties.type) || normalizeTypeId(feature.properties.entity_type_id); if (semanticType) { const option = findGeometryTypeOption(semanticType); if (option) return option.geometryPreset; } return mapGeometryTypeToPreset(feature.geometry.type); } function normalizeGeometryPreset(value: unknown): GeometryPreset | null { if (typeof value !== "string") return null; const normalized = value.trim().toLowerCase(); if ( normalized === "point" || normalized === "line" || normalized === "polygon" || normalized === "circle-area" ) { return normalized; } return null; } function normalizeTypeId(value: unknown): string | null { return normalizeGeoTypeKey(value); } function mapGeometryTypeToPreset( geometryType: Feature["geometry"]["type"] ): GeometryPreset { if (geometryType === "Point" || geometryType === "MultiPoint") { return "point"; } if (geometryType === "LineString" || geometryType === "MultiLineString") { return "line"; } return "polygon"; } function getAllowedGroupIdsForPreset( geometryPreset: GeometryPreset ): GeometryTypeGroupId[] { if (geometryPreset === "point") { return ["point"]; } if (geometryPreset === "line") { return ["line"]; } if (geometryPreset === "circle-area") { return ["circle"]; } return ["polygon"]; }