2026-09-15 14:12:51 +07:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
// N4 — ฟอร์มอัปโหลดไฟล์เอกสารแบบง่ายบนหน้ารายการ (PDF/รูป รับพร้อมกัน)
|
|
|
|
|
// เสร็จแล้วรายการโผล่เองจาก revalidatePath("/") ของ action
|
|
|
|
|
import { useState, useTransition } from "react";
|
|
|
|
|
|
|
|
|
|
import { uploadFile } from "@/app/actions/files";
|
|
|
|
|
|
|
|
|
|
const ACCEPT = ".pdf,.jpg,.jpeg,.png,.tif,.tiff";
|
|
|
|
|
|
UX audit ทั้งแอป + typography audit 2026-09-16: toast แจ้ง error การบันทึก (H1 — เดิมรายการหายเงียบ + ReplyBox เก็บ draft ตอน fail), คำเตือน redaction แสดงทุกขนาดจอ (H2), toolbar แสดงชื่อ tool active + aria-pressed บนจอสัมผัส (H3/M9), ปุ่ม popover จิ้มง่าย 36px + focus ring เติมครบ (H4) + M1-M9 (ปิด sidebar ตอน navigate, bookmark หัวแถวจอเล็ก, hint โหมดมาร์กบนจอสัมผัส, การ์ดหน้ารายการคลิกได้ทั้งใบ, เช็ค 100MB ฝั่ง client, feedback ✓/pending ตอนบันทึก bookmark, dropdown วางที่ sort ตามหน้า+เลขหน้า, slate-500 แทน slate-400) + webfont Sarabun ผ่าน next/font self-host 400/600 (Option B — แสดงผลตรงกันทุกอุปกรณ์ รวม TEXTBOX ที่ผูก stack นี้) + NumberCombo preset เป็น chips แทน dropdown ล้นเมนู (L2) + leading-relaxed/13px ข้อความไทยที่ wrap + tabular-nums + prefers-reduced-motion (L7) + L1/L4/L5 + แถว bookmark แสดงชื่อผู้บันทึกเหมือนผลการค้นหา
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-16 14:28:53 +07:00
|
|
|
/** ขนาดสูงสุดตาม validator ของ uploadFile (app/actions/files.ts) — เช็คฝั่ง client
|
|
|
|
|
* ก่อนอัปโหลด (M5, UX audit 2026-09-16): ไฟล์สแกนคดีที่เกินไม่ต้องรอส่งจนจบ
|
|
|
|
|
* บนเน็ตช้าก่อนเจอ error ของ server */
|
|
|
|
|
const MAX_BYTES = 100 * 1024 * 1024;
|
|
|
|
|
|
2026-09-15 14:12:51 +07:00
|
|
|
export default function UploadFileForm() {
|
|
|
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
|
const [pending, startTransition] = useTransition();
|
|
|
|
|
|
|
|
|
|
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
const form = e.currentTarget;
|
|
|
|
|
setError(null);
|
UX audit ทั้งแอป + typography audit 2026-09-16: toast แจ้ง error การบันทึก (H1 — เดิมรายการหายเงียบ + ReplyBox เก็บ draft ตอน fail), คำเตือน redaction แสดงทุกขนาดจอ (H2), toolbar แสดงชื่อ tool active + aria-pressed บนจอสัมผัส (H3/M9), ปุ่ม popover จิ้มง่าย 36px + focus ring เติมครบ (H4) + M1-M9 (ปิด sidebar ตอน navigate, bookmark หัวแถวจอเล็ก, hint โหมดมาร์กบนจอสัมผัส, การ์ดหน้ารายการคลิกได้ทั้งใบ, เช็ค 100MB ฝั่ง client, feedback ✓/pending ตอนบันทึก bookmark, dropdown วางที่ sort ตามหน้า+เลขหน้า, slate-500 แทน slate-400) + webfont Sarabun ผ่าน next/font self-host 400/600 (Option B — แสดงผลตรงกันทุกอุปกรณ์ รวม TEXTBOX ที่ผูก stack นี้) + NumberCombo preset เป็น chips แทน dropdown ล้นเมนู (L2) + leading-relaxed/13px ข้อความไทยที่ wrap + tabular-nums + prefers-reduced-motion (L7) + L1/L4/L5 + แถว bookmark แสดงชื่อผู้บันทึกเหมือนผลการค้นหา
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-16 14:28:53 +07:00
|
|
|
const input = form.elements.namedItem("file") as HTMLInputElement | null;
|
|
|
|
|
const file = input?.files?.[0];
|
|
|
|
|
if (file && file.size > MAX_BYTES) {
|
|
|
|
|
setError("ไฟล์ใหญ่เกิน 100MB — เลือกไฟล์เล็กกว่า");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-09-15 14:12:51 +07:00
|
|
|
startTransition(async () => {
|
|
|
|
|
try {
|
|
|
|
|
const result = await uploadFile(new FormData(form));
|
|
|
|
|
if (result.ok) {
|
|
|
|
|
form.reset();
|
|
|
|
|
} else {
|
|
|
|
|
setError(result.error);
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// action fail ที่ระดับ transport (เช่น body ใหญ่เกิน bodySizeLimit ของ next.config)
|
|
|
|
|
setError("อัปโหลดไม่สำเร็จ — ลองใหม่อีกครั้ง");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<form
|
|
|
|
|
onSubmit={onSubmit}
|
|
|
|
|
className="mt-3 flex flex-wrap items-center gap-2 rounded-xl border border-dashed border-slate-300 bg-white/60 p-4"
|
|
|
|
|
>
|
|
|
|
|
<input
|
|
|
|
|
type="file"
|
|
|
|
|
name="file"
|
|
|
|
|
accept={ACCEPT}
|
|
|
|
|
required
|
|
|
|
|
disabled={pending}
|
UX audit ทั้งแอป + typography audit 2026-09-16: toast แจ้ง error การบันทึก (H1 — เดิมรายการหายเงียบ + ReplyBox เก็บ draft ตอน fail), คำเตือน redaction แสดงทุกขนาดจอ (H2), toolbar แสดงชื่อ tool active + aria-pressed บนจอสัมผัส (H3/M9), ปุ่ม popover จิ้มง่าย 36px + focus ring เติมครบ (H4) + M1-M9 (ปิด sidebar ตอน navigate, bookmark หัวแถวจอเล็ก, hint โหมดมาร์กบนจอสัมผัส, การ์ดหน้ารายการคลิกได้ทั้งใบ, เช็ค 100MB ฝั่ง client, feedback ✓/pending ตอนบันทึก bookmark, dropdown วางที่ sort ตามหน้า+เลขหน้า, slate-500 แทน slate-400) + webfont Sarabun ผ่าน next/font self-host 400/600 (Option B — แสดงผลตรงกันทุกอุปกรณ์ รวม TEXTBOX ที่ผูก stack นี้) + NumberCombo preset เป็น chips แทน dropdown ล้นเมนู (L2) + leading-relaxed/13px ข้อความไทยที่ wrap + tabular-nums + prefers-reduced-motion (L7) + L1/L4/L5 + แถว bookmark แสดงชื่อผู้บันทึกเหมือนผลการค้นหา
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-16 14:28:53 +07:00
|
|
|
className="block w-full max-w-xs text-sm text-slate-600 file:mr-3 file:cursor-pointer file:rounded-md file:border-0 file:bg-primary/10 file:px-4 file:py-2 file:text-sm file:font-medium file:text-primary"
|
2026-09-15 14:12:51 +07:00
|
|
|
/>
|
|
|
|
|
<button
|
|
|
|
|
type="submit"
|
|
|
|
|
disabled={pending}
|
UX audit ทั้งแอป + typography audit 2026-09-16: toast แจ้ง error การบันทึก (H1 — เดิมรายการหายเงียบ + ReplyBox เก็บ draft ตอน fail), คำเตือน redaction แสดงทุกขนาดจอ (H2), toolbar แสดงชื่อ tool active + aria-pressed บนจอสัมผัส (H3/M9), ปุ่ม popover จิ้มง่าย 36px + focus ring เติมครบ (H4) + M1-M9 (ปิด sidebar ตอน navigate, bookmark หัวแถวจอเล็ก, hint โหมดมาร์กบนจอสัมผัส, การ์ดหน้ารายการคลิกได้ทั้งใบ, เช็ค 100MB ฝั่ง client, feedback ✓/pending ตอนบันทึก bookmark, dropdown วางที่ sort ตามหน้า+เลขหน้า, slate-500 แทน slate-400) + webfont Sarabun ผ่าน next/font self-host 400/600 (Option B — แสดงผลตรงกันทุกอุปกรณ์ รวม TEXTBOX ที่ผูก stack นี้) + NumberCombo preset เป็น chips แทน dropdown ล้นเมนู (L2) + leading-relaxed/13px ข้อความไทยที่ wrap + tabular-nums + prefers-reduced-motion (L7) + L1/L4/L5 + แถว bookmark แสดงชื่อผู้บันทึกเหมือนผลการค้นหา
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-16 14:28:53 +07:00
|
|
|
className="ml-auto shrink-0 rounded-md bg-primary px-4 py-2.5 text-sm font-medium text-white transition hover:opacity-90 disabled:opacity-50"
|
2026-09-15 14:12:51 +07:00
|
|
|
>
|
|
|
|
|
{pending ? "กำลังอัปโหลด…" : "อัปโหลด"}
|
|
|
|
|
</button>
|
2026-09-16 16:52:08 +07:00
|
|
|
<p className="w-full text-xs text-slate-500">
|
|
|
|
|
รองรับ PDF, JPG, PNG, TIFF — ไม่เกิน 100MB ต่อไฟล์
|
|
|
|
|
</p>
|
2026-09-15 14:12:51 +07:00
|
|
|
{error && <p className="w-full text-xs text-red-600">{error}</p>}
|
|
|
|
|
</form>
|
|
|
|
|
);
|
|
|
|
|
}
|