mock login e-Court หน้า /login + identity จาก cookie oacCase แทน localStorage — dropdown ผู้ใช้ MOCK_USERS (user1–user5, utils/user.ts pure module ให้ client+server ใช้ร่วม) รหัสผ่านกลาง Demo1234 ผ่าน server action login (เช็ครายชื่อฝั่ง server เป็น defense กัน hand-craft + delay 500ms ให้เห็น "กำลังตรวจสอบ…") ตั้ง cookie oacCase ตาม format จริงของระบบศาล 16 field — u_userid/u_userlogin ต่างกันต่อคน (= ชื่อผู้ใช้) เพื่อให้สิทธิ์ "แก้ไขได้เฉพาะของตัวเอง" (guard ด้วย userId) แยกกันจริงทั้ง 5 คน httpOnly/sameSite lax/8 ชม. + middleware.ts บังคับ login ทุกหน้า (parse จริงด้วย parseOacCase ไม่ใช่แค่มี cookie — ขยะ/ว่าง/ขาด field = redirect /login; matcher ยกเว้น /login, /api/*, /uploads/*, _next และ static ใน public/ — SSE/export จึงไม่โดน 302) + lib/session.ts getSessionUser อ่าน identity ฝั่ง server ใช้ในทุกหน้า (defense ซ้อน middleware) + PDFViewer รับ user เป็น prop จาก annotate page ตั้งแต่ first paint (หมดช่วง null user ที่เคยสร้าง annotation ด้วย userId="" ได้ + ไม่มี hydration mismatch; Server Actions ไม่ต้องแก้ — vString รับ userId ใหม่อยู่แล้ว) + SessionBar แสดง "เข้าสู่ระบบเป็น <user>" + ปุ่มออกจากระบบ (ลบ cookie ด้วย path "/" ตรงตอน set + redirect ใน action เอง — client router.replace เองชนกับ re-render ของหน้าที่เพิ่งเสีย session จน navigation ไม่เกิด) แทน UserPicker mock 10 คน (ลบไฟล์พร้อม MOCK_USERS/localStorage/getLocalUser ทั้งชุด) + LoginForm การ์ด max-w-sm กลางจอ reuse brand lockup และปุ่ม primary เดิม, input text-base 16px กัน iOS zoom บน iPad, dropdown placeholder "เลือกผู้ใช้" บังคับเลือก (ไม่ preselect กัน login ผิดคนโดยไม่ตั้งใจ), error แถบเดียว role=alert "รหัสผ่านไม่ถูกต้อง" (dropdown เลือกผิดไม่ได้แล้ว), ตอนผิดล้าง password คงผู้ใช้ที่เลือกไว้ + focus+select + tests/utils/user.test.ts ล็อก format จริงของ e-Court (parse ตัวอย่าง cookie จริง 235821/tu_2, garbage/empty/ขาด field → null, round-trip, buildOacCaseCookie ครบ 16 field) + sync CLAUDE.md/PLAN.md §0 A4/README — annotation สมัย mock-user-01/UUID ไม่ใช่ของตัวเองอีก (auth จริงเทียบระบบศาล + roles ยัง out of scope; /api/* และ /uploads/* ยังไม่ต้อง login ตามขอบเขต mock)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
460cd9c600
commit
65b72cf817
16 changed files with 414 additions and 131 deletions
|
|
@ -113,7 +113,7 @@ import {
|
|||
type Rect,
|
||||
type Size,
|
||||
} from "@/utils/coordinates";
|
||||
import { getLocalUser, type LocalUser } from "@/utils/user";
|
||||
import type { OacUser } from "@/utils/user";
|
||||
import { fileKindFromUrl, imageFormatFromUrl } from "@/utils/file-kind";
|
||||
import { decodeTiffPages } from "@/utils/tiff-client";
|
||||
import {
|
||||
|
|
@ -1138,11 +1138,14 @@ export default function PDFViewer({
|
|||
initialAnnotations,
|
||||
initialBookmarks,
|
||||
initialReplies,
|
||||
user,
|
||||
}: {
|
||||
file: { id: string; title: string; pdfUrl: string };
|
||||
initialAnnotations: AnnotationDTO[];
|
||||
initialBookmarks: BookmarkDTO[];
|
||||
initialReplies: ReplyDTO[];
|
||||
/** identity จาก cookie oacCase (หน้า annotate การันตีให้ — ไม่มีช่วง null หลัง mount) */
|
||||
user: OacUser;
|
||||
}) {
|
||||
const [pdfjs, setPdfjs] = useState<typeof import("pdfjs-dist") | null>(null);
|
||||
const [doc, setDoc] = useState<import("pdfjs-dist").PDFDocumentProxy | null>(null);
|
||||
|
|
@ -1194,7 +1197,6 @@ export default function PDFViewer({
|
|||
const [menuPos, setMenuPos] = useState<{ left: number; top: number } | null>(null);
|
||||
const [bookmarkPos, setBookmarkPos] = useState<{ left: number; top: number } | null>(null);
|
||||
const [scale, setScale] = useState(1);
|
||||
const [user, setUser] = useState<LocalUser | null>(null);
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
// tool highlight — live preview มาร์กตามรูปแบบ/สีที่ตั้งไว้ ระหว่างลากคลุมข้อความ
|
||||
const [liveMark, setLiveMark] = useState<{ pageIndex: number; rects: Rect[] } | null>(null);
|
||||
|
|
@ -1323,11 +1325,10 @@ export default function PDFViewer({
|
|||
[replies, visibleAnnotations],
|
||||
);
|
||||
|
||||
// anonymous identity จาก localStorage — ต้องรันใน effect (SSR ไม่มี localStorage)
|
||||
// UX review 2026-09-14 H1: จอ < lg sidebar เป็น overlay บังเอกสาร — ปิดตอน mount
|
||||
// ให้เห็นเอกสารทันที (คง initial true ไว้กัน hydration mismatch เหมือนเดิม)
|
||||
// (identity มาจาก prop user แล้ว — ไม่ต้องอ่านใน effect)
|
||||
useEffect(() => {
|
||||
setUser(getLocalUser());
|
||||
// UX review 2026-09-14 H1: จอ < lg sidebar เป็น overlay บังเอกสาร — ปิดตอน mount
|
||||
// ให้เห็นเอกสารทันที (คง initial true ไว้กัน hydration mismatch เหมือนเดิม)
|
||||
if (!window.matchMedia("(min-width: 1024px)").matches) setSidebarOpen(false);
|
||||
}, []);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue