Skip to content

Commit 731db26

Browse files
committed
refactor: simplify modal handling
This deals with issues in our old approach. If a confirmation dialog pops up, and the user declines to navigate, the modal will not be closed.
1 parent 6f005a5 commit 731db26

1 file changed

Lines changed: 9 additions & 26 deletions

File tree

  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page-client.tsx

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,12 @@ import { ALL_APPS_FRONTEND, getAppPath } from "@/lib/apps-frontend";
88
import { useUpdateConfig } from "@/lib/config-update";
99
import { AppId } from "@stackframe/stack-shared/dist/apps/apps-config";
1010
import { usePathname } from "next/navigation";
11-
import { useEffect, useRef, useState } from "react";
11+
import { useEffect, useState } from "react";
1212

1313
export default function AppDetailsModalPageClient({ appId }: { appId: AppId }) {
1414
const router = useRouter();
1515
const pathname = usePathname();
1616
const [isOpen, setIsOpen] = useState(true);
17-
const [navigateTo, setNavigateTo] = useState<string | null>(null);
18-
// Tracks whether we've already navigated to prevent duplicate navigations
19-
const hasNavigatedRef = useRef(false);
2017

2118
const adminApp = useAdminApp();
2219
const project = adminApp.useProject();
@@ -25,24 +22,14 @@ export default function AppDetailsModalPageClient({ appId }: { appId: AppId }) {
2522

2623
const isEnabled = config.apps.installed[appId]?.enabled ?? false;
2724

25+
// Control modal visibility based on whether we're on a modal route.
26+
// This ensures the modal only closes when navigation actually succeeds,
27+
// preventing issues if router.replace is vetoed by a confirmation dialog.
2828
useEffect(() => {
2929
const isModalRoute = /^\/projects\/[^/]+\/apps\/[^/]+$/.test(pathname);
30-
if (isModalRoute) {
31-
setIsOpen(true);
32-
setNavigateTo(null);
33-
// Block any stale navigation from previous session's navigateTo value
34-
hasNavigatedRef.current = true;
35-
}
30+
setIsOpen(isModalRoute);
3631
}, [pathname]);
3732

38-
useEffect(() => {
39-
if (!isOpen && navigateTo && !hasNavigatedRef.current) {
40-
// Mark as navigated to prevent duplicate navigation on re-renders
41-
hasNavigatedRef.current = true;
42-
router.replace(navigateTo);
43-
}
44-
}, [isOpen, navigateTo, router]);
45-
4633
const handleEnable = async () => {
4734
await updateConfig({
4835
adminApp,
@@ -61,18 +48,14 @@ export default function AppDetailsModalPageClient({ appId }: { appId: AppId }) {
6148

6249
const handleOpen = () => {
6350
const path = getAppPath(project.id, ALL_APPS_FRONTEND[appId]);
64-
// Allow navigation by resetting the flag (was set to true by pathname effect)
65-
hasNavigatedRef.current = false;
66-
setNavigateTo(path);
67-
setIsOpen(false);
51+
// Navigate to the app page. Modal stays open until pathname changes.
52+
router.replace(path);
6853
};
6954

7055
const handleOpenChange = (open: boolean) => {
7156
if (!open) {
72-
setIsOpen(false);
73-
if (!navigateTo) {
74-
router.replace(`/projects/${project.id}/apps`);
75-
}
57+
// Navigate back to apps list. Modal stays open until pathname changes.
58+
router.replace(`/projects/${project.id}/apps`);
7659
}
7760
};
7861

0 commit comments

Comments
 (0)