summaryrefslogtreecommitdiff
path: root/apps/web/src/stores
diff options
context:
space:
mode:
authornaoNao89 <90588855+naoNao89@users.noreply.github.com>2025-07-31 05:29:42 +0700
committernaoNao89 <90588855+naoNao89@users.noreply.github.com>2025-07-31 05:29:42 +0700
commita1d2fbd96bb6713c3172198d71e94274af409aee (patch)
treeb8bf5c16f221462272512377331204b6290607a9 /apps/web/src/stores
parente6e08057f510e70c956af0f0c08c6eef349edf3c (diff)
downloadopencut-a1d2fbd96bb6713c3172198d71e94274af409aee.tar.gz
[Editor] Prevent excessive project creation from invalid routes
Race conditions in useEffect hook caused navigation to invalid project IDs to create multiple 'Untitled Project' entries. Users reported accumulating 885+ projects due to this bug. This change adds global invalid project ID tracking across component remounts and prevents race conditions through: - Global invalidProjectIds Set in project store with tracking functions - isInitializingRef to prevent duplicate initialization attempts - Proper useEffect cleanup with cancellation tokens - Specific error handling for 'not found' vs recoverable errors - Removed problematic activeProject?.id dependency Testing: - Add comprehensive test suite (15 tests) with Vitest + React Testing Library - Include integration tests demonstrating bug and validating fix - Update CI pipeline to run automated tests Fixes #182
Diffstat (limited to 'apps/web/src/stores')
-rw-r--r--apps/web/src/stores/project-store.ts34
1 files changed, 34 insertions, 0 deletions
diff --git a/apps/web/src/stores/project-store.ts b/apps/web/src/stores/project-store.ts
index 7bb38039..82f449de 100644
--- a/apps/web/src/stores/project-store.ts
+++ b/apps/web/src/stores/project-store.ts
@@ -11,6 +11,7 @@ interface ProjectStore {
savedProjects: TProject[];
isLoading: boolean;
isInitialized: boolean;
+ invalidProjectIds?: Set<string>;
// Actions
createNewProject: (name: string) => Promise<string>;
@@ -32,6 +33,11 @@ interface ProjectStore {
searchQuery: string,
sortOption: string
) => TProject[];
+
+ // Global invalid project ID tracking
+ isInvalidProjectId: (id: string) => boolean;
+ markProjectIdAsInvalid: (id: string) => void;
+ clearInvalidProjectIds: () => void;
}
export const useProjectStore = create<ProjectStore>((set, get) => ({
@@ -39,6 +45,7 @@ export const useProjectStore = create<ProjectStore>((set, get) => ({
savedProjects: [],
isLoading: true,
isInitialized: false,
+ invalidProjectIds: new Set<string>(),
createNewProject: async (name: string) => {
const newProject: TProject = {
@@ -52,14 +59,25 @@ export const useProjectStore = create<ProjectStore>((set, get) => ({
blurIntensity: 8,
};
+ // DEBUG: Log project creation
+ console.log("🆕 Creating new project:", {
+ id: newProject.id,
+ name: newProject.name,
+ timestamp: new Date().toISOString()
+ });
+
set({ activeProject: newProject });
+ console.log("📝 Set activeProject to new project");
try {
await storageService.saveProject(newProject);
+ console.log("💾 Project saved to storage");
// Reload all projects to update the list
await get().loadAllProjects();
+ console.log("🔄 All projects reloaded");
return newProject.id;
} catch (error) {
+ console.error("❌ Failed to save new project:", error);
toast.error("Failed to save new project");
throw error;
}
@@ -357,4 +375,20 @@ export const useProjectStore = create<ProjectStore>((set, get) => ({
return sortedProjects;
},
+
+ // Global invalid project ID tracking implementation
+ isInvalidProjectId: (id: string) => {
+ const invalidIds = get().invalidProjectIds || new Set();
+ return invalidIds.has(id);
+ },
+
+ markProjectIdAsInvalid: (id: string) => {
+ set((state) => ({
+ invalidProjectIds: new Set([...(state.invalidProjectIds || new Set()), id])
+ }));
+ },
+
+ clearInvalidProjectIds: () => {
+ set({ invalidProjectIds: new Set() });
+ },
}));