Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
15 changes: 6 additions & 9 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -42,14 +41,12 @@ const App = () => {
<PubSubProvider>
<ShortcutProvider>
<PluginEngine>
<HistoryAPIProvider>
<AuthUserProvider
unauthorized={<Routers.PublicRouter />}
otpAuthorized={<Routers.PatientRouter />}
>
<Routers.AppRouter />
</AuthUserProvider>
</HistoryAPIProvider>
<AuthUserProvider
unauthorized={<Routers.PublicRouter />}
otpAuthorized={<Routers.PatientRouter />}
>
<Routers.AppRouter />
</AuthUserProvider>
<Toaster
position="top-center"
theme="light"
Expand Down
11 changes: 3 additions & 8 deletions src/CAREUI/misc/PrintPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { Button } from "@/components/ui/button";

import Page from "@/components/Common/Page";

import BackButton from "@/components/Common/BackButton";
import { useShortcutSubContext } from "@/context/ShortcutContext";
import useAppHistory from "@/hooks/useAppHistory";
import useAutoPrint, { AutoPrintOptions } from "@/hooks/useAutoPrint";
import useBreakpoints from "@/hooks/useBreakpoints";
import { FacilityRead } from "@/types/facility/facility";
Expand All @@ -38,7 +38,6 @@ type Props = {

export default function PrintPreview(props: Props) {
const initialScale = useBreakpoints({ default: 0.44, md: 1 });
const { goBack } = useAppHistory();
const { t } = useTranslation();
useShortcutSubContext();

Expand All @@ -61,14 +60,10 @@ export default function PrintPreview(props: Props) {
options={
<div className="flex items-center gap-2">
{props.showBackButton !== false && (
<Button
variant="outline"
onClick={() => goBack()}
data-shortcut-id="go-back"
>
<BackButton variant="outline" data-shortcut-id="go-back">
<CareIcon icon="l-arrow-left" className="text-lg" />
{t("back")}
</Button>
</BackButton>
)}
<Button
variant="primary"
Expand Down
38 changes: 0 additions & 38 deletions src/Providers/HistoryAPIProvider.tsx

This file was deleted.

18 changes: 4 additions & 14 deletions src/Routers/routes/ConsultationRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,22 +103,12 @@ const consultationRoutes: AppRoutes = {
<TreatmentSummary encounterId={encounterId} patientId={patientId} />
),
"/facility/:facilityId/patient/:patientId/encounter/:encounterId/report/template/:templateSlug":
({ facilityId, encounterId, patientId, templateSlug }) => (
<ReportViewer
facilityId={facilityId}
patientId={patientId}
encounterId={encounterId}
templateSlug={templateSlug}
/>
({ encounterId, templateSlug }) => (
<ReportViewer encounterId={encounterId} templateSlug={templateSlug} />
),
"/facility/:facilityId/patient/:patientId/encounter/:encounterId/report/:reportId":
({ facilityId, encounterId, patientId, reportId }) => (
<ReportViewer
facilityId={facilityId}
encounterId={encounterId}
patientId={patientId}
reportId={reportId}
/>
({ encounterId, reportId }) => (
<ReportViewer encounterId={encounterId} reportId={reportId} />
),
"/facility/:facilityId/patient/:patientId/encounter/:encounterId/questionnaire":
({ facilityId, encounterId, patientId }) => (
Expand Down
45 changes: 22 additions & 23 deletions src/components/Common/BackButton.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
import { Link } from "raviger";

import { Button } from "@/components/ui/button";

import useAppHistory from "@/hooks/useAppHistory";
import { Button, ButtonSize, ButtonVariant } from "@/components/ui/button";

type BackButtonProps = {
to?: string;
fallbackUrl?: string;
} & React.ComponentProps<typeof Button>;

children: React.ReactNode;
variant?: ButtonVariant;
className?: string;
size?: ButtonSize;
disabled?: boolean;
} & Omit<React.ComponentProps<"button">, "onClick">;
export default function BackButton({
to,
fallbackUrl,
children,
variant = "outline",
className,
size = "default",
disabled = false,
...props
}: BackButtonProps) {
const { history } = useAppHistory();

to ??= history[1] ?? fallbackUrl;

if (!to) {
return null;
}

return (
<Button variant="outline" data-shortcut-id="go-back" asChild {...props}>
<Link basePath="/" href={to}>
{props.children}
</Link>
<Button
type="button"
variant={variant}
onClick={() => history.back()}
className={className}
size={size}
disabled={disabled}
{...props}
Comment on lines +19 to +26
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Prop spread order allows type to be overridden.

The {...props} spread at Line 26 comes after type="button" at Line 20. Since type is not omitted from BackButtonProps, a caller could pass type="submit", which would override type="button" and potentially cause unintended form submissions.

🛡️ Proposed fix: spread props before explicit values or omit `type`

Option 1 - Spread props first so explicit values take precedence:

     <Button
+      {...props}
       type="button"
       variant={variant}
       onClick={() => history.back()}
       className={className}
       size={size}
       disabled={disabled}
-      {...props}
     >

Option 2 - Omit type from allowed props:

-} & Omit<React.ComponentProps<"button">, "onClick">;
+} & Omit<React.ComponentProps<"button">, "onClick" | "type">;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Common/BackButton.tsx` around lines 19 - 26, The BackButton
component currently spreads {...props} after setting type="button" on the
Button, allowing callers to override the button type; update BackButton so the
explicit type cannot be overridden by either (a) move the {...props} spread
before the explicit props so type="button" takes precedence on the Button, or
(b) remove/omit "type" from BackButtonProps (e.g. use Omit<BackButtonProps,
"type">) so callers cannot pass a type prop; ensure the component (BackButton)
still passes variant, onClick, className, size, disabled to the Button and that
Button.type remains "button".

Comment on lines +19 to +26
Comment on lines +20 to +26
Comment on lines +19 to +26
>
Comment on lines +19 to +27
{children}
</Button>
);
}
9 changes: 3 additions & 6 deletions src/components/Common/Drawings/ExcalidrawEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -57,15 +55,14 @@ 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),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["drawing", drawingId, associatingId],
});
goBack();
history.back();
},
});

Expand Down Expand Up @@ -119,7 +116,7 @@ export default function ExcalidrawEditor({
if (isDirty) {
setIsAlertOpen(true);
} else {
goBack();
history.back();
}
};

Expand Down Expand Up @@ -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")}
Expand Down
5 changes: 2 additions & 3 deletions src/components/ErrorPages/DefaultErrorPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -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<HTMLDivElement>(null);
const [isHovering, setIsHovering] = useState(false);
Expand Down Expand Up @@ -176,7 +175,7 @@ export default function ErrorPage({
<div className="mt-6">
<Button
onClick={() => {
goBack("/");
navigate("/");
window.location.reload();
}}
Comment on lines 177 to 180
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n src/components/ErrorPages/DefaultErrorPage.tsx | head -200

Repository: ohcnetwork/care_fe

Length of output: 7533


🏁 Script executed:

rg -A 5 -B 5 "onClick.*navigate.*reload" src/components/ErrorPages/

Repository: ohcnetwork/care_fe

Length of output: 44


🏁 Script executed:

rg -A 3 -B 3 "window.location.replace" src/

Repository: ohcnetwork/care_fe

Length of output: 44


🏁 Script executed:

rg -B 2 -A 5 "navigate\(" src/components/ErrorPages/ | head -30

Repository: ohcnetwork/care_fe

Length of output: 831


🏁 Script executed:

rg "useRedirect|navigate.*replace" src/ -A 2 -B 2 | head -40

Repository: ohcnetwork/care_fe

Length of output: 899


🏁 Script executed:

fd -e "ts" -e "tsx" src/ -x grep -l "raviger" | head -5 | xargs -I {} sh -c 'echo "File: {}"; grep -A 2 -B 2 "navigate\(" {} | head -15'

Repository: ohcnetwork/care_fe

Length of output: 383


🏁 Script executed:

rg "PAGE_LOAD_ERROR|PAGE_NOT_FOUND" src/ -A 5 -B 5 | head -50

Repository: ohcnetwork/care_fe

Length of output: 3185


🏁 Script executed:

rg "window.location.reload" src/ -B 3 -A 1

Repository: ohcnetwork/care_fe

Length of output: 996


Simplify recovery navigation to avoid redundant calls.

The navigate("/") call is unnecessary before window.location.reload(). Use navigate("/", { replace: true }) to handle the redirect without triggering an additional SPA navigation that gets replaced by the full page reload.

💡 Suggested fix
             onClick={() => {
-              navigate("/");
-              window.location.reload();
+              navigate("/", { replace: true });
             }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onClick={() => {
goBack("/");
navigate("/");
window.location.reload();
}}
onClick={() => {
navigate("/", { replace: true });
}}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/ErrorPages/DefaultErrorPage.tsx` around lines 177 - 180, The
onClick handler in DefaultErrorPage.tsx currently calls navigate("/") and then
window.location.reload(), which is redundant; change the navigate call to
navigate("/", { replace: true }) to avoid pushing a history entry before the
full-page reload (keep the subsequent window.location.reload() if you still want
a hard reload), i.e., update the onClick lambda that references navigate and
window.location.reload accordingly.

className="rounded-md bg-primary-700 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-primary-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-800"
Expand Down
15 changes: 1 addition & 14 deletions src/components/Facility/FacilityDeleteDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import { buttonVariants } from "@/components/ui/button";

import CriticalActionConfirmationDialog from "@/components/Common/CriticalActionConfirmationDialog";

import useAppHistory from "@/hooks/useAppHistory";

import mutate from "@/Utils/request/mutate";
import facilityApi from "@/types/facility/facilityApi";

Expand All @@ -27,7 +25,6 @@ const FacilityDeleteDialog = ({
trigger,
}: FacilityDeleteDialogProps) => {
const { t } = useTranslation();
const { goBack, history } = useAppHistory();
const queryClient = useQueryClient();

const [open, setOpen] = useState(false);
Expand All @@ -53,17 +50,7 @@ const FacilityDeleteDialog = ({
});

setOpen(false);

if (history.length > 1) {
const prevPath = history[1];
if (prevPath.startsWith("/facility/")) {
navigate("/");
} else {
goBack("/");
}
} else {
navigate("/");
}
navigate("/");
},
onError: () => {
setOpen(false);
Expand Down
4 changes: 0 additions & 4 deletions src/components/Patient/EncounterQuestionnaire.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import { Card, CardContent } from "@/components/ui/card";
import Page from "@/components/Common/Page";
import { QuestionnaireForm } from "@/components/Questionnaire/QuestionnaireForm";

import useAppHistory from "@/hooks/useAppHistory";

import query from "@/Utils/request/query";
import {
PatientDeceasedInfo,
Expand All @@ -33,7 +31,6 @@ export default function EncounterQuestionnaire({
}: Props) {
const { t } = useTranslation();

const { goBack } = useAppHistory();
const { data: encounter } = useQuery({
queryKey: ["encounter", encounterId],
queryFn: query(encounterApi.get, {
Expand Down Expand Up @@ -81,7 +78,6 @@ export default function EncounterQuestionnaire({
navigate(`/patient/${patientId}/updates`);
}
}}
onCancel={() => goBack()}
/>
</CardContent>
</Card>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useQuery } from "@tanstack/react-query";
import { useQueryParams } from "raviger";
import { navigate, useQueryParams } from "raviger";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
Expand All @@ -14,8 +14,6 @@ import CreateEncounterForm from "@/components/Encounter/CreateEncounterForm";
import { TimelineEncounterCard } from "@/components/Facility/EncounterCard";
import { PatientProps } from "@/components/Patient/PatientDetailsTab";

import useAppHistory from "@/hooks/useAppHistory";

import { getPermissions } from "@/common/Permissions";

import { ShortcutBadge } from "@/Utils/keyboardShortcutComponents";
Expand All @@ -40,7 +38,6 @@ const EncounterHistory = (props: PatientProps) => {
hasPermission,
patientData.permissions,
);
const { goBack } = useAppHistory();

const { data: encounterData, isLoading } = useQuery({
queryKey: ["encounterHistory", patientId, qParams],
Expand All @@ -57,7 +54,7 @@ const EncounterHistory = (props: PatientProps) => {
useEffect(() => {
if (!canViewPatients) {
toast.error(t("no_permission_to_view_page"));
goBack(`/facility/${facilityId}/patient/${patientId}`);
navigate(`/facility/${facilityId}/patient/${patientId}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether PatientProps allows missing facilityId and which patient routes exist.

echo "== PatientProps definition =="
fd "PatientDetailsTab.tsx" src | xargs -I{} rg -n -C3 "interface PatientProps|facilityId\\??|facilityId:" {}

echo
echo "== Patient history route patterns in router files =="
fd ".*Routes\\.tsx$" src/Routers/routes | xargs -I{} rg -n -C2 "/facility/:facilityId/patient/:patientId|/patient/:patientId" {}

Repository: ohcnetwork/care_fe

Length of output: 7397


🏁 Script executed:

#!/bin/bash
# Locate and read EncounterHistory.tsx
echo "== Finding EncounterHistory.tsx =="
fd "EncounterHistory.tsx" src/

echo
echo "== Reading EncounterHistory.tsx (full file) =="
fd "EncounterHistory.tsx" src/ | head -1 | xargs cat

Repository: ohcnetwork/care_fe

Length of output: 5700


🏁 Script executed:

#!/bin/bash
# Search for PatientProps interface definition
echo "== PatientProps definition =="
rg -n "interface PatientProps|type PatientProps" src/components/Patient/PatientDetailsTab/ -A10

echo
echo "== facilityId usage in EncounterHistory context =="
rg -n "facilityId" src/components/Patient/PatientDetailsTab/EncounterHistory.tsx -B2 -A2

Repository: ohcnetwork/care_fe

Length of output: 2049


🏁 Script executed:

#!/bin/bash
# Verify the patient-scoped route exists and is used in ClinicalHistoryPage
echo "== Search for /patient/:patientId/history pattern =="
rg "/patient/:patientId/history" src/Routers/routes -B1 -A3

echo
echo "== Verify ClinicalHistoryPage accepts patientId without facilityId =="
rg -n "ClinicalHistoryPage" src/Routers/routes -B2 -A8 | head -30

Repository: ohcnetwork/care_fe

Length of output: 4385


Guard unauthorized redirect to handle missing facilityId.

Line 57 unconditionally navigates to a facility-scoped URL, but facilityId is optional in PatientProps. When absent, this produces /facility/undefined/patient/${patientId}. Add a patient-scoped fallback to match the existing route pattern.

💡 Suggested fix
-      navigate(`/facility/${facilityId}/patient/${patientId}`);
+      navigate(
+        facilityId
+          ? `/facility/${facilityId}/patient/${patientId}`
+          : `/patient/${patientId}`,
+      );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Patient/PatientDetailsTab/EncounterHistory.tsx` at line 57,
The redirect unconditionally uses facilityId which may be undefined, causing
URLs like /facility/undefined/patient/:patientId; update the navigation logic in
EncounterHistory (where navigate(...) is called) to check facilityId from
PatientProps and, if present, call
navigate(`/facility/${facilityId}/patient/${patientId}`), otherwise fallback to
the patient-scoped route such as navigate(`/patient/${patientId}`); ensure you
reference the facilityId and patientId variables from the component props and
adjust any types if necessary.

}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [canViewPatients]);
Expand Down
Loading
Loading