/** * Create-desc gate (Call 2): disable Create desc unless these are present. * Does NOT require short_description, description, or price — Call 2 writes * short + long; price stays publish-only. */ export type CreateDescInput = { contentLlmEnabled: boolean; title: string; speciesId: number | null | undefined; woodCategoryIds: number[]; primaryCatId: number | '' | null | undefined; edgeTermId: number | string | '' | null | undefined; figureTermIds: number[]; gradeTermId: number | string | '' | null | undefined; moistureTermId: number | string | '' | null | undefined; }; /** Human labels shown under Create desc when the gate fails. */ export const CREATE_DESC_LABELS: Record = { content_llm: 'content LLM on', title: 'title', species: 'species', wood_categories: '≥1 wood category', primary: 'primary wood category', edge: 'edge type', figure: '≥1 figure', grade: 'grade', moisture: 'moisture', }; function presentId(v: number | string | '' | null | undefined): boolean { if (v === null || v === undefined || v === '') return false; if (typeof v === 'number') return Number.isFinite(v); return String(v).trim() !== ''; } /** Return missing field keys (stable order). Empty ⇒ Create desc enabled. */ export function missingCreateDesc(input: CreateDescInput): string[] { const missing: string[] = []; if (!input.contentLlmEnabled) missing.push('content_llm'); if (!String(input.title ?? '').trim()) missing.push('title'); if (input.speciesId == null || !Number.isFinite(Number(input.speciesId))) missing.push('species'); if (!input.woodCategoryIds?.length) missing.push('wood_categories'); if (!presentId(input.primaryCatId)) missing.push('primary'); if (!presentId(input.edgeTermId)) missing.push('edge'); if (!input.figureTermIds?.length) missing.push('figure'); if (!presentId(input.gradeTermId)) missing.push('grade'); if (!presentId(input.moistureTermId)) missing.push('moisture'); return missing; } export function canCreateDesc(input: CreateDescInput): boolean { return missingCreateDesc(input).length === 0; } export function missingCreateDescLabels(input: CreateDescInput): string[] { return missingCreateDesc(input).map((k) => CREATE_DESC_LABELS[k] ?? k); }