Files
History-user/src/app/editor/[id]/featureCommands.ts
T
taDuc fe7696b72d feat: Support multi-select editor workflow and improve UI/UX
- Refactored state from single selectedFeatureId to selectedFeatureIds array in Editor and Viewer
- Updated Map component to support multi-select filtering for geometry binding visibility
- Made entity, wiki, and geometry side panels scrollable for better overflow handling
- Fixed viewer mode wiki link navigation for independent wikis
- Improved geometry binding UX and state synchronization
2026-05-11 04:49:28 +07:00

127 lines
4.4 KiB
TypeScript

"use client";
import { useCallback } from "react";
import type { Dispatch, SetStateAction } from "react";
import type { Entity } from "@/uhm/types/entities";
import type { Feature, FeatureProperties } from "@/uhm/types/geo";
import { ApiError } from "@/uhm/api/http";
import { buildFeatureEntityPatch } from "@/uhm/lib/editor/entity/entityBinding";
import { buildGeometryMetadataPatch } from "@/uhm/lib/editor/geometry/geometryMetadata";
import { uniqueEntityIds } from "@/uhm/lib/editor/snapshot/editorSnapshot";
import type { GeometryMetaFormState } from "@/uhm/lib/editor/session/sessionTypes";
type EditorDraftApi = {
patchFeatureProperties: (id: FeatureProperties["id"], patch: Partial<FeatureProperties>) => void;
};
type Options = {
editor: EditorDraftApi;
selectedFeatures: Feature[];
geometryMetaForm: GeometryMetaFormState;
setGeometryMetaForm: Dispatch<SetStateAction<GeometryMetaFormState>>;
selectedGeometryEntityIds: string[];
setSelectedGeometryEntityIds: Dispatch<SetStateAction<string[]>>;
entities: Entity[];
setIsEntitySubmitting: Dispatch<SetStateAction<boolean>>;
setEntityFormStatus: Dispatch<SetStateAction<string | null>>;
};
export function useFeatureCommands(options: Options) {
const {
editor,
selectedFeatures,
geometryMetaForm,
setGeometryMetaForm,
selectedGeometryEntityIds,
setSelectedGeometryEntityIds,
entities,
setIsEntitySubmitting,
setEntityFormStatus,
} = options;
const applyGeometryMetadata = useCallback(async (): Promise<{ ok: boolean; error?: string }> => {
if (!selectedFeatures || selectedFeatures.length === 0) {
const msg = "Hãy chọn ít nhất một geometry trước.";
setEntityFormStatus(msg);
return { ok: false, error: msg };
}
if (!geometryMetaForm.time_start.trim() || !geometryMetaForm.time_end.trim()) {
const msg = "time_start và time_end là bắt buộc.";
setEntityFormStatus(msg);
return { ok: false, error: msg };
}
let metadata;
try {
metadata = buildGeometryMetadataPatch(geometryMetaForm);
} catch (err) {
const msg = err instanceof Error ? err.message : "Thời gian không hợp lệ.";
setEntityFormStatus(msg);
return { ok: false, error: msg };
}
setIsEntitySubmitting(true);
setEntityFormStatus(null);
try {
for (const feature of selectedFeatures) {
editor.patchFeatureProperties(feature.properties.id, metadata.patch);
}
setGeometryMetaForm(metadata.formState);
setEntityFormStatus("Đã cập nhật thuộc tính GEO. Commit khi sẵn sàng.");
return { ok: true };
} finally {
setIsEntitySubmitting(false);
}
}, [
editor,
geometryMetaForm,
selectedFeatures,
setEntityFormStatus,
setGeometryMetaForm,
setIsEntitySubmitting,
]);
const applyEntitiesToSelectedGeometry = useCallback(async () => {
if (!selectedFeatures || selectedFeatures.length === 0) {
setEntityFormStatus("Hãy chọn ít nhất một geometry trước.");
return;
}
const entityIds = uniqueEntityIds(selectedGeometryEntityIds);
setIsEntitySubmitting(true);
setEntityFormStatus(null);
try {
for (const feature of selectedFeatures) {
editor.patchFeatureProperties(
feature.properties.id,
buildFeatureEntityPatch(feature, entityIds, entities)
);
}
setSelectedGeometryEntityIds(entityIds);
setEntityFormStatus("Đã cập nhật danh sách entity. Commit khi sẵn sàng.");
} catch (err) {
if (err instanceof ApiError) {
setEntityFormStatus(`Lưu thất bại: ${err.body}`);
} else {
setEntityFormStatus("Lưu thất bại.");
}
} finally {
setIsEntitySubmitting(false);
}
}, [
editor,
entities,
selectedFeatures,
selectedGeometryEntityIds,
setEntityFormStatus,
setIsEntitySubmitting,
setSelectedGeometryEntityIds,
]);
return {
applyGeometryMetadata,
applyEntitiesToSelectedGeometry,
};
}