From b7af79f72a8042592f1f291b3c50c0f778cf7dc9 Mon Sep 17 00:00:00 2001 From: Rithvik Nishad Date: Mon, 23 Jan 2023 18:15:47 +0530 Subject: [PATCH] App history provider (#4592) * Implement useHistory and Providers for its API * Upgrade `PageTitle`'s goBack * `HistoryAPIProvider` for `AppRouter` * reset history if sidebar item clicked --- src/App.tsx | 7 +++- src/CAREUI/misc/HistoryAPIProvider.tsx | 38 +++++++++++++++++++ src/Common/hooks/useAppHistory.ts | 26 +++++++++++++ src/Components/Common/PageTitle.tsx | 20 +++++++--- src/Components/Common/Sidebar/SidebarItem.tsx | 4 +- src/Components/Facility/AddBedForm.tsx | 8 +--- src/Components/Patient/PatientRegister.tsx | 3 +- src/Utils/utils.ts | 3 ++ 8 files changed, 93 insertions(+), 16 deletions(-) create mode 100644 src/CAREUI/misc/HistoryAPIProvider.tsx create mode 100644 src/Common/hooks/useAppHistory.ts diff --git a/src/App.tsx b/src/App.tsx index 9d2e3da6122..1ee69184f4d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,6 +6,7 @@ import { useDispatch, useSelector } from "react-redux"; import { getConfig, getCurrentUser } from "./Redux/actions"; import { useAbortableEffect, statusType } from "./Common/utils"; import axios from "axios"; +import { HistoryAPIProvider } from "./CAREUI/misc/HistoryAPIProvider"; const Loading = loadable(() => import("./Components/Common/Loading")); @@ -68,7 +69,11 @@ const App: React.FC = () => { } if (currentUser?.data) { - return ; + return ( + + + + ); } else { return ; } diff --git a/src/CAREUI/misc/HistoryAPIProvider.tsx b/src/CAREUI/misc/HistoryAPIProvider.tsx new file mode 100644 index 00000000000..3048aa22f02 --- /dev/null +++ b/src/CAREUI/misc/HistoryAPIProvider.tsx @@ -0,0 +1,38 @@ +import { useLocationChange } from "raviger"; +import { createContext, ReactNode, useState } from "react"; + +export const HistoryContext = createContext([]); +// eslint-disable-next-line @typescript-eslint/no-empty-function +export const ResetHistoryContext = createContext(() => {}); + +export const HistoryAPIProvider = (props: { children: ReactNode }) => { + const [history, setHistory] = useState([]); + + useLocationChange( + (newLocation) => { + setHistory((history) => { + if (history.length && newLocation.fullPath === history[0]) + // Ignore push if navigate to same path (for some weird unknown reasons?) + return history; + + if (history.length > 1 && newLocation.fullPath === history[1]) + // Pop current path if navigate back to previous path + return history.slice(1); + + // Otherwise just push the current path + return [newLocation.fullPath, ...history]; + }); + }, + { onInitial: true } + ); + + const resetHistory = () => setHistory((history) => history.slice(0, 1)); + + return ( + + + {props.children} + + + ); +}; diff --git a/src/Common/hooks/useAppHistory.ts b/src/Common/hooks/useAppHistory.ts new file mode 100644 index 00000000000..893b1a06cfd --- /dev/null +++ b/src/Common/hooks/useAppHistory.ts @@ -0,0 +1,26 @@ +import { navigate } from "raviger"; +import { useContext } from "react"; +import { + HistoryContext, + ResetHistoryContext, +} from "../../CAREUI/misc/HistoryAPIProvider"; + +export default function useAppHistory() { + const history = useContext(HistoryContext); + const resetHistory = useContext(ResetHistoryContext); + + const goBack = (fallbackUrl?: string) => { + if (history.length > 1) + // Navigate to history present in the app navigation history stack. + return navigate(history[1]); + + if (fallbackUrl) + // Otherwise, use provided fallback url if provided. + return navigate(fallbackUrl); + + // Otherwise, fallback to browser's go back behaviour. + window.history.back(); + }; + + return { history, resetHistory, goBack }; +} diff --git a/src/Components/Common/PageTitle.tsx b/src/Components/Common/PageTitle.tsx index 6ed7c442344..52dd839454e 100644 --- a/src/Components/Common/PageTitle.tsx +++ b/src/Components/Common/PageTitle.tsx @@ -1,15 +1,19 @@ import React, { useEffect, useRef } from "react"; import Breadcrumbs from "./Breadcrumbs"; import PageHeadTitle from "./PageHeadTitle"; -import { classNames, goBack } from "../../Utils/utils"; +import { classNames } from "../../Utils/utils"; +import useAppHistory from "../../Common/hooks/useAppHistory"; interface PageTitleProps { title: string; hideBack?: boolean; backUrl?: string; - backButtonCB?: () => number | void; className?: string; componentRight?: React.ReactNode; + /** + * If `false` is returned, prevents from going back. + */ + onBackClick?: () => boolean | void; justifyContents?: | "justify-center" | "justify-start" @@ -26,8 +30,8 @@ export default function PageTitle({ title, hideBack = false, backUrl, - backButtonCB, className = "", + onBackClick, componentRight = <>, breadcrumbs = true, crumbsReplacements = {}, @@ -42,8 +46,7 @@ export default function PageTitle({ } }, [divRef, focusOnLoad]); - const onBackButtonClick = () => - backButtonCB ? goBack(backButtonCB()) : goBack(backUrl); + const { goBack } = useAppHistory(); return (
@@ -51,7 +54,12 @@ export default function PageTitle({
{!hideBack && ( -