Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
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
43 changes: 0 additions & 43 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
7 changes: 2 additions & 5 deletions src/components/Patient/PatientDetailsTab/patientUpdates.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link } from "raviger";
import { Link, navigate } from "raviger";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
Expand All @@ -9,8 +9,6 @@ import { Button } from "@/components/ui/button";

import QuestionnaireResponsesList from "@/components/Facility/ConsultationDetails/QuestionnaireResponsesList";

import useAppHistory from "@/hooks/useAppHistory";

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

import { usePermissions } from "@/context/PermissionContext";
Expand All @@ -22,7 +20,6 @@ export const Updates = (props: PatientProps) => {
const patientId = patientData.id;
const { t } = useTranslation();
const { hasPermission } = usePermissions();
const { goBack } = useAppHistory();
const {
canViewPatientQuestionnaireResponses,
canSubmitPatientQuestionnaireResponses,
Expand All @@ -31,7 +28,7 @@ export const Updates = (props: PatientProps) => {
useEffect(() => {
if (!canViewPatientQuestionnaireResponses) {
toast.error(t("no_permission_to_view_page"));
goBack(
navigate(
facilityId
? `/facility/${facilityId}/patient/${patientId}`
: `/patient/${patientId}`,
Expand Down
Loading
Loading