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
This commit is contained in:
@@ -6,15 +6,44 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* 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 { useHistory } from '@/base/hooks/useHistory.ts';
|
||||||
|
import { noOp } from '@/lib/HelperFunctions.ts';
|
||||||
|
import { useForceUpdate } from '@mantine/hooks';
|
||||||
|
|
||||||
export const AppPageHistoryContext = createContext<string[]>([]);
|
interface IAppPageHistoryContext {
|
||||||
|
history: string[];
|
||||||
|
onBack: () => Promise<boolean> | boolean;
|
||||||
|
setOnBack: (subscriber: (() => Promise<boolean> | boolean) | null) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AppPageHistoryContext = createContext<IAppPageHistoryContext>({
|
||||||
|
history: [],
|
||||||
|
onBack: () => true,
|
||||||
|
setOnBack: noOp,
|
||||||
|
});
|
||||||
|
|
||||||
export const useAppPageHistoryContext = () => useContext(AppPageHistoryContext);
|
export const useAppPageHistoryContext = () => useContext(AppPageHistoryContext);
|
||||||
|
|
||||||
export const AppPageHistoryContextProvider = ({ children }: { children: React.ReactNode }) => {
|
export const AppPageHistoryContextProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
const forceUpdate = useForceUpdate();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
return <AppPageHistoryContext.Provider value={history}>{children}</AppPageHistoryContext.Provider>;
|
const onBackRef = useRef<IAppPageHistoryContext['onBack']>(() => true);
|
||||||
|
|
||||||
|
const setOnBack = useCallback((callback: (() => Promise<boolean> | boolean) | null) => {
|
||||||
|
onBackRef.current = callback ?? (() => true);
|
||||||
|
forceUpdate();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const value = useMemo(
|
||||||
|
() => ({
|
||||||
|
history,
|
||||||
|
onBack: onBackRef.current,
|
||||||
|
setOnBack,
|
||||||
|
}),
|
||||||
|
[history, onBackRef.current, setOnBack],
|
||||||
|
);
|
||||||
|
|
||||||
|
return <AppPageHistoryContext.Provider value={value}>{children}</AppPageHistoryContext.Provider>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ const PAGES_TO_IGNORE: readonly RegExp[] = [READER_REGEX];
|
|||||||
export const useBackButton = () => {
|
export const useBackButton = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const history = useAppPageHistoryContext();
|
const { history, onBack } = useAppPageHistoryContext();
|
||||||
|
|
||||||
return useCallback(() => {
|
return useCallback(async () => {
|
||||||
const getDelta = (historyToCheck: string[] = history, delta: number = 0) => {
|
const getDelta = (historyToCheck: string[] = history, delta: number = 0) => {
|
||||||
const isHistoryEmpty = !historyToCheck.length;
|
const isHistoryEmpty = !historyToCheck.length;
|
||||||
if (isHistoryEmpty) {
|
if (isHistoryEmpty) {
|
||||||
@@ -45,6 +45,11 @@ export const useBackButton = () => {
|
|||||||
return getDelta(historyToCheck.slice(0, -1), delta - 1);
|
return getDelta(historyToCheck.slice(0, -1), delta - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isAllowedToGoBack = await onBack();
|
||||||
|
if (!isAllowedToGoBack) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const backDelta = getDelta();
|
const backDelta = getDelta();
|
||||||
|
|
||||||
const canNavigateBack = backDelta < 0;
|
const canNavigateBack = backDelta < 0;
|
||||||
@@ -54,5 +59,5 @@ export const useBackButton = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
navigate(backDelta);
|
navigate(backDelta);
|
||||||
}, [history, location.pathname]);
|
}, [history, onBack, location.pathname]);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user