refactor
This commit is contained in:
44
lib/editor/session/sessionTypes.ts
Normal file
44
lib/editor/session/sessionTypes.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import type { EntityGeometryPreset } from "@/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;
|
||||
|
||||
20
lib/editor/session/useBackgroundSessionState.ts
Normal file
20
lib/editor/session/useBackgroundSessionState.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { useState } from "react";
|
||||
import {
|
||||
BackgroundLayerVisibility,
|
||||
HIDDEN_BACKGROUND_LAYER_VISIBILITY,
|
||||
} from "@/lib/backgroundLayers";
|
||||
|
||||
export function useBackgroundSessionState() {
|
||||
const [backgroundVisibility, setBackgroundVisibility] = useState<BackgroundLayerVisibility>(
|
||||
() => ({ ...HIDDEN_BACKGROUND_LAYER_VISIBILITY })
|
||||
);
|
||||
const [isBackgroundVisibilityReady, setIsBackgroundVisibilityReady] = useState(false);
|
||||
|
||||
return {
|
||||
backgroundVisibility,
|
||||
setBackgroundVisibility,
|
||||
isBackgroundVisibilityReady,
|
||||
setIsBackgroundVisibilityReady,
|
||||
};
|
||||
}
|
||||
|
||||
66
lib/editor/session/useEntitySessionState.ts
Normal file
66
lib/editor/session/useEntitySessionState.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { useState } from "react";
|
||||
import type { Entity } from "@/types/entities";
|
||||
import type { FeatureId } from "@/types/geo";
|
||||
import { DEFAULT_ENTITY_TYPE_ID } from "@/lib/entityTypeOptions";
|
||||
import type {
|
||||
CreatedEntitySummary,
|
||||
EntityFormState,
|
||||
GeometryMetaFormState,
|
||||
PendingEntityCreate,
|
||||
} from "@/lib/editor/session/sessionTypes";
|
||||
|
||||
export function useEntitySessionState() {
|
||||
const [persistedEntities, setPersistedEntities] = useState<Entity[]>([]);
|
||||
const [pendingEntityCreates, setPendingEntityCreates] = useState<PendingEntityCreate[]>([]);
|
||||
const [createdEntities, setCreatedEntities] = useState<CreatedEntitySummary[]>([]);
|
||||
const [entityStatus, setEntityStatus] = useState<string | null>(null);
|
||||
const [selectedFeatureId, setSelectedFeatureId] = useState<FeatureId | null>(null);
|
||||
const [entityForm, setEntityForm] = useState<EntityFormState>({
|
||||
name: "",
|
||||
slug: "",
|
||||
type_id: DEFAULT_ENTITY_TYPE_ID,
|
||||
});
|
||||
const [selectedGeometryEntityIds, setSelectedGeometryEntityIds] = useState<string[]>([]);
|
||||
const [geometryMetaForm, setGeometryMetaForm] = useState<GeometryMetaFormState>({
|
||||
time_start: "",
|
||||
time_end: "",
|
||||
binding: "",
|
||||
});
|
||||
const [isEntitySubmitting, setIsEntitySubmitting] = useState(false);
|
||||
const [entityFormStatus, setEntityFormStatus] = useState<string | null>(null);
|
||||
const [entitySearchQuery, setEntitySearchQuery] = useState("");
|
||||
const [entitySearchResults, setEntitySearchResults] = useState<Entity[]>([]);
|
||||
const [selectedSearchEntityId, setSelectedSearchEntityId] = useState<string | null>(null);
|
||||
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,
|
||||
};
|
||||
}
|
||||
74
lib/editor/session/useSectionSessionState.ts
Normal file
74
lib/editor/session/useSectionSessionState.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import type { Dispatch, SetStateAction } from "react";
|
||||
import type { EditorSnapshot, Section, SectionCommit, SectionState } from "@/types/sections";
|
||||
|
||||
type Options = {
|
||||
defaultEditorUserId: string;
|
||||
};
|
||||
|
||||
type SectionTask = "idle" | "saving" | "submitting" | "opening-section";
|
||||
|
||||
export function useSectionSessionState(options: Options) {
|
||||
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]);
|
||||
|
||||
const [availableSections, setAvailableSections] = useState<Section[]>([]);
|
||||
const [selectedSectionId, setSelectedSectionId] = useState("");
|
||||
const [newSectionTitle, setNewSectionTitle] = useState("");
|
||||
const [commitTitle, setCommitTitle] = useState("");
|
||||
const [commitNote, setCommitNote] = useState("");
|
||||
const [editorUserIdInput, setEditorUserIdInput] = useState(options.defaultEditorUserId);
|
||||
const [activeSection, setActiveSection] = useState<Section | null>(null);
|
||||
const [sectionState, setSectionState] = useState<SectionState | null>(null);
|
||||
const [sectionCommits, setSectionCommits] = useState<SectionCommit[]>([]);
|
||||
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,
|
||||
};
|
||||
}
|
||||
45
lib/editor/session/useTimelineState.ts
Normal file
45
lib/editor/session/useTimelineState.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { useState } from "react";
|
||||
import type { TimelineRange } from "@/lib/editor/session/sessionTypes";
|
||||
|
||||
type Options = {
|
||||
currentYear: number;
|
||||
fallbackTimelineRange: TimelineRange;
|
||||
};
|
||||
|
||||
export function useTimelineState(options: Options) {
|
||||
const [timelineYear, setTimelineYear] = useState<number>(() =>
|
||||
clampYearValue(
|
||||
options.currentYear,
|
||||
options.fallbackTimelineRange.min,
|
||||
options.fallbackTimelineRange.max
|
||||
)
|
||||
);
|
||||
const [timelineDraftYear, setTimelineDraftYear] = useState<number>(() =>
|
||||
clampYearValue(
|
||||
options.currentYear,
|
||||
options.fallbackTimelineRange.min,
|
||||
options.fallbackTimelineRange.max
|
||||
)
|
||||
);
|
||||
const [isTimelineLoading, setIsTimelineLoading] = useState(false);
|
||||
const [timelineStatus, setTimelineStatus] = useState<string | null>(null);
|
||||
|
||||
return {
|
||||
timelineYear,
|
||||
setTimelineYear,
|
||||
timelineDraftYear,
|
||||
setTimelineDraftYear,
|
||||
isTimelineLoading,
|
||||
setIsTimelineLoading,
|
||||
timelineStatus,
|
||||
setTimelineStatus,
|
||||
};
|
||||
}
|
||||
|
||||
function clampYearValue(year: number, minYear: number, maxYear: number): number {
|
||||
const lower = Math.min(minYear, maxYear);
|
||||
const upper = Math.max(minYear, maxYear);
|
||||
if (year < lower) return lower;
|
||||
if (year > upper) return upper;
|
||||
return year;
|
||||
}
|
||||
Reference in New Issue
Block a user