Phase 10: field editor (FR-14)
เพิ่ม editor ต่อ template field — ผู้ดูแลเลือกรูปแบบช่องกรอกในฟอร์มสร้างเอกสารได้: text → textbox/textarea, number/date → control ตาม type (presentation metadata ล้วน — validation ยังยึด Type, ค่า field เป็น string ทั้ง flow, ไม่แตะ generate/sync/add-in) - Backend: TemplateField.Editor (nullable, null = default ของ type) + migration AddTemplateFieldEditor + validate ตาม type ใน PUT templates (ค่าไม่รู้จัก/ไม่เข้ากับ type → 400, normalize-on-write, API คืน resolved เสมอ) - Web: util fieldEditor.ts + editor select หน้าแก้ template (desktop+mobile, ซ่อนเมื่อ type มีทางเดียว) + ฟอร์มสร้างเอกสาร render ตาม editor + แก้ prefill re-generate ของ field date จาก ISO timestamp เต็ม (input[type=date] รับเฉพาะ yyyy-MM-dd เดิมแสดงว่าง) - Docs: spec v6 (FR-14/AC-17) + plan Phase 10 + sub-plan field-editor.md + acceptance-review AC-17 + README/CLAUDE.md - Tests: backend 60/60 (FieldEditorTests ใหม่ 8 กรณี) · web 46/46 + build ผ่าน Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
7b20f12ede
commit
9bb4a48c00
23 changed files with 865 additions and 45 deletions
43
web/app/utils/fieldEditor.ts
Normal file
43
web/app/utils/fieldEditor.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* Editor (รูปแบบช่องกรอก) ต่อ template field (FR-14) — pure util ให้ unit test ได้
|
||||
* มิเรอร์ allow-list ของ backend (TemplateField.EditorsByType): text เลือก textbox/textarea ได้,
|
||||
* number/date มีทางเดียวตาม type — เป็น presentation metadata เท่านั้น (validation ของค่ายังยึด type)
|
||||
*/
|
||||
|
||||
import type { FieldEditor } from '~/types/api'
|
||||
|
||||
export const EDITORS_BY_TYPE: Record<string, FieldEditor[]> = {
|
||||
text: ['textbox', 'textarea'],
|
||||
number: ['number'],
|
||||
date: ['date'],
|
||||
}
|
||||
|
||||
/** editor เริ่มต้นของ type (ตัวแรกของรายการ) — type ที่ไม่รู้จัก → textbox */
|
||||
export function defaultEditor(type: string): FieldEditor {
|
||||
return EDITORS_BY_TYPE[type]?.[0] ?? 'textbox'
|
||||
}
|
||||
|
||||
/** ตัวเลือก editor ที่เลือกได้ตาม type — ใช้ซ่อน select เมื่อมีทางเดียว (number/date) */
|
||||
export function editorOptions(type: string): FieldEditor[] {
|
||||
return EDITORS_BY_TYPE[type] ?? ['textbox']
|
||||
}
|
||||
|
||||
/**
|
||||
* หา editor ที่จะใช้ render จริงจาก field — editor ที่ถูกต้องตาม type → ใช้ค่านั้น,
|
||||
* ไม่มี/ไม่รู้จัก/ไม่เข้ากับ type → default ของ type (degrade อ่อนโยน ไม่ throw)
|
||||
*/
|
||||
export function resolveEditor(field: { type: string; editor?: string | null }): FieldEditor {
|
||||
const options = EDITORS_BY_TYPE[field.type] ?? ['textbox']
|
||||
return options.includes(field.editor as FieldEditor)
|
||||
? (field.editor as FieldEditor)
|
||||
: options[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* ค่าวันที่สำหรับ input[type=date] — รับเฉพาะรูป yyyy-MM-dd เท่านั้น
|
||||
* ค่าจาก field sync ของ Word อาจเป็น ISO timestamp เต็ม (backend parse ได้ตาม FR-10) → ตัดเอาส่วนวันที่
|
||||
* ค่าอื่นที่ไม่ใช่รูป ISO → คงเดิม ให้ validation ของฟอร์มจัดการต่อ
|
||||
*/
|
||||
export function dateInputValue(value: string): string {
|
||||
return /^\d{4}-\d{2}-\d{2}/.test(value) ? value.slice(0, 10) : value
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue