/* ============================================================================= * B05_Profile_UI_Drainage_Saved.ts * 저장 배수유역 다시 받기(열 때 · 초안 버림 · 되돌리기) — 패널 본체가 700줄이라 나눔(520-7). * * - 세션 관 초안이 있으면 그 관 목록으로 세부유역(저장 안 함) · 없으면 저장분 GET. * - 되돌리기 한 번에 셋(관 자리 되돌림 · 시설 따라감 `reload` · 묶음 초안 버림)이 같이 부름 — * 떠 있는 받기가 있으면 그 답을 같이 씀(모두 같은 「올렸나」를 받음). * - 마지막 저장분 답 · 그 답을 실은 뒤 요청 몸통 — 화면이 그 답 그대로(뒤에 다른 답이 안 올랐고 관 * 목록 같음)면 관 자리 되돌림은 건너뜀(472 덧) · 초안 버림(`back`)은 그 답을 다시 올림(GET 없음 · * 낡음 표시만 다시 셈). `reload` 는 늘 받음(B06 관 쓰기 · [확정] 뒤). * ========================================================================== */ import { computeDetailBasins, fetchDetailPipePoints, type DetailBasinResponse, type DetailPipeInput, } from "../B04_PreProcess/B04_PreProcess_Api_Fetch"; import { readPendingPipes } from "./B05_Profile_Api_Pipes_Draft"; import type { DetailRunner } from "./B05_Profile_UI_Drainage_Run"; export interface SavedLoader { /** 저장분(세션 초안이 있으면 그 관 목록) 받기 — 답을 화면에 올렸으면 true. */ run(quiet?: boolean): Promise; /** 초안 버림 — 화면이 마지막 저장분 그대로면 그 답을 다시 올림(GET 없음) · 아니면 `run`. */ back(): Promise; /** 답이 화면에 오른 뒤 — 저장분 답이면 그때 요청 몸통을 적어 둠 · 아니면 「화면 ≠ 저장분」. */ applied(response: DetailBasinResponse): void; /** 화면이 마지막 저장분 답 그대로이고 지금 요청 몸통도 같은가. */ matches(): boolean; /** 프로젝트가 바뀜 — 옛 저장분 잊음. */ reset(): void; } export function createSavedLoader( runner: DetailRunner, pipeRequest: () => DetailPipeInput[], ): SavedLoader { let saved: { response: DetailBasinResponse; request: string | null } | null = null; let inflight: Promise | null = null; /** 마지막으로 화면에 오른 답이 `saved.response` 인가. */ let showing = false; const load = (projectId: string): Promise => { const pending = readPendingPipes(projectId); return pending !== null // 빈 목록 = 다 지움(관 0개 · 312) — 저장분으로 안 넘어감 ? computeDetailBasins(projectId, pending) : fetchDetailPipePoints(projectId).then( (response) => ((saved = { response, request: null }), response), ); }; const matches = (): boolean => showing && !!saved && JSON.stringify(pipeRequest()) === saved.request; const run = (quiet = false): Promise => { const projectId = runner.projectId(); if (!projectId) return Promise.resolve(false); // ponytail: 떠 있는 동안 온 부름은 그 답을 같이 — 그 사이 서버 쓰기(B06 관 쓰기 뒤 reload)는 // 다음 부름까지 안 보임. 잦아지면 쓰기 뒤 부름만 새로 받게 표시를 넘김. inflight ??= runner.run(() => load(projectId), quiet).finally(() => (inflight = null)); return inflight; }; return { run, back() { if (inflight || !matches()) return run(true); const response = saved!.response; // 뒤이어 온 받기(`reload`)가 이 답을 밀어내면 그 답을 기다림 — 「안 올림」으로 낡음이 남지 않게. return runner .run(() => Promise.resolve(response), true) .then((applied) => applied || (inflight ?? Promise.resolve(false))); }, applied(response) { showing = saved?.response === response; if (showing) saved!.request = JSON.stringify(pipeRequest()); }, matches, reset() { saved = null; showing = false; }, }; }