Add confirm dialog for leaving board page in edit mode

This commit is contained in:
Meier Lukas
2023-11-17 23:25:59 +01:00
parent eac4f20499
commit 4863364225

View File

@@ -1,7 +1,10 @@
import { useRouter } from 'next/router';
import { createContext, useContext } from 'react';
import { useEventListener } from '@mantine/hooks';
import Router, { useRouter } from 'next/router';
import { createContext, useContext, useEffect } from 'react';
import { RouterOutputs, api } from '~/utils/api';
import { useEditModeStore } from './useEditModeStore';
type BoardContextType = {
layout?: string;
board: RouterOutputs['boards']['byName'];
@@ -13,6 +16,7 @@ type BoardProviderProps = {
children: React.ReactNode;
};
export const BoardProvider = ({ children, userAgent, ...props }: BoardProviderProps) => {
const { enabled } = useEditModeStore();
const router = useRouter();
const { layout } = router.query;
const { data: board } = api.boards.byName.useQuery(
@@ -23,10 +27,12 @@ export const BoardProvider = ({ children, userAgent, ...props }: BoardProviderPr
},
{
initialData: props.initialBoard,
enabled: !!layout,
//enabled: !!layout,
}
);
useConfirmLeavePage(enabled);
return (
<BoardContext.Provider
value={{
@@ -68,3 +74,60 @@ type ItemOfType<TItem extends Item, TItemType extends Item['kind']> = TItem exte
: never;
export type AppItem = ItemOfType<Item, 'app'>;
export type WidgetItem = ItemOfType<Item, 'widget'>;
const useConfirmLeavePage = (enabled: boolean) => {
const utils = api.useUtils();
const { toggleEditMode } = useEditModeStore();
useEffect(() => {
const handleRouteChange = (url: string) => {
if (enabled && Router.pathname !== url) {
Router.events.emit('routeChangeError');
const shouldLeave = window.confirm(
'You have unsaved changes. Are you sure you want to leave?'
);
if (!shouldLeave) {
throw 'abort-navigation';
}
toggleEditMode();
utils.boards.byName.invalidate();
}
};
const catchAbortNavigationError = (event: PromiseRejectionEvent) => {
if (event.reason === 'abort-navigation') {
event.preventDefault();
}
};
Router.beforePopState(({ url }) => {
if (enabled) {
if (Router.pathname !== url) {
window.history.pushState('', '', url);
return false;
}
}
return true;
});
// For changing in-app route.
if (enabled) {
Router.events.on('routeChangeStart', handleRouteChange);
window.addEventListener('unhandledrejection', catchAbortNavigationError);
window.onbeforeunload = () => '';
window.close = () => '';
}
return () => {
Router.beforePopState(() => true);
Router.events.off('routeChangeStart', handleRouteChange);
window.removeEventListener('unhandledrejection', catchAbortNavigationError);
window.onbeforeunload = null;
window.close = () => null;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [enabled]);
useEventListener('close', () => {
if (enabled) return '';
});
};