From ffe1c917d63adb6aaa64f290c05536423c462aae Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Mon, 5 Jan 2026 13:43:23 +0530 Subject: [PATCH 1/2] :fix: prevent form prefilling when creating new Blueprint during active generation When navigating to create a new Blueprint while another generation was in progress, the form would be prefilled with data from the previous Blueprint. This was caused by a race condition where the zustand store's reset() was called before the persist middleware finished rehydrating from IndexedDB, causing the hydrated state to overwrite the reset. Added hydration tracking to the create blueprint store: - Added hasHydrated state and onRehydrateStorage callback - Updated useEffect to wait for hydration before calling reset() - Added loader during hydration to prevent flash of stale content Fixes #273 --- src/app/create/[id]/page.tsx | 13 ++++++++++--- src/app/create/[id]/store.ts | 10 +++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/app/create/[id]/page.tsx b/src/app/create/[id]/page.tsx index d74b7fc..c8555cc 100644 --- a/src/app/create/[id]/page.tsx +++ b/src/app/create/[id]/page.tsx @@ -48,6 +48,7 @@ const CreateBlueprint = ({ params }: { params: Promise<{ id: string }> }) => { file, setFile, blueprint, + hasHydrated: storeHasHydrated, } = store; const [errors, setErrors] = useState([]); @@ -118,7 +119,13 @@ const CreateBlueprint = ({ params }: { params: Promise<{ id: string }> }) => { }, [savedEmls[id]]); // Load data if an id is provided + // Wait for store hydration before resetting to prevent race condition + // where hydrated state overwrites the reset state useEffect(() => { + if (!storeHasHydrated) { + return; + } + if (id === 'new') { reset(); setHasLoadedBlueprint(false); @@ -140,7 +147,7 @@ const CreateBlueprint = ({ params }: { params: Promise<{ id: string }> }) => { }; loadBlueprint(); } - }, [id]); // Only run when id changes, not on step changes + }, [id, storeHasHydrated]); // Run when id or hydration state changes useEffect(() => { // Load all EMLs from IndexedDB on mount @@ -444,8 +451,8 @@ const CreateBlueprint = ({ params }: { params: Promise<{ id: string }> }) => { return <>; }; - // Show loader while auth store is hydrating from localStorage - if (!hasHydrated) { + // Show loader while auth store or create blueprint store is hydrating from storage + if (!hasHydrated || !storeHasHydrated) { return (
diff --git a/src/app/create/[id]/store.ts b/src/app/create/[id]/store.ts index f474c35..0a0168d 100644 --- a/src/app/create/[id]/store.ts +++ b/src/app/create/[id]/store.ts @@ -25,6 +25,8 @@ interface ExtendedBlueprintProps extends BlueprintProps { type CreateBlueprintState = ExtendedBlueprintProps & { blueprint: Blueprint | null; validationErrors: ValidationErrors; + hasHydrated: boolean; + setHasHydrated: (value: boolean) => void; setField: (field: keyof ExtendedBlueprintProps, value: any) => void; validateField: (field: keyof BlueprintProps) => void; validateAll: () => boolean; @@ -76,6 +78,8 @@ export const useCreateBlueprintStore = create()( blueprint: null, validationErrors: {}, file: null, + hasHydrated: false, + setHasHydrated: (value: boolean) => set({ hasHydrated: value }), setField: (field: keyof ExtendedBlueprintProps, value: any) => { set({ [field]: value }); @@ -335,9 +339,13 @@ export const useCreateBlueprintStore = create()( name: 'create-blueprint', // Exclude 'file' from persistence as File objects cannot be serialized partialize: (state) => { - const { file, blueprint, ...rest } = state; + const { file, blueprint, hasHydrated, setHasHydrated, ...rest } = state; return rest; }, + onRehydrateStorage: () => (state) => { + // This is called after the store has been rehydrated from storage + state?.setHasHydrated(true); + }, storage: { getItem: async (name) => { const value = await get(name); From 4249c85f22621a3ac0a8322b88fd6dc23e840afb Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Thu, 15 Jan 2026 21:50:45 +0530 Subject: [PATCH 2/2] :fix: guard rehydrate state and set fallback hydration flag --- src/app/create/[id]/store.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/create/[id]/store.ts b/src/app/create/[id]/store.ts index 0a0168d..7a5af7b 100644 --- a/src/app/create/[id]/store.ts +++ b/src/app/create/[id]/store.ts @@ -344,7 +344,11 @@ export const useCreateBlueprintStore = create()( }, onRehydrateStorage: () => (state) => { // This is called after the store has been rehydrated from storage - state?.setHasHydrated(true); + if (state) { + state.setHasHydrated(true); + } else { + useCreateBlueprintStore.setState({ hasHydrated: true }); + } }, storage: { getItem: async (name) => {