@@ -8,15 +8,12 @@ import { ALL_APPS_FRONTEND, getAppPath } from "@/lib/apps-frontend";
88import { useUpdateConfig } from "@/lib/config-update" ;
99import { AppId } from "@stackframe/stack-shared/dist/apps/apps-config" ;
1010import { usePathname } from "next/navigation" ;
11- import { useEffect , useRef , useState } from "react" ;
11+ import { useEffect , useState } from "react" ;
1212
1313export 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 = / ^ \/ p r o j e c t s \/ [ ^ / ] + \/ a p p s \/ [ ^ / ] + $ / . 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