From 9aae34b8adbc0b8383d40d0a8b3610100026c23b Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Fri, 20 Mar 2026 01:28:31 +0100 Subject: [PATCH] Add logic to have optional page specific back button logic Makes it possible to trigger actions on back button click and optionally prevent the actual back navigation --- src/base/contexts/AppPageHistoryContext.tsx | 35 +++++++++++++++++++-- src/base/hooks/useBackButton.ts | 11 +++++-- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/base/contexts/AppPageHistoryContext.tsx b/src/base/contexts/AppPageHistoryContext.tsx index 09630788..16cad697 100644 --- a/src/base/contexts/AppPageHistoryContext.tsx +++ b/src/base/contexts/AppPageHistoryContext.tsx @@ -6,15 +6,44 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { createContext, useContext } from 'react'; +import { createContext, useCallback, useContext, useMemo, useRef } from 'react'; import { useHistory } from '@/base/hooks/useHistory.ts'; +import { noOp } from '@/lib/HelperFunctions.ts'; +import { useForceUpdate } from '@mantine/hooks'; -export const AppPageHistoryContext = createContext([]); +interface IAppPageHistoryContext { + history: string[]; + onBack: () => Promise | boolean; + setOnBack: (subscriber: (() => Promise | boolean) | null) => void; +} + +export const AppPageHistoryContext = createContext({ + history: [], + onBack: () => true, + setOnBack: noOp, +}); export const useAppPageHistoryContext = () => useContext(AppPageHistoryContext); export const AppPageHistoryContextProvider = ({ children }: { children: React.ReactNode }) => { + const forceUpdate = useForceUpdate(); const history = useHistory(); - return {children}; + const onBackRef = useRef(() => true); + + const setOnBack = useCallback((callback: (() => Promise | boolean) | null) => { + onBackRef.current = callback ?? (() => true); + forceUpdate(); + }, []); + + const value = useMemo( + () => ({ + history, + onBack: onBackRef.current, + setOnBack, + }), + [history, onBackRef.current, setOnBack], + ); + + return {children}; }; diff --git a/src/base/hooks/useBackButton.ts b/src/base/hooks/useBackButton.ts index bc7d0902..441c30bf 100644 --- a/src/base/hooks/useBackButton.ts +++ b/src/base/hooks/useBackButton.ts @@ -17,9 +17,9 @@ const PAGES_TO_IGNORE: readonly RegExp[] = [READER_REGEX]; export const useBackButton = () => { const navigate = useNavigate(); const location = useLocation(); - const history = useAppPageHistoryContext(); + const { history, onBack } = useAppPageHistoryContext(); - return useCallback(() => { + return useCallback(async () => { const getDelta = (historyToCheck: string[] = history, delta: number = 0) => { const isHistoryEmpty = !historyToCheck.length; if (isHistoryEmpty) { @@ -45,6 +45,11 @@ export const useBackButton = () => { return getDelta(historyToCheck.slice(0, -1), delta - 1); }; + const isAllowedToGoBack = await onBack(); + if (!isAllowedToGoBack) { + return; + } + const backDelta = getDelta(); const canNavigateBack = backDelta < 0; @@ -54,5 +59,5 @@ export const useBackButton = () => { } navigate(backDelta); - }, [history, location.pathname]); + }, [history, onBack, location.pathname]); };