From 79fc5512cca8e6a88df0a24029b58139c9712c5c Mon Sep 17 00:00:00 2001 From: NikhilA8606 Date: Mon, 16 Mar 2026 12:20:31 +0530 Subject: [PATCH 1/4] Remove HistoryAPIProvider and rely on browser history to prevent navigation loops --- package-lock.json | 8 ++-- package.json | 2 +- src/App.tsx | 15 +++---- src/CAREUI/misc/PrintPreview.tsx | 11 ++--- src/Routers/routes/ConsultationRoutes.tsx | 18 ++------ src/components/Common/BackButton.tsx | 45 +++++++++---------- .../Common/Drawings/ExcalidrawEditor.tsx | 9 ++-- .../ErrorPages/DefaultErrorPage.tsx | 5 +-- .../Facility/FacilityDeleteDialog.tsx | 15 +------ .../Patient/EncounterQuestionnaire.tsx | 4 -- .../PatientDetailsTab/EncounterHistory.tsx | 7 +-- .../PatientDetailsTab/patientUpdates.tsx | 7 +-- .../Patient/PatientRegistration.tsx | 5 +-- .../Questionnaire/QuestionnaireForm.tsx | 11 +---- src/components/Resource/ResourceForm.tsx | 15 ++++--- src/components/Resource/ResourceList.tsx | 1 - src/components/Users/UserDeleteDialog.tsx | 6 +-- src/components/Users/UserHome.tsx | 6 +-- src/components/ValueSet/ValueSetForm.tsx | 14 ++---- src/components/ui/button.tsx | 1 + src/hooks/useAppHistory.ts | 35 --------------- src/pages/Admin/TagConfig/TagConfigView.tsx | 16 ++----- src/pages/Appointments/AppointmentDetail.tsx | 8 ++-- src/pages/Appointments/AppointmentsPage.tsx | 4 +- src/pages/Encounters/EncounterShow.tsx | 4 +- src/pages/Encounters/ReportViewer.tsx | 12 +---- src/pages/Facility/FacilityDetailsPage.tsx | 20 +++------ .../billing/account/CreateInvoice.tsx | 24 +++++----- .../account/components/PrintChargeItems.tsx | 9 +--- src/pages/Facility/billing/account/utils.ts | 27 +++++++++++ .../Facility/billing/invoice/InvoiceShow.tsx | 6 +-- .../PaymentReconciliationShow.tsx | 12 ++--- src/pages/Facility/queues/ManageQueue.tsx | 11 +---- .../services/HealthcareServiceShow.tsx | 2 +- .../deliveryOrder/DeliveryOrderForm.tsx | 3 ++ .../deliveryOrder/DeliveryOrderShow.tsx | 28 +++++++----- .../requestOrder/RequestOrderForm.tsx | 16 +++---- .../pharmacy/MedicationReturnShow.tsx | 2 +- .../serviceRequests/ServiceRequestShow.tsx | 9 ++-- .../ActivityDefinitionForm.tsx | 20 ++++----- .../ActivityDefinitionView.tsx | 14 +++--- .../ChargeItemDefinitionDetail.tsx | 7 +-- .../ChargeItemDefinitionForm.tsx | 15 +++---- .../UpdateChargeItemDefinition.tsx | 3 ++ .../settings/devices/CreateDevice.tsx | 4 +- .../settings/devices/UpdateDevice.tsx | 5 +-- .../devices/components/DeviceForm.tsx | 19 ++------ .../HealthcareServiceForm.tsx | 7 ++- .../Facility/settings/product/ProductForm.tsx | 10 ++--- .../productKnowledge/ProductKnowledgeView.tsx | 4 +- src/pages/Patient/PatientHome.tsx | 11 ++--- src/pages/PublicAppointments/Schedule.tsx | 11 ++--- .../PublicAppointments/auth/PatientLogin.tsx | 4 +- 53 files changed, 210 insertions(+), 377 deletions(-) delete mode 100644 src/hooks/useAppHistory.ts create mode 100644 src/pages/Facility/billing/account/utils.ts diff --git a/package-lock.json b/package-lock.json index a719c642956..3b6b86d2b57 100644 --- a/package-lock.json +++ b/package-lock.json @@ -75,7 +75,7 @@ "normalize-wheel": "^1.0.1", "pigeon-maps": "^0.22.1", "qrcode.react": "^4.1.0", - "raviger": "^5.0.0-2", + "raviger": "^5.3.0", "react": "19.1.1", "react-day-picker": "^9.6.3", "react-dom": "19.1.1", @@ -15027,9 +15027,9 @@ } }, "node_modules/raviger": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/raviger/-/raviger-5.2.0.tgz", - "integrity": "sha512-9xr+OKl81gyuBY0uHpjPF4utEqu1JV7B3f1H7IxvWEc+GDzwreJGWPfsKH8Dzgggpzp7Cr1VJhpbZxkhGB1Hxg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/raviger/-/raviger-5.3.0.tgz", + "integrity": "sha512-6I9nntaB9x/LdQZo5Q2Dfv9jvHvPlScKsChEkltGswZQCwCKKMKp/PNWcRspVOwRFjHWt4+jqRvBEpkztjmFjA==", "license": "MIT", "engines": { "node": ">=20" diff --git a/package.json b/package.json index 9180a525877..269fc51c464 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "normalize-wheel": "^1.0.1", "pigeon-maps": "^0.22.1", "qrcode.react": "^4.1.0", - "raviger": "^5.0.0-2", + "raviger": "^5.3.0", "react": "19.1.1", "react-day-picker": "^9.6.3", "react-dom": "19.1.1", diff --git a/src/App.tsx b/src/App.tsx index c36d1a97491..19d8b5dab7d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,7 +12,6 @@ import ProductionWarningBanner from "@/components/Common/ProductionWarningBanner import Integrations from "@/Integrations"; import PluginEngine from "@/PluginEngine"; import AuthUserProvider from "@/Providers/AuthUserProvider"; -import HistoryAPIProvider from "@/Providers/HistoryAPIProvider"; import Routers from "@/Routers"; import { displayCareConsoleArt } from "@/Utils/consoleArt"; import queryClient from "@/Utils/request/queryClient"; @@ -42,14 +41,12 @@ const App = () => { - - } - otpAuthorized={} - > - - - + } + otpAuthorized={} + > + + {props.showBackButton !== false && ( - + )} ); } diff --git a/src/components/Common/Drawings/ExcalidrawEditor.tsx b/src/components/Common/Drawings/ExcalidrawEditor.tsx index 96e13cfe7d3..3bd22d0412f 100644 --- a/src/components/Common/Drawings/ExcalidrawEditor.tsx +++ b/src/components/Common/Drawings/ExcalidrawEditor.tsx @@ -31,8 +31,6 @@ import { Input } from "@/components/ui/input"; import Loading from "@/components/Common/Loading"; -import useAppHistory from "@/hooks/useAppHistory"; - import mutate from "@/Utils/request/mutate"; import query from "@/Utils/request/query"; import metaArtifactApi from "@/types/metaArtifact/metaArtifactApi"; @@ -57,7 +55,6 @@ export default function ExcalidrawEditor({ const [name, setName] = useState(""); const [isDirty, setIsDirty] = useState(false); const [isAlertOpen, setIsAlertOpen] = useState(false); - const { goBack } = useAppHistory(); const { mutate: saveDrawing } = useMutation({ mutationFn: mutate(metaArtifactApi.upsert), @@ -65,7 +62,7 @@ export default function ExcalidrawEditor({ queryClient.invalidateQueries({ queryKey: ["drawing", drawingId, associatingId], }); - goBack(); + history.back(); }, }); @@ -119,7 +116,7 @@ export default function ExcalidrawEditor({ if (isDirty) { setIsAlertOpen(true); } else { - goBack(); + history.back(); } }; @@ -148,7 +145,7 @@ export default function ExcalidrawEditor({ className="bg-red-500 text-gray-50 shadow-xs hover:bg-red-500/90" onClick={() => { setIsAlertOpen(false); - goBack(); + history.back(); }} > {t("discard_changes")} diff --git a/src/components/ErrorPages/DefaultErrorPage.tsx b/src/components/ErrorPages/DefaultErrorPage.tsx index 4599db5130b..64d8a0577e8 100644 --- a/src/components/ErrorPages/DefaultErrorPage.tsx +++ b/src/components/ErrorPages/DefaultErrorPage.tsx @@ -6,7 +6,7 @@ import { cn } from "@/lib/utils"; import { Button } from "@/components/ui/button"; -import useAppHistory from "@/hooks/useAppHistory"; +import { navigate } from "raviger"; type ErrorType = "PAGE_NOT_FOUND" | "PAGE_LOAD_ERROR" | "CUSTOM_ERROR"; @@ -32,7 +32,6 @@ export default function ErrorPage({ ...props }: ErrorPageProps) { const { t } = useTranslation(); - const { goBack } = useAppHistory(); const [mousePos, setMousePos] = useState({ x: 0, y: 0 }); const containerRef = useRef(null); const [isHovering, setIsHovering] = useState(false); @@ -176,7 +175,7 @@ export default function ErrorPage({
+ {isDraftSaveable && (
- + {t("cancel")}
)}
- + + {/* Header */}
diff --git a/src/pages/Appointments/AppointmentDetail.tsx b/src/pages/Appointments/AppointmentDetail.tsx index 93edb18a551..cc8e8f9e696 100644 --- a/src/pages/Appointments/AppointmentDetail.tsx +++ b/src/pages/Appointments/AppointmentDetail.tsx @@ -101,7 +101,6 @@ import { Separator } from "@/components/ui/separator"; import { Textarea } from "@/components/ui/textarea"; import { usePermissions } from "@/context/PermissionContext"; import { useShortcutSubContext } from "@/context/ShortcutContext"; -import useAppHistory from "@/hooks/useAppHistory"; import { cn } from "@/lib/utils"; import { AppointmentDateSelection } from "@/pages/Appointments/BookAppointment/AppointmentDateSelection"; import { AppointmentSlotPicker } from "@/pages/Appointments/BookAppointment/AppointmentSlotPicker"; @@ -124,7 +123,6 @@ export default function AppointmentDetail(props: Props) { const queryClient = useQueryClient(); const { facility, facilityId, isFacilityLoading } = useCurrentFacility(); const { hasPermission } = usePermissions(); - const { goBack } = useAppHistory(); const [params, setQueryParams] = useQueryParams(); const { showSuccess } = params; const [{ from_queue }] = useQueryParams(); @@ -158,14 +156,14 @@ export default function AppointmentDetail(props: Props) { // If facility query failed (no access to facility) if (!facility) { toast.error(t("no_permission_to_view_page")); - goBack(`/`); + navigate(`/`); return; } // If facility is loaded but user doesn't have permission to view appointments if (facility && !canViewAppointments) { toast.error(t("no_permission_to_view_page")); - goBack(`/facility/${facility.id}/overview`); + navigate(`/facility/${facility.id}/overview`); return; } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -207,7 +205,7 @@ export default function AppointmentDetail(props: Props) {
- +

diff --git a/src/pages/Appointments/AppointmentsPage.tsx b/src/pages/Appointments/AppointmentsPage.tsx index add64c3eddd..c7302c6d8b6 100644 --- a/src/pages/Appointments/AppointmentsPage.tsx +++ b/src/pages/Appointments/AppointmentsPage.tsx @@ -57,7 +57,6 @@ import { TableSkeleton, } from "@/components/Common/SkeletonLoading"; -import useAppHistory from "@/hooks/useAppHistory"; import useFilters, { FilterState } from "@/hooks/useFilters"; import { getPermissions } from "@/common/Permissions"; @@ -208,7 +207,6 @@ export default function AppointmentsPage({ resourceType, resourceId }: Props) { .filter(Boolean) as TagConfig[]; const { hasPermission } = usePermissions(); - const { goBack } = useAppHistory(); const { canViewAppointments } = getPermissions( hasPermission, @@ -315,7 +313,7 @@ export default function AppointmentsPage({ resourceType, resourceId }: Props) { useEffect(() => { if (!isFacilityLoading && !canViewAppointments && !facility) { toast.error(t("no_permission_to_view_page")); - goBack("/"); + navigate("/"); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [canViewAppointments, facility, isFacilityLoading]); diff --git a/src/pages/Encounters/EncounterShow.tsx b/src/pages/Encounters/EncounterShow.tsx index dabc3ae57d9..c06e3ba2c87 100644 --- a/src/pages/Encounters/EncounterShow.tsx +++ b/src/pages/Encounters/EncounterShow.tsx @@ -19,7 +19,6 @@ import { Card } from "@/components/ui/card"; import { CommandShortcut } from "@/components/ui/command"; import { NavTabs } from "@/components/ui/nav-tabs"; import { Skeleton } from "@/components/ui/skeleton"; -import useAppHistory from "@/hooks/useAppHistory"; import useBreakpoints from "@/hooks/useBreakpoints"; import { useCareAppEncounterTabs } from "@/hooks/useCareApps"; import { useSidebarAutoCollapse } from "@/hooks/useSidebarAutoCollapse"; @@ -82,7 +81,6 @@ export const EncounterShow = (props: Props) => { const { t } = useTranslation(); const pluginTabs = useCareAppEncounterTabs(); - const { goBack } = useAppHistory(); const showMoreAfterIndex = useBreakpoints({ default: 2, xs: 2, @@ -107,7 +105,7 @@ export const EncounterShow = (props: Props) => { useEffect(() => { if (!isPrimaryEncounterLoading && !isPatientLoading && !canAccess) { toast.error(t("permission_denied_encounter")); - goBack("/"); + navigate("/"); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isPrimaryEncounterLoading, isPatientLoading]); diff --git a/src/pages/Encounters/ReportViewer.tsx b/src/pages/Encounters/ReportViewer.tsx index 916fcd8083f..284399b57dc 100644 --- a/src/pages/Encounters/ReportViewer.tsx +++ b/src/pages/Encounters/ReportViewer.tsx @@ -52,16 +52,12 @@ const POLL_INTERVAL_MS = 2000; const POLL_TIMEOUT_MS = 30000; interface ReportViewerProps { - facilityId: string; - patientId: string; encounterId: string; templateSlug?: string; reportId?: string; } export default function ReportViewer({ - facilityId: facilityId, - patientId: patientId, encounterId, templateSlug, reportId, @@ -385,7 +381,7 @@ export default function ReportViewer({ icon={} title={t("template_not_found")} action={ - + {t("back")} } @@ -402,11 +398,7 @@ export default function ReportViewer({ hideTitleOnPage componentRight={
- +

{template.name}

diff --git a/src/pages/Facility/FacilityDetailsPage.tsx b/src/pages/Facility/FacilityDetailsPage.tsx index 859aa06f4ef..9c6b0ca74da 100644 --- a/src/pages/Facility/FacilityDetailsPage.tsx +++ b/src/pages/Facility/FacilityDetailsPage.tsx @@ -4,7 +4,6 @@ import { toast } from "sonner"; import CareIcon from "@/CAREUI/icons/CareIcon"; -import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; import { Markdown } from "@/components/ui/markdown"; @@ -14,12 +13,12 @@ import { CardGridSkeleton } from "@/components/Common/SkeletonLoading"; import { FacilityMapsLink } from "@/components/Facility/FacilityMapLink"; import { Skeleton } from "@/components/ui/skeleton"; -import useAppHistory from "@/hooks/useAppHistory"; import useFilters from "@/hooks/useFilters"; import query from "@/Utils/request/query"; import publicFacilityApi from "@/types/facility/publicFacilityApi"; +import BackButton from "@/components/Common/BackButton"; import { FeatureBadge } from "./Utils"; import { UserCard } from "./components/UserCard"; @@ -29,7 +28,6 @@ interface Props { export function FacilityDetailsPage({ id }: Props) { const { t } = useTranslation(); - const { goBack } = useAppHistory(); const { data: facilityResponse, isLoading } = useQuery({ queryKey: ["facility", id], queryFn: query(publicFacilityApi.getAny, { @@ -85,13 +83,9 @@ export function FacilityDetailsPage({ id }: Props) {

{t("facility_not_found")}

- +
); @@ -100,14 +94,10 @@ export function FacilityDetailsPage({ id }: Props) { return (
- +
diff --git a/src/pages/Facility/billing/account/CreateInvoice.tsx b/src/pages/Facility/billing/account/CreateInvoice.tsx index 8a88de5bb15..f37e14668d9 100644 --- a/src/pages/Facility/billing/account/CreateInvoice.tsx +++ b/src/pages/Facility/billing/account/CreateInvoice.tsx @@ -7,7 +7,6 @@ import { } from "@tanstack/react-query"; import { CheckIcon, - ChevronLeft, ChevronRight, Package, PlusIcon, @@ -80,7 +79,6 @@ import { PaginatedResponse } from "@/Utils/request/types"; import { formatDateTime, formatName } from "@/Utils/utils"; import { EditInvoiceDialog } from "@/components/Billing/Invoice/EditInvoiceDialog"; -import BackButton from "@/components/Common/BackButton"; import { ResourceDefinitionCategoryPicker } from "@/components/Common/ResourceDefinitionCategoryPicker"; import { ResourceCategoryResourceType } from "@/types/base/resourceCategory/resourceCategory"; import { @@ -264,7 +262,7 @@ export function CreateInvoicePage({ onSuccess?.(); } else { onSuccess?.(); - navigate(invoiceUrl); + navigate(invoiceUrl, { replace: true }); } }, }); @@ -417,14 +415,6 @@ export function CreateInvoicePage({ {showHeader && (
- - - {t("back")} -