/* ============================================================================= * B05_Profile_UI_RouteEdit_Initial.ts * 계획노선 편집의 **지금 추천 이음**(계획서 20 · 23-2 · 626-1) — [저장]에 실을 지금 추천 · 편집 걸음 짝. * * 추천 고르기(옛 좌측 「노선 추천」 칸 · 모달 · [적용] = `as_initial`)는 걷음(626-1 · 요구 530 · 결정 D1 · D8) — * 추천은 평면 도구줄 미리보기(`_RecPreview`)만 · 초기값 = 예정노선 추적(자동설계 체인 · [초기화] 그대로). * 지금 추천 = 서버가 적어 둔 것(`current_initial` · 없으면 예정노선 추적) · 옛 캐시(`routeedit-initial`)는 * 서버와 같을 때만 남음 · [저장]은 그 값 그대로 실음(서버 `initial_choice.json`). * ========================================================================== */ import type { RouteInitialCriteria, RouteInitialLogic, RouteInitialWeights, } from "./B05_Profile_Api_RouteInitial"; import type { RouteEditSnapshot } from "./B05_Profile_UI_RouteEdit_History"; import { choiceWithProfile, readInitialChoice, sameBase, serverBase, writeInitialChoice, type InitialBase, type InitialChoice, } from "./B05_Profile_UI_RouteEdit_Initial_Model"; export interface InitialPanelParams { projectId: string; } export interface InitialPanel { /** 노선을 읽었다 — 창을 연 편집값 · 서버가 적어 둔 현재 초기값(`current_initial`). */ ready: (opening: RouteEditSnapshot, server?: unknown) => void; /** [저장]에 실어 보낼 지금 추천. */ current: () => { mode: RouteInitialLogic; weights: RouteInitialWeights | null; criteria: RouteInitialCriteria | null; with_profile: boolean; }; /** 지금 노선이 종단을 반영하는가 — 지금 추천의 「종단 반영」 값(421 · 옛 기록이면 갈래로). * 종단 띠 · [확인]이 함께 본다(추천을 손으로 고쳤어도 그 값대로). */ withProfile: () => boolean; /** 지금 추천 — 편집 걸음(사진)에 실어 둔다. 되돌리기 · 다시하기가 `restoreTag` 로 되살린다. */ tag: () => InitialChoice | null; restoreTag: (tag: unknown) => void; /** [취소] — 이 창에서 바꾼 추천을 창을 열 때 것으로 되돌린다. */ cancel: () => void; /** [확인] 뒤 결과 캐시를 비웠다 — 추천은 새 노선의 출발점이라 다시 적는다. */ keep: () => void; } export function createInitialPanel(params: InitialPanelParams): InitialPanel { const { projectId } = params; /** 창을 열 때 캐시에 있던 추천 — [취소]가 돌아갈 자리. */ let openingChoice = readInitialChoice(projectId); let choice: InitialChoice | null = openingChoice; /** 노드 없이 이름만 아는 현재 추천 — 서버가 적어 둔 것(없으면 예상노선 추적). */ let base: InitialBase = { logic: "follow", weights: null, criteria: null }; return { ready(_snapshot, server) { // 「현재 추천」은 서버가 [확인] 때 적어 둔 것이 정본이다 — 캐시가 다르면(확인 없이 닫음) // 캐시를 버린다. if (server) { base = serverBase(server); if (choice && !sameBase(choice, base)) choice = null; openingChoice = choice; writeInitialChoice(projectId, choice); } }, current: () => { const now = choice ?? base; const criteria = choice ? choice.criteriaOverrides : base.criteria; return { mode: now.logic, weights: now.weights, criteria, with_profile: choiceWithProfile(now), }; }, withProfile: () => choiceWithProfile(choice ?? base), tag: () => choice, restoreTag(tag) { if (tag === undefined) return; // 추천을 안 실은 옛 걸음 — 그대로 둔다. choice = tag as InitialChoice | null; writeInitialChoice(projectId, choice); }, cancel: () => writeInitialChoice(projectId, openingChoice), keep: () => writeInitialChoice(projectId, choice), }; }