diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page-client.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page-client.tsx index 906cb0697e..0061981e00 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page-client.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/@modal/(.)apps/[appId]/page-client.tsx @@ -7,32 +7,67 @@ import { Dialog, DialogContent, DialogTitle } from "@/components/ui"; import { ALL_APPS_FRONTEND, getAppPath } from "@/lib/apps-frontend"; import { useUpdateConfig } from "@/lib/config-update"; import { AppId } from "@stackframe/stack-shared/dist/apps/apps-config"; -import { wait } from "@stackframe/stack-shared/dist/utils/promises"; +import { usePathname } from "next/navigation"; +import { useEffect, useState } from "react"; export default function AppDetailsModalPageClient({ appId }: { appId: AppId }) { const router = useRouter(); + const pathname = usePathname(); + const [isOpen, setIsOpen] = useState(true); const adminApp = useAdminApp(); const project = adminApp.useProject(); + const config = project.useConfig(); const updateConfig = useUpdateConfig(); + const isEnabled = config.apps.installed[appId]?.enabled ?? false; + + // Control modal visibility based on whether we're on a modal route. + // This ensures the modal only closes when navigation actually succeeds, + // preventing issues if router.replace is vetoed by a confirmation dialog. + useEffect(() => { + const isModalRoute = /^\/projects\/[^/]+\/apps\/[^/]+$/.test(pathname); + setIsOpen(isModalRoute); + }, [pathname]); + const handleEnable = async () => { - await wait(1000); await updateConfig({ adminApp, configUpdate: { [`apps.installed.${appId}.enabled`]: true }, pushable: true, }); + }; + + const handleDisable = async () => { + await updateConfig({ + adminApp, + configUpdate: { [`apps.installed.${appId}.enabled`]: false }, + pushable: true, + }); + }; + + const handleOpen = () => { const path = getAppPath(project.id, ALL_APPS_FRONTEND[appId]); - router.push(path); + // Navigate to the app page. Modal stays open until pathname changes. + router.replace(path); + }; + + const handleOpenChange = (open: boolean) => { + if (!open) { + // Navigate back to apps list. Modal stays open until pathname changes. + router.replace(`/projects/${project.id}/apps`); + } }; return ( - !open && router.back()} modal> + diff --git a/apps/dashboard/src/components/app-store-entry.tsx b/apps/dashboard/src/components/app-store-entry.tsx index 66116146d9..e6178c3297 100644 --- a/apps/dashboard/src/components/app-store-entry.tsx +++ b/apps/dashboard/src/components/app-store-entry.tsx @@ -156,8 +156,9 @@ export function AppStoreEntry({ {onDisable && (