summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/web/src/app/editor/[project_id]/page.tsx96
-rw-r--r--apps/web/src/stores/project-store.ts26
2 files changed, 115 insertions, 7 deletions
diff --git a/apps/web/src/app/editor/[project_id]/page.tsx b/apps/web/src/app/editor/[project_id]/page.tsx
index 26fdcf8a..5e294fe7 100644
--- a/apps/web/src/app/editor/[project_id]/page.tsx
+++ b/apps/web/src/app/editor/[project_id]/page.tsx
@@ -32,39 +32,121 @@ export default function Editor() {
setPropertiesPanel,
} = usePanelStore();
- const { activeProject, loadProject, createNewProject } = useProjectStore();
+ const {
+ activeProject,
+ loadProject,
+ createNewProject,
+ isInvalidProjectId,
+ markProjectIdAsInvalid,
+ } = useProjectStore();
const params = useParams();
const router = useRouter();
const projectId = params.project_id as string;
const handledProjectIds = useRef<Set<string>>(new Set());
+ const isInitializingRef = useRef<boolean>(false);
usePlaybackControls();
useEffect(() => {
+ let isCancelled = false;
+
const initProject = async () => {
- if (!projectId) return;
+ if (!projectId) {
+ return;
+ }
+ // Prevent duplicate initialization
+ if (isInitializingRef.current) {
+ return;
+ }
+
+ // Check if project is already loaded
if (activeProject?.id === projectId) {
return;
}
+ // Check global invalid tracking first (most important for preventing duplicates)
+ if (isInvalidProjectId(projectId)) {
+ return;
+ }
+
+ // Check if we've already handled this project ID locally
if (handledProjectIds.current.has(projectId)) {
return;
}
+ // Mark as initializing to prevent race conditions
+ isInitializingRef.current = true;
+ handledProjectIds.current.add(projectId);
+
try {
await loadProject(projectId);
+
+ // Check if component was unmounted during async operation
+ if (isCancelled) {
+ return;
+ }
+
+ // Project loaded successfully
+ isInitializingRef.current = false;
} catch (error) {
- handledProjectIds.current.add(projectId);
+ // Check if component was unmounted during async operation
+ if (isCancelled) {
+ return;
+ }
- const newProjectId = await createNewProject("Untitled Project");
- router.replace(`/editor/${newProjectId}`);
- return;
+ // More specific error handling - only create new project for actual "not found" errors
+ const isProjectNotFound =
+ error instanceof Error &&
+ (error.message.includes("not found") ||
+ error.message.includes("does not exist") ||
+ error.message.includes("Project not found"));
+
+ if (isProjectNotFound) {
+ // Mark this project ID as invalid globally BEFORE creating project
+ markProjectIdAsInvalid(projectId);
+
+ try {
+ const newProjectId = await createNewProject("Untitled Project");
+
+ // Check again if component was unmounted
+ if (isCancelled) {
+ return;
+ }
+
+ router.replace(`/editor/${newProjectId}`);
+ } catch (createError) {
+ console.error("Failed to create new project:", createError);
+ }
+ } else {
+ // For other errors (storage issues, corruption, etc.), don't create new project
+ console.error(
+ "Project loading failed with recoverable error:",
+ error
+ );
+ // Remove from handled set so user can retry
+ handledProjectIds.current.delete(projectId);
+ }
+
+ isInitializingRef.current = false;
}
};
initProject();
- }, [projectId, activeProject?.id, loadProject, createNewProject, router]);
+
+ // Cleanup function to cancel async operations
+ return () => {
+ isCancelled = true;
+ isInitializingRef.current = false;
+ };
+ }, [
+ projectId,
+ loadProject,
+ createNewProject,
+ router,
+ isInvalidProjectId,
+ markProjectIdAsInvalid,
+ ]);
return (
<EditorProvider>
diff --git a/apps/web/src/stores/project-store.ts b/apps/web/src/stores/project-store.ts
index 7bb38039..6744bdec 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 = {
@@ -357,4 +364,23 @@ 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() });
+ },
}));