Files
Aislo/A00_Common/design/design_pipeline_facilities.ts
T
eomsangdonandClaude Opus 5.5 a3815bfaa1 fix(472-5 겹침 정리): 되돌리기 알림 한 벌 — 관 · 구조물 = 가게 알림 한 번 · 추가 측점 = 자기 훅 · 묶음 = 출처마다 한 번
- announceDesignStore = 관 · 구조물만(추가 측점은 _Api_PlusStations 훅이 이미 알림 · 페이지 설정은 5-C 훅)
- 계산 묶음 먹이기 — 되돌리는 동안 구독은 안 받음(되살림 훅 한 길) · 묶음 입력과 같은 값 다시 알림은 안 넣음
  (옛: 추가 측점 되돌리기에 묶음 두 번)
- 시험 test_472_5_shop_owner 알림 수(옛 코드 실패 확인) · helper_429 가짜 묶음이 받은 값을 입력으로(까닭: 실제 묶음과 같게)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 10:06:03 +09:00

80 lines
3.7 KiB
TypeScript

/* =============================================================================
* A00_Common/design/design_pipeline_facilities.ts
* 계산 묶음 관 · 구조물 · 추가 측점 먹이기(PLAN 415 · 429 ⑨) — 가게 초안이 바뀌면 묶음에 넣음(비면 저장분).
* · [저장] 도중 = 안 넣음(H2) — 초안이 비는 사이 열 때 읽은 옛 저장분으로 돌지 않게 · 끝나면 `resync`
* (저장 목록 다시 읽기 · 입력 맞춤) 한 번.
* · 되돌리기 · 다시하기 = 아래 되살림 훅 한 길 — 묶음 입력과 견줘 다르면 넣음(415-2 · 노선 초안은 노선 길이
* 맡음) · 그 사이 가게 알림(`announceDesignStore` · 472-5)은 구독이 받지 않음(두 번 안 넣음).
* 저장 창구는 늦게 불러옴(묶음 시험이 화면 모듈을 안 끌게).
* ========================================================================== */
import { onPageHistory, pageReplaying } from "../../B05_Profile/B05_Profile_UI_Profile_History";
import type { useDesignStore } from "./design_store";
import type { ChangeSource } from "./logic/design_pipeline_types";
type Key = "pipes" | "structures" | "plusStations";
const FACILITIES: ReadonlyArray<{ source: ChangeSource; key: Key }> = [
{ source: "pipe", key: "pipes" },
{ source: "structure", key: "structures" },
{ source: "plus", key: "plusStations" },
];
export interface FacilityFeed {
saving(): boolean;
/** 저장이 끝나면 `resync` 한 번 — 기다리는 동안 다시 불러도 한 번. */
afterSave(): void;
stop(): void;
}
export function feedFacilities(o: {
projectId: string;
store: ReturnType<typeof useDesignStore>;
/** 묶음이 받을 때인가(열었음 · 묶음이 가게에 쓰는 메아리 아님). */
ready: () => boolean;
gone: () => boolean;
saved: (key: Key) => unknown;
input: (key: Key) => unknown;
/** 노선 초안이 걸렸나 — 되돌리기는 노선 길이 맡음. */
routed: () => boolean;
feed: (source: ChangeSource, value: unknown) => void;
resync: () => Promise<unknown>;
}): FacilityFeed {
let savingOf: ((id: string) => boolean) | null = null;
// 한 번 불러 봄 — 덜 선 모듈(시험 싣개의 고리)은 안 받음
void import("./design_save")
.then((m) => (m.savingDesign(o.projectId), (savingOf = m.savingDesign)))
.catch(() => undefined);
const saving = (): boolean => savingOf?.(o.projectId) ?? false;
let waiting: Promise<void> | null = null;
const afterSave = (): void => {
waiting ??= (async () => {
// ponytail: 100 ms 마다 물음 — 저장 끝 알림이 생기면 그것으로
while (saving() && !o.gone()) await new Promise((done) => setTimeout(done, 100));
if (!o.gone()) await o.resync();
})().finally(() => (waiting = null));
};
const put = (source: ChangeSource, value: unknown): void =>
saving() ? afterSave() : o.feed(source, value);
const stops = [
...FACILITIES.map(({ source, key }) =>
o.store.subscribe(key, (value) => {
const now = value ?? o.saved(key);
// 묶음 입력과 같은 값 = 이미 받음(되살림 뒤 추가 측점 다시 알림 등) — 한 번만 넣음(472-5)
if (!o.ready() || pageReplaying() || JSON.stringify(now) === JSON.stringify(o.input(key)))
return;
put(source, now);
}),
),
onPageHistory({
restore: () => {
if (!o.ready() || o.routed()) return;
for (const { source, key } of FACILITIES) {
const now = o.store.get(key) ?? o.saved(key);
if (JSON.stringify(now) !== JSON.stringify(o.input(key))) put(source, now);
}
},
}),
];
return { saving, afterSave, stop: () => stops.forEach((stop) => stop()) };
}