add editor
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import type { EntityGeometryPreset } from "@/uhm/lib/entityTypeOptions";
|
||||
|
||||
export type EditorMode =
|
||||
| "idle"
|
||||
| "draw"
|
||||
| "select"
|
||||
| "add-point"
|
||||
| "add-line"
|
||||
| "add-path"
|
||||
| "add-circle";
|
||||
|
||||
export type TimelineRange = {
|
||||
min: number;
|
||||
max: number;
|
||||
};
|
||||
|
||||
export type EntityFormState = {
|
||||
name: string;
|
||||
slug: string;
|
||||
type_id: string;
|
||||
};
|
||||
|
||||
export type GeometryMetaFormState = {
|
||||
time_start: string;
|
||||
time_end: string;
|
||||
binding: string;
|
||||
};
|
||||
|
||||
export type PendingEntityCreate = {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string | null;
|
||||
type_id: string;
|
||||
status: number;
|
||||
};
|
||||
|
||||
export type CreatedEntitySummary = {
|
||||
id: string;
|
||||
name: string;
|
||||
type_id?: string | null;
|
||||
};
|
||||
|
||||
export type GeometryPreset = EntityGeometryPreset;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { useState } from "react";
|
||||
import {
|
||||
BackgroundLayerVisibility,
|
||||
HIDDEN_BACKGROUND_LAYER_VISIBILITY,
|
||||
} from "@/uhm/lib/backgroundLayers";
|
||||
|
||||
export function useBackgroundSessionState() {
|
||||
// Trạng thái bật/tắt layer nền (khởi tạo default hidden; sẽ load từ storage ở page).
|
||||
const [backgroundVisibility, setBackgroundVisibility] = useState<BackgroundLayerVisibility>(
|
||||
() => ({ ...HIDDEN_BACKGROUND_LAYER_VISIBILITY })
|
||||
);
|
||||
// Đảm bảo đã load visibility trước khi render map thật.
|
||||
const [isBackgroundVisibilityReady, setIsBackgroundVisibilityReady] = useState(false);
|
||||
|
||||
return {
|
||||
backgroundVisibility,
|
||||
setBackgroundVisibility,
|
||||
isBackgroundVisibilityReady,
|
||||
setIsBackgroundVisibilityReady,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import { useState } from "react";
|
||||
import type { Entity } from "@/uhm/types/entities";
|
||||
import type { FeatureId } from "@/uhm/types/geo";
|
||||
import { DEFAULT_ENTITY_TYPE_ID } from "@/uhm/lib/entityTypeOptions";
|
||||
import type {
|
||||
CreatedEntitySummary,
|
||||
EntityFormState,
|
||||
GeometryMetaFormState,
|
||||
PendingEntityCreate,
|
||||
} from "@/uhm/lib/editor/session/sessionTypes";
|
||||
|
||||
export function useEntitySessionState() {
|
||||
// Entities đã persisted từ backend (dùng cho search/binding).
|
||||
const [persistedEntities, setPersistedEntities] = useState<Entity[]>([]);
|
||||
// Entities tạo mới trong phiên nhưng chưa commit lên backend.
|
||||
const [pendingEntityCreates, setPendingEntityCreates] = useState<PendingEntityCreate[]>([]);
|
||||
// Tóm tắt entities đã tạo (để hiển thị nhanh ở sidebar).
|
||||
const [createdEntities, setCreatedEntities] = useState<CreatedEntitySummary[]>([]);
|
||||
// Thông báo trạng thái/lỗi liên quan entity/session.
|
||||
const [entityStatus, setEntityStatus] = useState<string | null>(null);
|
||||
// Feature đang được chọn để thao tác bind entities/metadata.
|
||||
const [selectedFeatureId, setSelectedFeatureId] = useState<FeatureId | null>(null);
|
||||
// Form tạo entity mới (độc lập).
|
||||
const [entityForm, setEntityForm] = useState<EntityFormState>({
|
||||
name: "",
|
||||
slug: "",
|
||||
type_id: DEFAULT_ENTITY_TYPE_ID,
|
||||
});
|
||||
// Danh sách entity IDs đang chọn để bind vào geometry hiện tại.
|
||||
const [selectedGeometryEntityIds, setSelectedGeometryEntityIds] = useState<string[]>([]);
|
||||
// Form metadata geometry (time range + binding ids).
|
||||
const [geometryMetaForm, setGeometryMetaForm] = useState<GeometryMetaFormState>({
|
||||
time_start: "",
|
||||
time_end: "",
|
||||
binding: "",
|
||||
});
|
||||
// Cờ loading khi apply entity/metadata (local submit).
|
||||
const [isEntitySubmitting, setIsEntitySubmitting] = useState(false);
|
||||
// Thông báo trạng thái/lỗi cho form entity/metadata.
|
||||
const [entityFormStatus, setEntityFormStatus] = useState<string | null>(null);
|
||||
// Keyword search entity theo name.
|
||||
const [entitySearchQuery, setEntitySearchQuery] = useState("");
|
||||
// Kết quả search entity để user chọn.
|
||||
const [entitySearchResults, setEntitySearchResults] = useState<Entity[]>([]);
|
||||
// Entity ID đang được chọn trong dropdown kết quả search.
|
||||
const [selectedSearchEntityId, setSelectedSearchEntityId] = useState<string | null>(null);
|
||||
// Cờ loading khi search entity.
|
||||
const [isEntitySearchLoading, setIsEntitySearchLoading] = useState(false);
|
||||
|
||||
return {
|
||||
persistedEntities,
|
||||
setPersistedEntities,
|
||||
pendingEntityCreates,
|
||||
setPendingEntityCreates,
|
||||
createdEntities,
|
||||
setCreatedEntities,
|
||||
entityStatus,
|
||||
setEntityStatus,
|
||||
selectedFeatureId,
|
||||
setSelectedFeatureId,
|
||||
entityForm,
|
||||
setEntityForm,
|
||||
selectedGeometryEntityIds,
|
||||
setSelectedGeometryEntityIds,
|
||||
geometryMetaForm,
|
||||
setGeometryMetaForm,
|
||||
isEntitySubmitting,
|
||||
setIsEntitySubmitting,
|
||||
entityFormStatus,
|
||||
setEntityFormStatus,
|
||||
entitySearchQuery,
|
||||
setEntitySearchQuery,
|
||||
entitySearchResults,
|
||||
setEntitySearchResults,
|
||||
selectedSearchEntityId,
|
||||
setSelectedSearchEntityId,
|
||||
isEntitySearchLoading,
|
||||
setIsEntitySearchLoading,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import type { Dispatch, SetStateAction } from "react";
|
||||
import type { EditorSnapshot, Section, SectionCommit, SectionState } from "@/uhm/types/sections";
|
||||
|
||||
type Options = {
|
||||
defaultEditorUserId: string;
|
||||
};
|
||||
|
||||
type SectionTask = "idle" | "saving" | "submitting" | "opening-section";
|
||||
|
||||
export function useSectionSessionState(options: Options) {
|
||||
// Single state machine cho các tác vụ async của section (saving/submitting/opening).
|
||||
const [sectionTask, setSectionTask] = useState<SectionTask>("idle");
|
||||
const setTaskFlag = useCallback((task: Exclude<SectionTask, "idle">, next: SetStateAction<boolean>) => {
|
||||
setSectionTask((prev) => {
|
||||
const currentValue = prev === task;
|
||||
const nextValue = typeof next === "function" ? next(currentValue) : next;
|
||||
if (nextValue) return task;
|
||||
return prev === task ? "idle" : prev;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const isSaving = sectionTask === "saving";
|
||||
const isSubmitting = sectionTask === "submitting";
|
||||
const isOpeningSection = sectionTask === "opening-section";
|
||||
const setIsSaving: Dispatch<SetStateAction<boolean>> = useCallback((next) => {
|
||||
setTaskFlag("saving", next);
|
||||
}, [setTaskFlag]);
|
||||
const setIsSubmitting: Dispatch<SetStateAction<boolean>> = useCallback((next) => {
|
||||
setTaskFlag("submitting", next);
|
||||
}, [setTaskFlag]);
|
||||
const setIsOpeningSection: Dispatch<SetStateAction<boolean>> = useCallback((next) => {
|
||||
setTaskFlag("opening-section", next);
|
||||
}, [setTaskFlag]);
|
||||
|
||||
// Danh sách sections để user chọn mở.
|
||||
const [availableSections, setAvailableSections] = useState<Section[]>([]);
|
||||
// Section ID đang được chọn trong dropdown.
|
||||
const [selectedSectionId, setSelectedSectionId] = useState("");
|
||||
// Title section mới (để create).
|
||||
const [newSectionTitle, setNewSectionTitle] = useState("");
|
||||
// Input title cho commit.
|
||||
const [commitTitle, setCommitTitle] = useState("");
|
||||
// Input note cho commit.
|
||||
const [commitNote, setCommitNote] = useState("");
|
||||
// User ID dùng để gắn vào commit/submit/lock.
|
||||
const [editorUserIdInput, setEditorUserIdInput] = useState(options.defaultEditorUserId);
|
||||
// Section đang mở để edit (null nếu chưa mở).
|
||||
const [activeSection, setActiveSection] = useState<Section | null>(null);
|
||||
// Trạng thái section (version/head/status/lock).
|
||||
const [sectionState, setSectionState] = useState<SectionState | null>(null);
|
||||
// Danh sách commits của section đang mở.
|
||||
const [sectionCommits, setSectionCommits] = useState<SectionCommit[]>([]);
|
||||
// Snapshot gần nhất đã load (để build snapshot diff/metadata).
|
||||
const [lastSectionSnapshot, setLastSectionSnapshot] = useState<EditorSnapshot | null>(null);
|
||||
|
||||
return {
|
||||
isSaving,
|
||||
setIsSaving,
|
||||
isSubmitting,
|
||||
setIsSubmitting,
|
||||
isOpeningSection,
|
||||
setIsOpeningSection,
|
||||
availableSections,
|
||||
setAvailableSections,
|
||||
selectedSectionId,
|
||||
setSelectedSectionId,
|
||||
newSectionTitle,
|
||||
setNewSectionTitle,
|
||||
commitTitle,
|
||||
setCommitTitle,
|
||||
commitNote,
|
||||
setCommitNote,
|
||||
editorUserIdInput,
|
||||
setEditorUserIdInput,
|
||||
activeSection,
|
||||
setActiveSection,
|
||||
sectionState,
|
||||
setSectionState,
|
||||
sectionCommits,
|
||||
setSectionCommits,
|
||||
lastSectionSnapshot,
|
||||
setLastSectionSnapshot,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { useState } from "react";
|
||||
import type { TimelineRange } from "@/uhm/lib/editor/session/sessionTypes";
|
||||
import { clampYearValue } from "@/uhm/lib/timeline";
|
||||
|
||||
type Options = {
|
||||
currentYear: number;
|
||||
fallbackTimelineRange: TimelineRange;
|
||||
};
|
||||
|
||||
export function useTimelineState(options: Options) {
|
||||
// Năm timeline "đã chốt" để fetch dữ liệu.
|
||||
const [timelineYear, setTimelineYear] = useState<number>(() =>
|
||||
clampYearValue(
|
||||
options.currentYear,
|
||||
options.fallbackTimelineRange.min,
|
||||
options.fallbackTimelineRange.max
|
||||
)
|
||||
);
|
||||
// Năm timeline đang chỉnh (debounce rồi đẩy sang timelineYear).
|
||||
const [timelineDraftYear, setTimelineDraftYear] = useState<number>(() =>
|
||||
clampYearValue(
|
||||
options.currentYear,
|
||||
options.fallbackTimelineRange.min,
|
||||
options.fallbackTimelineRange.max
|
||||
)
|
||||
);
|
||||
// Cờ loading khi fetch theo timeline.
|
||||
const [isTimelineLoading, setIsTimelineLoading] = useState(false);
|
||||
// Thông báo trạng thái/lỗi khi fetch theo timeline.
|
||||
const [timelineStatus, setTimelineStatus] = useState<string | null>(null);
|
||||
|
||||
return {
|
||||
timelineYear,
|
||||
setTimelineYear,
|
||||
timelineDraftYear,
|
||||
setTimelineDraftYear,
|
||||
isTimelineLoading,
|
||||
setIsTimelineLoading,
|
||||
timelineStatus,
|
||||
setTimelineStatus,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user