/* ============================================================================= * M02_MasterTemplete_Api_Fetch.ts * 마스터 템플릿 서버 호출 — 계약 `6_계약.md` 서버 길 · 시스템 층은 시스템 관리자만 * ========================================================================== */ import { API_BASE_URL } from "@config/config_frontend"; /** 층 이름 — 서버와 같은 글 */ export type Layer = "system" | "company" | "personal" | "project"; /** 서버 종류 — 화면의 「표 양식」 = table · 「도면 양식」 = drawing */ export type Kind = "table" | "drawing"; export interface TemplateInfo { 종류: Kind; 이름: string; 판: string; 수정일: string; } export interface TemplateDoc { 종류: Kind; 이름: string; /** 프로젝트 층에서 작업본이 아직 없으면(옛 프로젝트) 시스템 양식이 와서 null */ 판: string | null; 문서: unknown; } /** 서버가 판 불일치로 막았을 때 */ export class StaleError extends Error {} async function call(path: string, init: RequestInit = {}): Promise { const response = await fetch(`${API_BASE_URL}/m02${path}`, { credentials: "include", headers: { "Content-Type": "application/json" }, ...init, }); const body = (await response.json().catch(() => ({}))) as { detail?: unknown } & T; if (response.status === 409) throw new StaleError(String(body.detail ?? "409")); if (!response.ok) { const detail = body.detail; throw new Error(typeof detail === "string" ? detail : `HTTP ${response.status}`); } return body; } const enc = encodeURIComponent; const q = (projectId: string | null): string => (projectId ? `?project_id=${enc(projectId)}` : ""); const head = (layer: Layer): string => layer === "system" ? "/templates" : `/layers/${layer}/templates`; const item = (layer: Layer, kind: Kind, name: string, projectId: string | null): string => `${head(layer)}/${kind}/${enc(name)}${layer === "system" ? "" : q(projectId)}`; /** 시스템 길은 배열 · 층 길은 `{층, 양식: [...]}` — 둘 다 목록으로 */ export const listTemplates = async ( layer: Layer, projectId: string | null, ): Promise => { const got = await call( layer === "system" ? head(layer) : `${head(layer)}${q(projectId)}`, ); return Array.isArray(got) ? got : got.양식; }; export const readTemplate = ( layer: Layer, kind: Kind, name: string, projectId: string | null, ): Promise => call(item(layer, kind, name, projectId)); export const saveTemplate = ( layer: Layer, kind: Kind, name: string, projectId: string | null, 판: string, 문서: unknown, ): Promise => call(item(layer, kind, name, projectId), { method: "PUT", body: JSON.stringify({ 판, 문서 }) }); /** 시스템 층만 지움 */ export const deleteTemplate = (kind: Kind, name: string, 판: string): Promise<{ ok: boolean }> => call(`/templates/${kind}/${enc(name)}?판=${enc(판)}`, { method: "DELETE" }); /* --- 프로젝트 층 단추 다섯 --- */ const project = (id: string, tail: string): string => `/projects/${enc(id)}/templates/${tail}`; const post = (path: string, body: object = {}): Promise => call(path, { method: "POST", body: JSON.stringify(body) }); export const resetProject = (id: string): Promise => post(project(id, "reset")); export const applyToProject = ( id: string, from: { from: Layer; user_id?: string; project_id?: string; 종류?: Kind; 이름?: string }, ): Promise => post(project(id, "apply"), from); export const saveProjectAs = ( id: string, to: "personal" | "company", 종류: Kind, 이름: string, ): Promise => post(project(id, "save-as"), { to, 종류, 이름 }); export const fetchSources = (id: string): Promise => call(`/projects/${enc(id)}/sources`); /** 설계값을 채운 표 문서 — 서버가 그때그때 채움 · 저장 안 함 */ export const readFilled = (id: string, name: string): Promise => call(`/projects/${enc(id)}/tables/${enc(name)}/filled`);