Compare commits

...

1 Commits

Author SHA1 Message Date
Johannes
506323aed4 fix: prevent environment context race condition during rapid navigation
- Add defensive guards in EnvironmentContextWrapper to validate data before rendering
- Add loading.tsx for Next.js automatic loading state during navigation
- Handle AuthorizationError gracefully in layout to prevent crashes
- Fixes issue where environment becomes undefined during rapid page navigation
2025-11-11 10:16:01 +01:00
3 changed files with 37 additions and 8 deletions

View File

@@ -52,15 +52,22 @@ export const EnvironmentContextWrapper = ({
organization,
children,
}: EnvironmentContextWrapperProps) => {
const environmentContextValue = useMemo(
() => ({
const environmentContextValue = useMemo(() => {
if (!environment?.id || !project?.id || !organization?.id) {
return null;
}
return {
environment,
project,
organization,
organizationId: project.organizationId,
}),
[environment, project, organization]
);
};
}, [environment, project, organization]);
if (!environmentContextValue) {
return null;
}
return (
<EnvironmentContext.Provider value={environmentContextValue}>{children}</EnvironmentContext.Provider>

View File

@@ -1,5 +1,6 @@
import { getServerSession } from "next-auth";
import { redirect } from "next/navigation";
import { notFound, redirect } from "next/navigation";
import { AuthorizationError } from "@formbricks/types/errors";
import { EnvironmentLayout } from "@/app/(app)/environments/[environmentId]/components/EnvironmentLayout";
import { EnvironmentContextWrapper } from "@/app/(app)/environments/[environmentId]/context/environment-context";
import { authOptions } from "@/modules/auth/lib/authOptions";
@@ -20,8 +21,18 @@ const EnvLayout = async (props: {
return redirect(`/auth/login`);
}
// Single consolidated data fetch (replaces ~12 individual fetches)
const layoutData = await getEnvironmentLayoutData(params.environmentId, session.user.id);
// Handle AuthorizationError gracefully during rapid navigation
let layoutData;
try {
layoutData = await getEnvironmentLayoutData(params.environmentId, session.user.id);
} catch (error) {
// If user doesn't have access, show not found instead of crashing
if (error instanceof AuthorizationError) {
return notFound();
}
// Re-throw other errors
throw error;
}
return (
<EnvironmentIdBaseLayout

View File

@@ -0,0 +1,11 @@
"use client";
import { LoadingSpinner } from "@/modules/ui/components/loading-spinner";
export default function EnvironmentLoading() {
return (
<div className="flex h-screen min-h-screen items-center justify-center">
<LoadingSpinner className="h-8 w-8" />
</div>
);
}