From 289d735bf3aa9ed832d0cdc2add7889d0e459a0e Mon Sep 17 00:00:00 2001 From: "DESKTOP-1R2VSQH\\Lenovo ThinkPad E490" Date: Thu, 10 Sep 2026 18:02:01 +0700 Subject: [PATCH] =?UTF-8?q?=E0=B9=80=E0=B8=9E=E0=B8=B4=E0=B9=88=E0=B8=A1?= =?UTF-8?q?=E0=B8=95=E0=B8=B1=E0=B8=A7=E0=B9=80=E0=B8=A5=E0=B8=B7=E0=B8=AD?= =?UTF-8?q?=E0=B8=81=20mock=20user=2010=20=E0=B8=84=E0=B8=99=E0=B8=97?= =?UTF-8?q?=E0=B8=B5=E0=B9=88=E0=B8=AB=E0=B8=99=E0=B9=89=E0=B8=B2=E0=B9=81?= =?UTF-8?q?=E0=B8=A3=E0=B8=81=20+=20=E0=B8=9B=E0=B8=A3=E0=B8=B1=E0=B8=9A?= =?UTF-8?q?=E0=B8=AB=E0=B8=99=E0=B9=89=E0=B8=B2=E0=B9=81=E0=B8=A3=E0=B8=81?= =?UTF-8?q?=20+=20select=20=E0=B8=A5=E0=B8=B9=E0=B8=81=E0=B8=A8=E0=B8=A3?= =?UTF-8?q?=E0=B9=80=E0=B8=AD=E0=B8=87=E0=B8=97=E0=B8=B1=E0=B9=88=E0=B8=A7?= =?UTF-8?q?=E0=B9=81=E0=B8=AD=E0=B8=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - utils/user.ts: MOCK_USERS (userId คงที่) + setLocalUser/getStoredLocalUser เขียนลง localStorage key เดิม — PDFViewer อ่าน getLocalUser() เหมือนเดิม - components/UserPicker.tsx: dropdown เลือกผู้ใช้ก่อนเข้า annotate (ยังไม่มี identity = default คนแรก, identity สุ่มเดิมแสดงเป็น option ชั่วคราว) - components/Select.tsx: select ถอดลูกศร native (ชิดขอบ) ใส่ ChevronDown เอง ใช้ที่ UserPicker + ตัวกรองรายคน + เลือกหัวข้อ bookmark 2 จุด - app/page.tsx: header monogram, การ์ดไฟล์ hover, empty state ใหม่ Co-Authored-By: Claude Code --- app/page.tsx | 53 ++++++++++++++----- components/Select.tsx | 19 +++++++ components/UserPicker.tsx | 66 ++++++++++++++++++++++++ components/pdf/PDFViewer.tsx | 5 +- components/sidebar/AnnotationSidebar.tsx | 10 ++-- utils/user.ts | 30 ++++++++++- 6 files changed, 162 insertions(+), 21 deletions(-) create mode 100644 components/Select.tsx create mode 100644 components/UserPicker.tsx diff --git a/app/page.tsx b/app/page.tsx index 011ca7b..ab7a586 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -4,6 +4,7 @@ import { FileText } from "lucide-react"; import { db } from "@/db"; import { files } from "@/db/schema"; +import UserPicker from "@/components/UserPicker"; export const dynamic = "force-dynamic"; @@ -11,29 +12,55 @@ export default async function HomePage() { const rows = await db.select().from(files).orderBy(asc(files.createdAt)); return ( -
-

Jude's Note

-

- ระบบ PDF Annotation สำหรับ e-Court -

+
+
+
+ JN +
+
+

+ Jude's Note +

+

+ ระบบ PDF Annotation สำหรับ e-Court +

+
+
+ + + +
+

เอกสาร

+ {rows.length > 0 && ( + {rows.length} ไฟล์ + )} +
{rows.length === 0 ? ( -

- ยังไม่มีไฟล์ในระบบ — รัน /sync-db เพื่อ seed ไฟล์ตัวอย่าง -

+
+ +

+ ยังไม่มีไฟล์ในระบบ +

+

+ รัน /sync-db เพื่อ seed ไฟล์ตัวอย่าง +

+
) : ( -
    +
      {rows.map((f) => (
    • - +
      + +
      - + {f.title} - + {new Date(f.createdAt).toLocaleString("th-TH")} diff --git a/components/Select.tsx b/components/Select.tsx new file mode 100644 index 0000000..d54ee67 --- /dev/null +++ b/components/Select.tsx @@ -0,0 +1,19 @@ +"use client"; + +// ปกติทุกอย่าง (props/children) +// className ที่ส่งเข้าไปใช้กับตัว + + + ); +} diff --git a/components/UserPicker.tsx b/components/UserPicker.tsx new file mode 100644 index 0000000..1717fa7 --- /dev/null +++ b/components/UserPicker.tsx @@ -0,0 +1,66 @@ +"use client"; + +// เลือก mock user ที่หน้าแรกก่อนเข้า annotate — เขียนลง localStorage key เดิม +// ที่ getLocalUser() อ่าน (PDFViewer ไม่ต้องแก้อะไร) +import { useEffect, useState } from "react"; + +import Select from "./Select"; +import { + MOCK_USERS, + getStoredLocalUser, + setLocalUser, + type LocalUser, +} from "@/utils/user"; + +export default function UserPicker() { + const [current, setCurrent] = useState(null); + + // ต้องรันใน effect เพราะ SSR ไม่มี localStorage — ก่อน mount แสดงคนแรกไว้ก่อน + useEffect(() => { + const stored = getStoredLocalUser(); + if (!stored) { + // ยังไม่เคยมี identity → เริ่มด้วย mock user คนแรก + setLocalUser(MOCK_USERS[0]); + setCurrent(MOCK_USERS[0]); + return; + } + setCurrent(stored); + }, []); + + // identity สุ่มเดิมไม่อยู่ในรายการ mock → แสดงเป็น option ชั่วคราวให้เห็นว่าปัจจุบันคือใคร + const isMock = current !== null && MOCK_USERS.some((u) => u.userId === current.userId); + + const select = (userId: string) => { + const user = MOCK_USERS.find((u) => u.userId === userId); + if (!user) return; + setLocalUser(user); + setCurrent(user); + }; + + return ( +
      +

      เลือกผู้ใช้ (mock)

      +

      + annotation ทั้งหมดจะบันทึกในชื่อผู้ใช้ที่เลือก +

      + +
      + ); +} diff --git a/components/pdf/PDFViewer.tsx b/components/pdf/PDFViewer.tsx index 8bca8fc..eaa1469 100644 --- a/components/pdf/PDFViewer.tsx +++ b/components/pdf/PDFViewer.tsx @@ -109,6 +109,7 @@ import InkLayer, { type InkRedaction, type InkShape, type InkStroke } from "./In import TextboxStampLayer, { type InkStamp, type InkTextbox } from "./TextboxStampLayer"; import AnnotationSelectionLayer from "./AnnotationSelectionLayer"; import AnnotationSidebar from "../sidebar/AnnotationSidebar"; +import Select from "../Select"; import { ColorSwatches, HIGHLIGHT_STYLE_BTNS, @@ -2634,7 +2635,7 @@ export default function PDFViewer({ className="mt-1.5 w-full resize-none rounded-md border border-slate-300 px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-slate-400" />

      วางที่

      - + {bookmarkError && (

      {bookmarkError} diff --git a/components/sidebar/AnnotationSidebar.tsx b/components/sidebar/AnnotationSidebar.tsx index c004308..6285d1e 100644 --- a/components/sidebar/AnnotationSidebar.tsx +++ b/components/sidebar/AnnotationSidebar.tsx @@ -28,6 +28,8 @@ import { X, } from "lucide-react"; +import Select from "../Select"; + import { listVersions, restoreVersion, @@ -359,7 +361,7 @@ export default function AnnotationSidebar({ className="mt-1 w-full resize-none rounded border border-slate-300 p-1.5 text-[11px] focus:outline-none focus:ring-1 focus:ring-slate-400" />

      วางที่

      - +