Bring back Undo/Redo functionality in the resume builder (#2629)

This commit is contained in:
Amruth Pillai
2026-01-28 11:20:11 +01:00
committed by GitHub
parent feda173b3b
commit 89102d6612
5 changed files with 1115 additions and 1471 deletions
+41 -23
View File
@@ -1,10 +1,14 @@
import { t } from "@lingui/core/macro";
import { debounce } from "es-toolkit";
import isDeepEqual from "fast-deep-equal";
import type { WritableDraft } from "immer";
import { current } from "immer";
import { toast } from "sonner";
import type { TemporalState } from "zundo";
import { temporal } from "zundo";
import { immer } from "zustand/middleware/immer";
import { create } from "zustand/react";
import { useStoreWithEqualityFn } from "zustand/traditional";
import { orpc, type RouterOutput } from "@/integrations/orpc/client";
import type { ResumeData } from "@/schema/resume/data";
@@ -33,30 +37,44 @@ const syncResume = debounce(_syncResume, 500, { signal });
let errorToastId: string | number | undefined;
type PartializedState = { resume: Resume | null };
export const useResumeStore = create<ResumeStore>()(
immer((set) => ({
resume: null as unknown as Resume,
isReady: false,
temporal(
immer((set) => ({
resume: null as unknown as Resume,
isReady: false,
initialize: (resume) => {
set((state) => {
state.resume = resume as Resume;
state.isReady = resume !== null;
});
initialize: (resume) => {
set((state) => {
state.resume = resume as Resume;
state.isReady = resume !== null;
useResumeStore.temporal.getState().clear();
});
},
updateResumeData: (fn) => {
set((state) => {
if (!state.resume) return state;
if (state.resume.isLocked) {
errorToastId = toast.error(t`This resume is locked and cannot be updated.`, { id: errorToastId });
return state;
}
fn(state.resume.data);
syncResume(current(state.resume));
});
},
})),
{
partialize: (state) => ({ resume: state.resume }),
equality: (pastState, currentState) => isDeepEqual(pastState, currentState),
limit: 100,
},
updateResumeData: (fn) => {
set((state) => {
if (!state.resume) return state;
if (state.resume.isLocked) {
errorToastId = toast.error(t`This resume is locked and cannot be updated.`, { id: errorToastId });
return state;
}
fn(state.resume.data);
syncResume(current(state.resume));
});
},
})),
),
);
export function useTemporalStore<T>(selector: (state: TemporalState<PartializedState>) => T): T {
return useStoreWithEqualityFn(useResumeStore.temporal, selector);
}