diff --git a/src/app/editor/[id]/page.tsx b/src/app/editor/[id]/page.tsx index 0da64c9..3069d29 100644 --- a/src/app/editor/[id]/page.tsx +++ b/src/app/editor/[id]/page.tsx @@ -31,8 +31,8 @@ import { HIDDEN_BACKGROUND_LAYER_VISIBILITY, } from "@/uhm/lib/map/styles/backgroundLayers"; import { - ENTITY_TYPE_OPTIONS, -} from "@/uhm/lib/utils/entityTypeOptions"; + GEOMETRY_TYPE_OPTIONS, +} from "@/uhm/lib/map/geo/geometryTypeOptions"; import { EntityFormState, GeometryMetaFormState, @@ -1560,7 +1560,7 @@ export default function Page() { entities={entities} selectedGeometryEntityIds={selectedGeometryEntityIds} onEntityIdsChange={handleEntityIdsChange} - entityTypeOptions={ENTITY_TYPE_OPTIONS} + entityTypeOptions={GEOMETRY_TYPE_OPTIONS} geometryMetaForm={geometryMetaForm} onGeometryMetaFormChange={handleGeometryMetaFormChange} isEntitySubmitting={isEntitySubmitting} diff --git a/src/uhm/components/editor/SelectedGeometryPanel.tsx b/src/uhm/components/editor/SelectedGeometryPanel.tsx index 8de45d6..f26cc7e 100644 --- a/src/uhm/components/editor/SelectedGeometryPanel.tsx +++ b/src/uhm/components/editor/SelectedGeometryPanel.tsx @@ -4,12 +4,12 @@ import { type CSSProperties, useMemo, useState } from "react"; import { Entity } from "@/uhm/api/entities"; import { Feature } from "@/uhm/lib/editor/state/useEditorState"; import { - EntityGeometryPreset, - EntityTypeGroupId, - EntityTypeOption, - findEntityTypeOption, - groupEntityTypeOptions, -} from "@/uhm/lib/utils/entityTypeOptions"; + GeometryPreset, + GeometryTypeGroupId, + GeometryTypeOption, + findGeometryTypeOption, + groupGeometryTypeOptions, +} from "@/uhm/lib/map/geo/geometryTypeOptions"; import type { GeometryMetaFormState } from "@/uhm/lib/editor/session/sessionTypes"; type Props = { @@ -19,7 +19,7 @@ type Props = { entities: Entity[]; selectedGeometryEntityIds: string[]; onEntityIdsChange: (values: string[]) => void; - entityTypeOptions: EntityTypeOption[]; + entityTypeOptions: GeometryTypeOption[]; geometryMetaForm: GeometryMetaFormState; onGeometryMetaFormChange: (key: keyof GeometryMetaFormState, value: string) => void; isEntitySubmitting: boolean; @@ -81,13 +81,13 @@ export default function SelectedGeometryPanel({ if (!selectedFeatures || selectedFeatures.length === 0) return null; const representativeFeature = selectedFeatures[0]; - const groupedEntityTypeOptions = groupEntityTypeOptions(entityTypeOptions); + const groupedGeometryTypeOptions = groupGeometryTypeOptions(entityTypeOptions); const featureGeometryPreset = resolveFeatureGeometryPreset(representativeFeature); const allowedGroupIds = getAllowedGroupIdsForPreset(featureGeometryPreset); - const groupedGeoTypeOptions = groupedEntityTypeOptions.filter((group) => + const groupedGeoTypeOptions = groupedGeometryTypeOptions.filter((group) => allowedGroupIds.includes(group.id) ); - const selectedTypeOption = findEntityTypeOption(geometryMetaForm.type_key); + const selectedTypeOption = findGeometryTypeOption(geometryMetaForm.type_key); const hasCurrentVisibleTypeOption = groupedGeoTypeOptions.some((group) => group.options.some((option) => option.value === geometryMetaForm.type_key) ); @@ -342,20 +342,20 @@ function MinusIcon() { ); } -function resolveFeatureGeometryPreset(feature: Feature): EntityGeometryPreset { +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 = findEntityTypeOption(semanticType); + const option = findGeometryTypeOption(semanticType); if (option) return option.geometryPreset; } return mapGeometryTypeToPreset(feature.geometry.type); } -function normalizeGeometryPreset(value: unknown): EntityGeometryPreset | null { +function normalizeGeometryPreset(value: unknown): GeometryPreset | null { if (typeof value !== "string") return null; const normalized = value.trim().toLowerCase(); if ( @@ -377,7 +377,7 @@ function normalizeTypeId(value: unknown): string | null { function mapGeometryTypeToPreset( geometryType: Feature["geometry"]["type"] -): EntityGeometryPreset { +): GeometryPreset { if (geometryType === "Point" || geometryType === "MultiPoint") { return "point"; } @@ -388,8 +388,8 @@ function mapGeometryTypeToPreset( } function getAllowedGroupIdsForPreset( - geometryPreset: EntityGeometryPreset -): EntityTypeGroupId[] { + geometryPreset: GeometryPreset +): GeometryTypeGroupId[] { if (geometryPreset === "point") { return ["point"]; } @@ -405,7 +405,7 @@ function getAllowedGroupIdsForPreset( return ["polygon"]; } -function formatGeometryPresetLabel(preset: EntityGeometryPreset | null): string { +function formatGeometryPresetLabel(preset: GeometryPreset | null): string { if (preset === "point") return "point - Điểm"; if (preset === "line") return "line - Tuyến"; if (preset === "circle-area") return "circle - Tròn"; diff --git a/src/uhm/lib/editor/session/sessionTypes.ts b/src/uhm/lib/editor/session/sessionTypes.ts index d8f71d9..7358d94 100644 --- a/src/uhm/lib/editor/session/sessionTypes.ts +++ b/src/uhm/lib/editor/session/sessionTypes.ts @@ -1,4 +1,4 @@ -import type { EntityGeometryPreset } from "@/uhm/lib/utils/entityTypeOptions"; +import type { GeometryPreset } from "@/uhm/lib/map/geo/geometryTypeOptions"; export type EditorMode = | "idle" @@ -38,4 +38,4 @@ export type CreatedEntitySummary = { name: string; }; -export type GeometryPreset = EntityGeometryPreset; +export type { GeometryPreset }; diff --git a/src/uhm/lib/editor/snapshot/editorSnapshot.ts b/src/uhm/lib/editor/snapshot/editorSnapshot.ts index 79eb505..0a1f0a1 100644 --- a/src/uhm/lib/editor/snapshot/editorSnapshot.ts +++ b/src/uhm/lib/editor/snapshot/editorSnapshot.ts @@ -1,4 +1,4 @@ -import { DEFAULT_ENTITY_TYPE_ID } from "@/uhm/lib/utils/entityTypeOptions"; +import { DEFAULT_GEOMETRY_TYPE_ID } from "@/uhm/lib/map/geo/geometryTypeOptions"; import { geoTypeCodeToTypeKey, typeKeyToGeoTypeCode } from "@/uhm/lib/map/geo/geoTypeMap"; import type { Change } from "@/uhm/lib/editor/draft/editorTypes"; import type { EntitySnapshot } from "@/uhm/types/entities"; @@ -659,7 +659,7 @@ export function getDefaultTypeIdForFeature(feature: Feature): string { if (preset === "line") return "defense_line"; if (preset === "point") return "city"; if (preset === "circle-area") return "war"; - if (preset === "polygon") return DEFAULT_ENTITY_TYPE_ID; + if (preset === "polygon") return DEFAULT_GEOMETRY_TYPE_ID; const geometryType = feature.geometry.type; if (geometryType === "LineString" || geometryType === "MultiLineString") { @@ -668,7 +668,7 @@ export function getDefaultTypeIdForFeature(feature: Feature): string { if (geometryType === "Point" || geometryType === "MultiPoint") { return "city"; } - return DEFAULT_ENTITY_TYPE_ID; + return DEFAULT_GEOMETRY_TYPE_ID; } export function normalizeFeatureEntityIds(feature: Feature): string[] { diff --git a/src/uhm/lib/utils/entityTypeOptions.ts b/src/uhm/lib/map/geo/geometryTypeOptions.ts similarity index 76% rename from src/uhm/lib/utils/entityTypeOptions.ts rename to src/uhm/lib/map/geo/geometryTypeOptions.ts index 1d9a6b7..7906590 100644 --- a/src/uhm/lib/utils/entityTypeOptions.ts +++ b/src/uhm/lib/map/geo/geometryTypeOptions.ts @@ -1,27 +1,27 @@ -export type EntityTypeGroupId = +export type GeometryTypeGroupId = | "line" | "polygon" | "circle" | "point"; -export type EntityGeometryPreset = "line" | "polygon" | "circle-area" | "point"; +export type GeometryPreset = "line" | "polygon" | "circle-area" | "point"; -export type EntityTypeGroup = { - id: EntityTypeGroupId; +export type GeometryTypeGroup = { + id: GeometryTypeGroupId; label: string; geometryLabel: string; description: string; }; -export type EntityTypeOption = { +export type GeometryTypeOption = { value: string; label: string; - groupId: EntityTypeGroupId; + groupId: GeometryTypeGroupId; groupLabel: string; - geometryPreset: EntityGeometryPreset; + geometryPreset: GeometryPreset; }; -export const ENTITY_TYPE_GROUPS: EntityTypeGroup[] = [ +export const GEOMETRY_TYPE_GROUPS: GeometryTypeGroup[] = [ { id: "line", label: "line - Tuyến", @@ -48,18 +48,18 @@ export const ENTITY_TYPE_GROUPS: EntityTypeGroup[] = [ }, ]; -const GROUP_BY_ID: Record = { - line: ENTITY_TYPE_GROUPS[0], - polygon: ENTITY_TYPE_GROUPS[1], - circle: ENTITY_TYPE_GROUPS[2], - point: ENTITY_TYPE_GROUPS[3], +const GROUP_BY_ID: Record = { + line: GEOMETRY_TYPE_GROUPS[0], + polygon: GEOMETRY_TYPE_GROUPS[1], + circle: GEOMETRY_TYPE_GROUPS[2], + point: GEOMETRY_TYPE_GROUPS[3], }; -const RAW_ENTITY_TYPE_OPTIONS: Array<{ +const RAW_GEOMETRY_TYPE_OPTIONS: Array<{ value: string; label: string; - groupId: EntityTypeGroupId; - geometryPreset: EntityGeometryPreset; + groupId: GeometryTypeGroupId; + geometryPreset: GeometryPreset; }> = [ { value: "defense_line", label: "Defense Line", groupId: "line", geometryPreset: "line" }, @@ -94,29 +94,29 @@ const RAW_ENTITY_TYPE_OPTIONS: Array<{ { value: "bridge", label: "Bridge", groupId: "point", geometryPreset: "point" }, ]; -export const ENTITY_TYPE_OPTIONS: EntityTypeOption[] = RAW_ENTITY_TYPE_OPTIONS.map((item) => ({ +export const GEOMETRY_TYPE_OPTIONS: GeometryTypeOption[] = RAW_GEOMETRY_TYPE_OPTIONS.map((item) => ({ ...item, groupLabel: GROUP_BY_ID[item.groupId].label, })); -export const DEFAULT_ENTITY_TYPE_ID = "country"; +export const DEFAULT_GEOMETRY_TYPE_ID = "country"; // Gom option theo group để render select phân nhóm. -export function groupEntityTypeOptions(options: EntityTypeOption[] = ENTITY_TYPE_OPTIONS): Array<{ - id: EntityTypeGroupId; +export function groupGeometryTypeOptions(options: GeometryTypeOption[] = GEOMETRY_TYPE_OPTIONS): Array<{ + id: GeometryTypeGroupId; label: string; geometryLabel: string; description: string; - options: EntityTypeOption[]; + options: GeometryTypeOption[]; }> { - return ENTITY_TYPE_GROUPS.map((group) => ({ + return GEOMETRY_TYPE_GROUPS.map((group) => ({ ...group, options: options.filter((option) => option.groupId === group.id), })).filter((group) => group.options.length > 0); } // Tìm option theo type id, trả null nếu không tồn tại. -export function findEntityTypeOption(typeId: string | null | undefined): EntityTypeOption | null { +export function findGeometryTypeOption(typeId: string | null | undefined): GeometryTypeOption | null { if (!typeId) return null; - return ENTITY_TYPE_OPTIONS.find((option) => option.value === typeId) || null; + return GEOMETRY_TYPE_OPTIONS.find((option) => option.value === typeId) || null; } diff --git a/src/uhm/types/geo.ts b/src/uhm/types/geo.ts index 74cb541..ad1aa50 100644 --- a/src/uhm/types/geo.ts +++ b/src/uhm/types/geo.ts @@ -1,4 +1,4 @@ -import type { EntityGeometryPreset } from "@/uhm/lib/utils/entityTypeOptions"; +import type { GeometryPreset } from "@/uhm/lib/map/geo/geometryTypeOptions"; export type Geometry = | { type: "Point"; coordinates: [number, number] } @@ -13,7 +13,7 @@ export type FeatureId = string | number; export type FeatureProperties = { id: FeatureId; type?: string | null; - geometry_preset?: EntityGeometryPreset | null; + geometry_preset?: GeometryPreset | null; time_start?: number | null; time_end?: number | null; binding?: string[];