feat(editor) : notify peers of draft overwrite
This commit is contained in:
+21
-5
@@ -16,6 +16,10 @@ interface SaveResult {
|
||||
currentVersion?: number;
|
||||
}
|
||||
|
||||
interface SaveIntent {
|
||||
overwrite?: boolean;
|
||||
}
|
||||
|
||||
export function useAutosave<Value, Draft = Value>({
|
||||
value,
|
||||
valid,
|
||||
@@ -32,7 +36,7 @@ export function useAutosave<Value, Draft = Value>({
|
||||
value: Value;
|
||||
valid: boolean;
|
||||
initialVersion: number;
|
||||
persist: (value: Value, expectedVersion: number) => Promise<SaveResult>;
|
||||
persist: (value: Value, expectedVersion: number, intent?: SaveIntent) => Promise<SaveResult>;
|
||||
delay?: number;
|
||||
storageKey?: string;
|
||||
localDraft?: Draft;
|
||||
@@ -52,6 +56,7 @@ export function useAutosave<Value, Draft = Value>({
|
||||
const [hydrated, setHydrated] = useState(!storageKey);
|
||||
const [manualRequest, setManualRequest] = useState(0);
|
||||
const [conflictVersion, setConflictVersion] = useState<number | null>(null);
|
||||
const [conflictActor, setConflictActor] = useState<string | null>(null);
|
||||
const [overwriteRequest, setOverwriteRequest] = useState<number | null>(null);
|
||||
const handledManualRequest = useRef(0);
|
||||
const storageWarningShown = useRef(false);
|
||||
@@ -125,14 +130,15 @@ export function useAutosave<Value, Draft = Value>({
|
||||
}
|
||||
}, [draftFingerprint, hydrated, localDraft, savedDraftFingerprint, storageKey, version]);
|
||||
|
||||
const save = useEffectEvent(async (snapshot: Value, snapshotFingerprint: string, snapshotDraftFingerprint: string, expectedVersion = version) => {
|
||||
const save = useEffectEvent(async (snapshot: Value, snapshotFingerprint: string, snapshotDraftFingerprint: string, expectedVersion = version, overwrite = false) => {
|
||||
setSaving(true);
|
||||
setErrorFingerprint(null);
|
||||
try {
|
||||
const result = await persist(snapshot, expectedVersion);
|
||||
const result = await persist(snapshot, expectedVersion, overwrite ? { overwrite: true } : undefined);
|
||||
if (result.status === "conflict") {
|
||||
if (result.currentVersion) setVersion(result.currentVersion);
|
||||
setConflictVersion(result.currentVersion ?? expectedVersion);
|
||||
setConflictActor(null);
|
||||
return;
|
||||
}
|
||||
if (result.status === "error") {
|
||||
@@ -144,6 +150,7 @@ export function useAutosave<Value, Draft = Value>({
|
||||
setSavedFingerprint(snapshotFingerprint);
|
||||
setSavedDraftFingerprint(snapshotDraftFingerprint);
|
||||
setConflictVersion(null);
|
||||
setConflictActor(null);
|
||||
} catch (cause) {
|
||||
setErrorFingerprint(snapshotFingerprint);
|
||||
toast.error(cause instanceof Error ? cause.message : "บันทึกอัตโนมัติไม่สำเร็จ");
|
||||
@@ -162,12 +169,18 @@ export function useAutosave<Value, Draft = Value>({
|
||||
return;
|
||||
}
|
||||
if (hydrated && valid && !saving && fingerprint === savedFingerprint) {
|
||||
if (event.operation === "overwrite" && event.actorName) {
|
||||
toast.warning(`${event.actorName} เขียนทับข้อมูลส่วนนี้ด้วย Local draft`, {
|
||||
description: "ระบบโหลดข้อมูลล่าสุดให้แล้ว",
|
||||
});
|
||||
}
|
||||
setVersion((current) => Math.max(current, event.version));
|
||||
router.refresh();
|
||||
return;
|
||||
}
|
||||
setVersion((current) => Math.max(current, event.version));
|
||||
setConflictVersion((current) => Math.max(current ?? 0, event.version));
|
||||
setConflictActor(event.operation === "overwrite" ? event.actorName ?? null : null);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -187,7 +200,9 @@ export function useAutosave<Value, Draft = Value>({
|
||||
}
|
||||
toast.error("Autosave ถูกหยุดชั่วคราว", {
|
||||
id: toastId,
|
||||
description: "มีผู้แก้ไขคนอื่นบันทึกข้อมูลส่วนนี้ กรุณาเลือกโหลดข้อมูลล่าสุดหรือเขียนทับด้วย Draft นี้",
|
||||
description: conflictActor
|
||||
? `${conflictActor} เขียนทับข้อมูลส่วนนี้ แต่ Draft ของคุณยังถูกเก็บไว้`
|
||||
: "มีผู้แก้ไขคนอื่นบันทึกข้อมูลส่วนนี้ กรุณาเลือกโหลดข้อมูลล่าสุดหรือเขียนทับด้วย Draft นี้",
|
||||
duration: Infinity,
|
||||
action: {
|
||||
label: "ดูตัวเลือก",
|
||||
@@ -197,7 +212,7 @@ export function useAutosave<Value, Draft = Value>({
|
||||
return () => {
|
||||
toast.dismiss(toastId);
|
||||
};
|
||||
}, [conflictVersion, guideId, scope]);
|
||||
}, [conflictActor, conflictVersion, guideId, scope]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hydrated || !valid || saving || conflictVersion !== null) return;
|
||||
@@ -218,6 +233,7 @@ export function useAutosave<Value, Draft = Value>({
|
||||
fingerprint,
|
||||
draftFingerprint,
|
||||
overwriteRequest,
|
||||
true,
|
||||
).finally(() => setOverwriteRequest(null));
|
||||
}, 0);
|
||||
return () => window.clearTimeout(timer);
|
||||
|
||||
Reference in New Issue
Block a user