mirror of
https://github.com/ajnart/homarr.git
synced 2026-05-07 17:36:16 +02:00
✨ Add confirm dialog for leaving board page in edit mode
This commit is contained in:
@@ -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 '';
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user