diff --git a/packages/playground/website/src/lib/state/redux/slice-ui.ts b/packages/playground/website/src/lib/state/redux/slice-ui.ts index 9b1f089d16..e248469263 100644 --- a/packages/playground/website/src/lib/state/redux/slice-ui.ts +++ b/packages/playground/website/src/lib/state/redux/slice-ui.ts @@ -127,6 +127,72 @@ export const listenToOnlineOfflineEventsMiddleware: Middleware = return next(action); }; +let browserConfirmationRanOnce = false; +let hasUserInteracted = false; + +export const browserConfirmationMiddleware: Middleware = + (store) => (next) => (action) => { + if (!browserConfirmationRanOnce) { + browserConfirmationRanOnce = true; + if (typeof window !== 'undefined') { + // Track user interactions to avoid warning on quick open/close + const interactionEvents = [ + 'click', + 'keypress', + 'input', + 'change', + ]; + interactionEvents.forEach((event) => { + window.addEventListener( + event, + () => { + hasUserInteracted = true; + }, + { once: true, capture: true } + ); + }); + + window.addEventListener('beforeunload', (e) => { + // Don't warn if user hasn't interacted with the site + if (!hasUserInteracted) { + return; + } + + // Check if WordPress editor already has unsaved changes + // If it does, let WordPress handle the confirmation + try { + const wpWindow = window as any; + if ( + wpWindow.wp?.data + ?.select?.('core/editor') + ?.isEditedPostDirty?.() + ) { + // WordPress will show its own dialog + return; + } + } catch { + // WordPress editor not available, continue with our check + } + + const state = store.getState() as any; + + // Check ALL temporary sites, not just the active one + const temporarySites = Object.values( + state.sites?.entities || {} + ).filter((site: any) => site?.metadata?.storage === 'none'); + + // Only show confirmation if there are temporary sites + if (temporarySites.length > 0) { + e.preventDefault(); + e.returnValue = ''; + return ''; + } + }); + } + } + return next(action); + }; + export const { setActiveModal, setActiveSiteError, diff --git a/packages/playground/website/src/lib/state/redux/store.ts b/packages/playground/website/src/lib/state/redux/store.ts index 3ba04ed195..ac62e0e741 100644 --- a/packages/playground/website/src/lib/state/redux/store.ts +++ b/packages/playground/website/src/lib/state/redux/store.ts @@ -3,6 +3,7 @@ import type { SiteError } from './slice-ui'; import uiReducer, { __internal_uiSlice, listenToOnlineOfflineEventsMiddleware, + browserConfirmationMiddleware, } from './slice-ui'; import type { SiteInfo } from './slice-sites'; import sitesReducer, { @@ -61,7 +62,8 @@ const store = configureStore({ }, middleware: (getDefaultMiddleware) => ignoreSerializableCheck(getDefaultMiddleware).concat( - listenToOnlineOfflineEventsMiddleware + listenToOnlineOfflineEventsMiddleware, + browserConfirmationMiddleware ), });