import { useEffect, useRef, useState, type FormEvent } from "react"; import type { CreateDocumentInput, RecordKind, } from "../../../contracts/studio/contract.ts"; import { createLocalId } from "../../../domain/studio/local-id.ts"; import { useStudio } from "../use-studio.ts"; const types = [ { kind: "CASE", title: "Case", description: "문제를 재현하고 검증한 결론을 기록합니다.", fields: "문제 · 결론 · 환경 · 재현 · 본문", }, { kind: "REFERENCE", title: "Reference", description: "반복해서 적용할 기술 기준을 정리합니다.", fields: "목적 · 규칙 · 적용 조건 · 예외 · 예시", }, { kind: "QUESTION", title: "Question", description: "아직 닫히지 않은 판단과 다음 검증을 관리합니다.", fields: "상태 · 사실 · 가정 · 미지수 · 선택지", }, { kind: "PROJECT_DECISION", title: "Decision", description: "프로젝트가 선택한 방향과 그 근거·영향을 기록합니다.", fields: "상태 · 결정일 · 결정문 · 판단 이유 · 영향 · 근거", }, ] as const; function emptyDocument(kind: RecordKind): CreateDocumentInput { const common = { title: "", slug: "" as const, summary: "", topicId: null, projectId: null, relations: [], }; if (kind === "CASE") { return { ...common, kind, problem: "", conclusion: "", environment: "", reproduction: "", lastVerifiedOn: null, bodyMarkdown: "", }; } if (kind === "REFERENCE") { return { ...common, kind, purpose: "", rules: [], applyWhen: [], exceptions: [], examples: [], verifiedOn: null, }; } if (kind === "QUESTION") { return { ...common, kind, questionStatus: null, facts: [], assumptions: [], unknowns: [], constraints: [], options: [], nextValidation: "", resolution: null, }; } return { ...common, kind, decisionStatus: null, decidedOn: null, statement: "", rationale: "", consequences: [], }; } function isAbortError(error: unknown): boolean { return error instanceof DOMException && error.name === "AbortError"; } export function NewDocumentForm() { const { gateway, navigateInternal, setRequestAnnouncement } = useStudio(); const [kind, setKind] = useState("CASE"); const [pending, setPending] = useState(false); const [error, setError] = useState(""); const locked = useRef(false); const activeRequest = useRef(null); useEffect(() => () => activeRequest.current?.abort(), []); const submit = async (event: FormEvent) => { event.preventDefault(); if (locked.current) return; locked.current = true; setPending(true); setError(""); const controller = new AbortController(); activeRequest.current = controller; try { const document = await gateway.createDocument(emptyDocument(kind), { idempotencyKey: createLocalId("studio-create"), signal: controller.signal, }); setRequestAnnouncement( `${types.find((type) => type.kind === kind)?.title} 작업본을 만들었습니다.`, ); navigateInternal(`/studio/documents/${document.id}/edit`); } catch (reason) { if (!isAbortError(reason)) { setError("작업본을 만들지 못했습니다. 다시 시도해 주세요."); } } finally { if (activeRequest.current === controller) activeRequest.current = null; locked.current = false; setPending(false); } }; return (

NEW WORKING COPY

새 문서

목적에 맞는 기록 종류를 선택하면 빈 작업본을 만들고 바로 편집을 시작합니다.

{ void submit(event); }} >
문서 종류 {types.map((type) => ( ))}

이 화면의 작업본은 현재 Studio 세션에서만 유지됩니다.

{error ? (

{error}

) : null}
); }