Add application codebase: PDF annotation for e-Court
Next.js 14 + Drizzle/PostgreSQL + SSE realtime sync — highlight,
freehand, comment, bookmark + ฟีเจอร์ต่อยอด F1–F19 (edit/move, undo/redo,
shapes, redaction, export PDF/CSV, reply, resolve, search, summary,
textbox, stamp, version history)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-10 14:29:40 +07:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import { useCallback, useRef, useState } from "react";
|
|
|
|
|
|
|
|
|
|
// Undo/Redo (PLAN-FEAT.md §3 F2, D10) — history ฝั่ง client ต่อ session ต่อผู้ใช้
|
|
|
|
|
// ไม่เก็บใน DB; push เฉพาะ action ของตัวเองที่สำเร็จเท่านั้น (event ของคนอื่นไม่เกี่ยว)
|
|
|
|
|
// ตัว entry เก็บ closure ที่เรียก Server Action + sync state เอง — id ของ annotation
|
|
|
|
|
// ที่ "สร้างใหม่" หลัง undo ต้องส่งต่อให้ redo ได้ จึงให้ entry เป็น object ที่แก้ field ได้
|
|
|
|
|
|
|
|
|
|
export type HistoryEntry = {
|
|
|
|
|
undo: () => Promise<void>;
|
|
|
|
|
redo: () => Promise<void>;
|
|
|
|
|
};
|
|
|
|
|
|
2026-11-02 10:01:00 +07:00
|
|
|
export function useHistory(options?: {
|
|
|
|
|
/** เรียกเมื่อ undo/redo ล้มเหลว (เน็ตสะดุด/session หมดอายุ ฯลฯ) — entry ถูกข้าม
|
|
|
|
|
* ไปแล้วโดย hook ผู้ใช้ควรเห็น toast ของ caller ไม่ใช่เงียบหายไปเฉย ๆ */
|
|
|
|
|
onError?: (err: unknown, kind: "undo" | "redo") => void;
|
|
|
|
|
}) {
|
Add application codebase: PDF annotation for e-Court
Next.js 14 + Drizzle/PostgreSQL + SSE realtime sync — highlight,
freehand, comment, bookmark + ฟีเจอร์ต่อยอด F1–F19 (edit/move, undo/redo,
shapes, redaction, export PDF/CSV, reply, resolve, search, summary,
textbox, stamp, version history)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-10 14:29:40 +07:00
|
|
|
// source of truth เป็น ref — state ที่เปลี่ยนแค่ไว้ trigger re-render ปุ่ม disabled
|
|
|
|
|
const undoRef = useRef<HistoryEntry[]>([]);
|
|
|
|
|
const redoRef = useRef<HistoryEntry[]>([]);
|
|
|
|
|
const [, bump] = useState(0);
|
2026-11-02 10:01:00 +07:00
|
|
|
// เก็บ callback ล่าสุดของ caller ใน ref — callback ที่ส่งเข้ามาเปลี่ยนทุก render ได้
|
|
|
|
|
const onErrorRef = useRef(options?.onError);
|
|
|
|
|
onErrorRef.current = options?.onError;
|
Add application codebase: PDF annotation for e-Court
Next.js 14 + Drizzle/PostgreSQL + SSE realtime sync — highlight,
freehand, comment, bookmark + ฟีเจอร์ต่อยอด F1–F19 (edit/move, undo/redo,
shapes, redaction, export PDF/CSV, reply, resolve, search, summary,
textbox, stamp, version history)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-10 14:29:40 +07:00
|
|
|
|
|
|
|
|
/** บันทึก action ที่สำเร็จ — action ใหม่เคลียร์ redo stack เสมอ */
|
|
|
|
|
const push = useCallback((entry: HistoryEntry) => {
|
|
|
|
|
undoRef.current.push(entry);
|
|
|
|
|
redoRef.current = [];
|
|
|
|
|
bump((n) => n + 1);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const undo = useCallback(async () => {
|
|
|
|
|
const entry = undoRef.current.pop();
|
|
|
|
|
if (!entry) return;
|
|
|
|
|
try {
|
|
|
|
|
await entry.undo();
|
|
|
|
|
redoRef.current.push(entry);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// เช่น undo ของ create แต่ row ถูกลบไปแล้วโดยแท็บอื่น → ข้าม ไม่ crash (§5)
|
|
|
|
|
console.error("undo ไม่สำเร็จ — ข้ามรายการนี้", err);
|
2026-11-02 10:01:00 +07:00
|
|
|
onErrorRef.current?.(err, "undo");
|
Add application codebase: PDF annotation for e-Court
Next.js 14 + Drizzle/PostgreSQL + SSE realtime sync — highlight,
freehand, comment, bookmark + ฟีเจอร์ต่อยอด F1–F19 (edit/move, undo/redo,
shapes, redaction, export PDF/CSV, reply, resolve, search, summary,
textbox, stamp, version history)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-10 14:29:40 +07:00
|
|
|
}
|
|
|
|
|
bump((n) => n + 1);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const redo = useCallback(async () => {
|
|
|
|
|
const entry = redoRef.current.pop();
|
|
|
|
|
if (!entry) return;
|
|
|
|
|
try {
|
|
|
|
|
await entry.redo();
|
|
|
|
|
undoRef.current.push(entry);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error("redo ไม่สำเร็จ — ข้ามรายการนี้", err);
|
2026-11-02 10:01:00 +07:00
|
|
|
onErrorRef.current?.(err, "redo");
|
Add application codebase: PDF annotation for e-Court
Next.js 14 + Drizzle/PostgreSQL + SSE realtime sync — highlight,
freehand, comment, bookmark + ฟีเจอร์ต่อยอด F1–F19 (edit/move, undo/redo,
shapes, redaction, export PDF/CSV, reply, resolve, search, summary,
textbox, stamp, version history)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-10 14:29:40 +07:00
|
|
|
}
|
|
|
|
|
bump((n) => n + 1);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
push,
|
|
|
|
|
undo,
|
|
|
|
|
redo,
|
|
|
|
|
canUndo: undoRef.current.length > 0,
|
|
|
|
|
canRedo: redoRef.current.length > 0,
|
|
|
|
|
};
|
|
|
|
|
}
|