Midday / apps /dashboard /src /store /invoice-editor.ts
Jules
Final deployment with all fixes and verified content
c09f67c
import { create } from "zustand";
interface InvoiceEditorState {
/** Serialized snapshot of the fully hydrated form values */
snapshot: string;
/** Whether the snapshot has been captured after the last reset */
initialized: boolean;
/** Called after form.reset() — invalidates the current snapshot so the next
* debounce cycle captures a fresh baseline (after child effects settle). */
markReset: () => void;
/** Called on the first debounce after a reset — captures the fully hydrated
* form values (post-Summary, post-all child effects) as the baseline. */
initialize: (values: unknown) => void;
/** Capture a new snapshot after a successful save.
* Accepts either the form values object or a pre-serialized JSON string. */
setSnapshot: (valuesOrSerialized: unknown) => void;
/** Returns true if the current values differ from the snapshot.
* Returns false if not yet initialized (prevents saving during hydration). */
hasChanged: (values: unknown) => boolean;
/** Clear everything when the invoice sheet closes */
reset: () => void;
}
export const useInvoiceEditorStore = create<InvoiceEditorState>()(
(set, get) => ({
snapshot: "",
initialized: false,
markReset: () => {
set({ snapshot: "", initialized: false });
},
initialize: (values) => {
set({ snapshot: JSON.stringify(values), initialized: true });
},
setSnapshot: (valuesOrSerialized) => {
set({
snapshot:
typeof valuesOrSerialized === "string"
? valuesOrSerialized
: JSON.stringify(valuesOrSerialized),
});
},
hasChanged: (values) => {
const { snapshot, initialized } = get();
if (!initialized) return false;
return JSON.stringify(values) !== snapshot;
},
reset: () => {
set({ snapshot: "", initialized: false });
},
}),
);