From c95a757a5b060f5e2af7e02c1fb582ae46430cb1 Mon Sep 17 00:00:00 2001 From: abhimanyurajeesh Date: Tue, 2 Jun 2026 23:47:29 +0530 Subject: [PATCH 1/9] feat: refactor ReportViewer for Account report --- src/Routers/routes/ConsultationRoutes.tsx | 4 +- src/Routers/routes/FacilityRoutes.tsx | 11 ++++ src/components/Common/FilePreviewDialog.tsx | 37 ------------- src/components/Files/ReportSubTab.tsx | 8 +-- src/pages/Encounters/ReportViewer.tsx | 54 +++++++++++++------ .../Facility/billing/account/AccountShow.tsx | 3 ++ 6 files changed, 60 insertions(+), 57 deletions(-) diff --git a/src/Routers/routes/ConsultationRoutes.tsx b/src/Routers/routes/ConsultationRoutes.tsx index 1f2c0916eb6..6eeb6881559 100644 --- a/src/Routers/routes/ConsultationRoutes.tsx +++ b/src/Routers/routes/ConsultationRoutes.tsx @@ -104,11 +104,11 @@ const consultationRoutes: AppRoutes = { ), "/facility/:facilityId/patient/:patientId/encounter/:encounterId/report/template/:templateSlug": ({ encounterId, templateSlug }) => ( - + ), "/facility/:facilityId/patient/:patientId/encounter/:encounterId/report/:reportId": ({ encounterId, reportId }) => ( - + ), "/facility/:facilityId/patient/:patientId/encounter/:encounterId/questionnaire": ({ facilityId, encounterId, patientId }) => ( diff --git a/src/Routers/routes/FacilityRoutes.tsx b/src/Routers/routes/FacilityRoutes.tsx index 2389dbfc538..ce4339d1484 100644 --- a/src/Routers/routes/FacilityRoutes.tsx +++ b/src/Routers/routes/FacilityRoutes.tsx @@ -7,6 +7,7 @@ import MedicationDispenseRedirect from "@/pages/Facility/billing/account/compone import BedAvailabilityDashboard from "@/pages/Facility/BedAvailabilityDashboard"; import { AppRoutes } from "@/Routers/AppRouter"; +import ReportViewer from "@/pages/Encounters/ReportViewer"; import TemplateBuilder from "@/pages/Encounters/TemplateBuilder/TemplateBuilder"; import TemplatePage from "@/pages/Encounters/TemplateBuilder/TemplatePage"; import AccountList from "@/pages/Facility/billing/account/AccountList"; @@ -104,6 +105,16 @@ const FacilityRoutes: AppRoutes = { facilityId, accountId, }) => , + "/facility/:facilityId/billing/account/:accountId/reports/:reportId": ({ + accountId, + reportId, + }) => ( + + ), "/facility/:facilityId/billing/account/:accountId/:tab": ({ facilityId, accountId, diff --git a/src/components/Common/FilePreviewDialog.tsx b/src/components/Common/FilePreviewDialog.tsx index 6293107ea30..29eefca4fb8 100644 --- a/src/components/Common/FilePreviewDialog.tsx +++ b/src/components/Common/FilePreviewDialog.tsx @@ -28,8 +28,6 @@ import { FileReadMinimal, getVideoMimeType, } from "@/types/files/file"; -import { ShortcutBadge } from "@/Utils/keyboardShortcutComponents"; -import { Printer } from "lucide-react"; const PDFViewer = lazy(() => import("@/components/Common/PDFViewer")); export interface StateInterface { @@ -247,41 +245,6 @@ export default function FilePreviewDialog(props: FilePreviewProps) { )}
- {file_state.extension === "pdf" && ( - - )} {file_state.extension === "pdf" && fileUrl && ( diff --git a/src/pages/Facility/billing/account/AccountShow.tsx b/src/pages/Facility/billing/account/AccountShow.tsx index 1ec3eff4d5a..2cc26c5f9cd 100644 --- a/src/pages/Facility/billing/account/AccountShow.tsx +++ b/src/pages/Facility/billing/account/AccountShow.tsx @@ -331,6 +331,9 @@ export function AccountShow({ + `/facility/${facilityId}/billing/account/${accountId}/reports/${reportId}` + } /> ), shortcutId: "switch-to-reports-tab", From e917f543d274cb3c0260500f77091392e7cf4179 Mon Sep 17 00:00:00 2001 From: abhimanyurajeesh Date: Tue, 2 Jun 2026 23:59:37 +0530 Subject: [PATCH 2/9] feat: update ReportViewer to use ReportType enum for reportType prop --- src/Routers/routes/FacilityRoutes.tsx | 3 ++- src/pages/Encounters/ReportViewer.tsx | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Routers/routes/FacilityRoutes.tsx b/src/Routers/routes/FacilityRoutes.tsx index ce4339d1484..fe5f78cd4e0 100644 --- a/src/Routers/routes/FacilityRoutes.tsx +++ b/src/Routers/routes/FacilityRoutes.tsx @@ -29,6 +29,7 @@ import DiagnosticReportPrint from "@/pages/Facility/services/diagnosticReports/D import DiagnosticReportView from "@/pages/Facility/services/diagnosticReports/DiagnosticReportView"; import ServiceRequestShow from "@/pages/Facility/services/serviceRequests/ServiceRequestShow"; import { SettingsLayout } from "@/pages/Facility/settings/layout"; +import { ReportType } from "@/types/emr/report/report"; const FacilityRoutes: AppRoutes = { "/facility": () => , @@ -112,7 +113,7 @@ const FacilityRoutes: AppRoutes = { ), "/facility/:facilityId/billing/account/:accountId/:tab": ({ diff --git a/src/pages/Encounters/ReportViewer.tsx b/src/pages/Encounters/ReportViewer.tsx index bc08e0391ab..5e2a5d425ba 100644 --- a/src/pages/Encounters/ReportViewer.tsx +++ b/src/pages/Encounters/ReportViewer.tsx @@ -39,7 +39,7 @@ import { EmptyState } from "@/components/ui/empty-state"; import { usePermissions } from "@/context/PermissionContext"; import { cn } from "@/lib/utils"; import { useCurrentFacilitySilently } from "@/pages/Facility/utils/useCurrentFacility"; -import { ReportReadList } from "@/types/emr/report/report"; +import { ReportReadList, ReportType } from "@/types/emr/report/report"; import reportApi from "@/types/emr/report/reportApi"; import { TemplateBaseRead } from "@/types/emr/template/template"; import templateApi from "@/types/emr/template/templateApi"; @@ -55,14 +55,14 @@ interface ReportViewerProps { associatingId: string; templateSlug?: string; reportId?: string; - reportType?: string; + reportType?: ReportType; } export default function ReportViewer({ associatingId, templateSlug, reportId, - reportType = "discharge_summary", + reportType = ReportType.DISCHARGE_SUMMARY, }: ReportViewerProps) { const { t } = useTranslation(); const queryClient = useQueryClient(); From 73c196c16fb1ebf70c883cbfc5503181a6473207 Mon Sep 17 00:00:00 2001 From: abhimanyurajeesh Date: Wed, 3 Jun 2026 12:32:57 +0530 Subject: [PATCH 3/9] feat: add account report templates dropdown in AccountShow component --- src/Routers/routes/FacilityRoutes.tsx | 8 ++++ .../Facility/billing/account/AccountShow.tsx | 44 ++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/Routers/routes/FacilityRoutes.tsx b/src/Routers/routes/FacilityRoutes.tsx index fe5f78cd4e0..2171f712812 100644 --- a/src/Routers/routes/FacilityRoutes.tsx +++ b/src/Routers/routes/FacilityRoutes.tsx @@ -106,6 +106,14 @@ const FacilityRoutes: AppRoutes = { facilityId, accountId, }) => , + "/facility/:facilityId/billing/account/:accountId/reports/template/:templateSlug": + ({ accountId, templateSlug }) => ( + + ), "/facility/:facilityId/billing/account/:accountId/reports/:reportId": ({ accountId, reportId, diff --git a/src/pages/Facility/billing/account/AccountShow.tsx b/src/pages/Facility/billing/account/AccountShow.tsx index 2cc26c5f9cd..a19c01bf3db 100644 --- a/src/pages/Facility/billing/account/AccountShow.tsx +++ b/src/pages/Facility/billing/account/AccountShow.tsx @@ -1,7 +1,7 @@ import { DialogDescription } from "@radix-ui/react-dialog"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { formatDistanceToNow } from "date-fns"; -import { Hash, MoreVertical } from "lucide-react"; +import { FileText, Hash, Loader, MoreVertical } from "lucide-react"; import { Link, navigate } from "raviger"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -23,6 +23,8 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { MonetaryDisplay } from "@/components/ui/monetary-display"; @@ -69,6 +71,7 @@ import { } from "@/pages/Facility/billing/account/utils"; import useCurrentFacility from "@/pages/Facility/utils/useCurrentFacility"; import { ReportType } from "@/types/emr/report/report"; +import templateApi from "@/types/emr/template/templateApi"; import AccountSheet from "./AccountSheet"; import TransferPaymentSheet from "./TransferPaymentSheet"; import BedChargeItemsTable from "./components/BedChargeItemsTable"; @@ -128,6 +131,7 @@ export function AccountShow({ }); }; const [transferPaymentOpen, setTransferPaymentOpen] = useState(false); + const [dropdownOpen, setDropdownOpen] = useState(false); const queryClient = useQueryClient(); const [closeAccountStatus, setCloseAccountStatus] = useState<{ sheetOpen: boolean; @@ -166,6 +170,20 @@ export function AccountShow({ const hasBillableItems = (billableChargeItems?.count ?? 0) > 0; + const { data: templatesData, isLoading: isLoadingTemplates } = useQuery({ + queryKey: ["templates", facilityId, "account_report"], + queryFn: query(templateApi.listTemplates, { + queryParams: { + facility: facilityId, + template_type: "account_report", + status: "active", + }, + }), + enabled: dropdownOpen, + }); + + const accountTemplates = templatesData?.results ?? []; + const showMoreAfterIndex = useBreakpoints({ default: 1, xs: 2, @@ -423,7 +441,7 @@ export function AccountShow({
)} {account.status == AccountStatus.active && ( - + + + +
+
+ {(isLoading || !templatesData) && ( +
+ + {t("loading")} +
+ )} + {!isLoading && templatesData && templates.length === 0 && ( +
+ {t("no_templates_found")} +
+ )} + {templates.map((template) => ( + + + + {template.name} + + + ))} +
+ {!isLoading && templatesData && templates.length > 0 && ( + + )} +
+
+
+ ); +} diff --git a/src/components/Files/ReportSubTab.tsx b/src/components/Files/ReportSubTab.tsx index 6e4d2b8be16..c2b670634ef 100644 --- a/src/components/Files/ReportSubTab.tsx +++ b/src/components/Files/ReportSubTab.tsx @@ -34,7 +34,7 @@ import useFilters from "@/hooks/useFilters"; import useReportManager from "@/hooks/useReportManager"; import queryClient from "@/Utils/request/queryClient"; -import TemplateReportSheet from "@/pages/Encounters/TemplateBuilder/TemplateReportSheet"; +import { GenerateReportDropdown } from "@/components/Files/GenerateReportDropdown"; import { useCurrentFacilitySilently } from "@/pages/Facility/utils/useCurrentFacility"; import { ReportRead, @@ -53,6 +53,24 @@ interface ReportTabProps { getViewUrl?: (reportId: string) => string; } +function buildReportPath( + facilityId: string, + reportIdOrSlug: string, + options?: { patientId?: string; encounterId?: string; isTemplate?: boolean }, +) { + const segment = options?.isTemplate + ? `template/${reportIdOrSlug}` + : reportIdOrSlug; + + if (options?.patientId && options?.encounterId) { + return `/facility/${facilityId}/patient/${options.patientId}/encounter/${options.encounterId}/report/${segment}`; + } + if (options?.patientId) { + return `/facility/${facilityId}/patient/${options.patientId}/report/${segment}`; + } + return `/facility/${facilityId}/reports/${segment}`; +} + export function ReportSubTab({ associatingId, reportType, @@ -63,6 +81,7 @@ export function ReportSubTab({ }: ReportTabProps) { const { t } = useTranslation(); const { facility } = useCurrentFacilitySilently(); + const resolvedFacilityId = facilityId ?? facility?.id; const { qParams, updateQuery, Pagination } = useFilters({ limit: 15, disableCache: true, @@ -74,7 +93,6 @@ export function ReportSubTab({ viewFile, downloadFile, archiveReport, - refetch, Dialogs, } = useReportManager({ associatingId, @@ -103,9 +121,12 @@ export function ReportSubTab({ const handleView = (report: ReportReadList) => { if (getViewUrl) { navigate(getViewUrl(report.id)); - } else if (facilityId && patientId && encounterId) { + } else if (resolvedFacilityId) { navigate( - `/facility/${facilityId}/patient/${patientId}/encounter/${encounterId}/report/${report.id}`, + buildReportPath(resolvedFacilityId, report.id, { + patientId, + encounterId, + }), ); } else { viewFile(report); @@ -375,21 +396,20 @@ export function ReportSubTab({ {t("refresh")} - {facility && ( - - - {t("generate_report")} - + getReportUrl={(slug) => + getViewUrl + ? getViewUrl(`template/${slug}`) + : buildReportPath(resolvedFacilityId, slug, { + patientId, + encounterId, + isTemplate: true, + }) } - onSuccess={() => { - refetch(); - }} /> )} diff --git a/src/components/ui/multi-filter/utils/navigation-helper.tsx b/src/components/ui/multi-filter/utils/navigation-helper.tsx index 66d2117acd5..9745fe79cc7 100644 --- a/src/components/ui/multi-filter/utils/navigation-helper.tsx +++ b/src/components/ui/multi-filter/utils/navigation-helper.tsx @@ -7,8 +7,10 @@ import useBreakpoints from "@/hooks/useBreakpoints"; export default function NavigationHelper({ isActiveFilter, + hideRight, }: { isActiveFilter?: boolean; + hideRight?: boolean; }) { const { t } = useTranslation(); const isMobile = useBreakpoints({ sm: false, default: true }); @@ -33,7 +35,7 @@ export default function NavigationHelper({
- {!isActiveFilter && ( + {!isActiveFilter && !hideRight && (
From 7e591e3089d80b05849af4fd06db987543fec04a Mon Sep 17 00:00:00 2001 From: abhimanyurajeesh Date: Wed, 3 Jun 2026 20:22:43 +0530 Subject: [PATCH 6/9] refactor: remove TemplateReportSheet component and its dependencies --- .../TemplateBuilder/TemplateReportSheet.tsx | 86 ------------------- 1 file changed, 86 deletions(-) delete mode 100644 src/pages/Encounters/TemplateBuilder/TemplateReportSheet.tsx diff --git a/src/pages/Encounters/TemplateBuilder/TemplateReportSheet.tsx b/src/pages/Encounters/TemplateBuilder/TemplateReportSheet.tsx deleted file mode 100644 index b086c5d6feb..00000000000 --- a/src/pages/Encounters/TemplateBuilder/TemplateReportSheet.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { useState } from "react"; -import { useTranslation } from "react-i18next"; - -import { Button } from "@/components/ui/button"; -import { - Sheet, - SheetContent, - SheetHeader, - SheetTitle, - SheetTrigger, -} from "@/components/ui/sheet"; - -import { getPermissions } from "@/common/Permissions"; - -import { usePermissions } from "@/context/PermissionContext"; - -import { TemplateType } from "@/types/emr/template/template"; -import { navigate } from "raviger"; -import TemplateList from "./TemplateList"; - -interface TemplateReportSheetProps { - facilityId: string; - encounterId?: string; - patientId?: string; - associatingId: string; - trigger: React.ReactNode; - onSuccess?: () => void; - permissions: string[]; - reportType?: TemplateType; -} - -export default function TemplateReportSheet({ - facilityId, - associatingId, - trigger, - permissions, - reportType, - onSuccess, -}: TemplateReportSheetProps) { - const { t } = useTranslation(); - const [open, setOpen] = useState(false); - const { hasPermission } = usePermissions(); - const { canWriteTemplate } = getPermissions(hasPermission, permissions); - - const handleSuccess = () => { - setOpen(false); - onSuccess?.(); - }; - - return ( - - {trigger} - - - - {t("available_templates")} - {canWriteTemplate && ( - - )} - - -
- -
-
-
- ); -} From fbdfdb3918d9bec267030fdb2c9fbfcff3ab35f7 Mon Sep 17 00:00:00 2001 From: abhimanyurajeesh Date: Thu, 4 Jun 2026 14:30:02 +0530 Subject: [PATCH 7/9] refactor: remove associatingId prop from GenerateReportDropdown and ReportSubTab components --- src/components/Files/GenerateReportDropdown.tsx | 3 +-- src/components/Files/ReportSubTab.tsx | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/Files/GenerateReportDropdown.tsx b/src/components/Files/GenerateReportDropdown.tsx index 725338fa901..4bf29c7caae 100644 --- a/src/components/Files/GenerateReportDropdown.tsx +++ b/src/components/Files/GenerateReportDropdown.tsx @@ -19,7 +19,6 @@ import templateApi from "@/types/emr/template/templateApi"; interface GenerateReportDropdownProps { facilityId: string; - associatingId: string; reportType?: TemplateType; getReportUrl: (templateSlug: string) => string; } @@ -56,7 +55,7 @@ export function GenerateReportDropdown({
diff --git a/src/components/Files/ReportSubTab.tsx b/src/components/Files/ReportSubTab.tsx index c2b670634ef..7b1e9cdc69a 100644 --- a/src/components/Files/ReportSubTab.tsx +++ b/src/components/Files/ReportSubTab.tsx @@ -399,7 +399,6 @@ export function ReportSubTab({ {resolvedFacilityId && ( getViewUrl From afb773b1ce82cb04a43a6c72a62110f9246f9138 Mon Sep 17 00:00:00 2001 From: abhimanyurajeesh Date: Fri, 5 Jun 2026 11:11:22 +0530 Subject: [PATCH 8/9] refactor: update reportType type in GenerateReportDropdown and add it to ReportViewer --- src/components/Files/GenerateReportDropdown.tsx | 6 +++--- src/pages/Encounters/ReportViewer.tsx | 9 ++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/Files/GenerateReportDropdown.tsx b/src/components/Files/GenerateReportDropdown.tsx index 4bf29c7caae..90b9e95ef0a 100644 --- a/src/components/Files/GenerateReportDropdown.tsx +++ b/src/components/Files/GenerateReportDropdown.tsx @@ -14,12 +14,12 @@ import { import NavigationHelper from "@/components/ui/multi-filter/utils/navigation-helper"; import query from "@/Utils/request/query"; -import { TemplateType } from "@/types/emr/template/template"; +import { ReportType } from "@/types/emr/report/report"; import templateApi from "@/types/emr/template/templateApi"; interface GenerateReportDropdownProps { facilityId: string; - reportType?: TemplateType; + reportType?: ReportType; getReportUrl: (templateSlug: string) => string; } @@ -83,7 +83,7 @@ export function GenerateReportDropdown({ ))}
{!isLoading && templatesData && templates.length > 0 && ( - + )}
diff --git a/src/pages/Encounters/ReportViewer.tsx b/src/pages/Encounters/ReportViewer.tsx index 8bd36a68d83..9a637be1939 100644 --- a/src/pages/Encounters/ReportViewer.tsx +++ b/src/pages/Encounters/ReportViewer.tsx @@ -117,7 +117,13 @@ export default function ReportViewer({ isLoading: isLoadingReports, refetch: refetchReports, } = useQuery({ - queryKey: ["reports", associatingId, "template", effectiveTSlug], + queryKey: [ + "reports", + associatingId, + "template", + effectiveTSlug, + reportType, + ], queryFn: query(reportApi.listReports, { queryParams: { associating_id: associatingId, @@ -206,6 +212,7 @@ export default function ReportViewer({ associatingId, "template", effectiveTSlug, + reportType, "fresh", ], queryFn: query(reportApi.listReports, { From 60945bdf57523fe34837e882609d29595c3ff4e2 Mon Sep 17 00:00:00 2001 From: abhimanyurajeesh Date: Fri, 5 Jun 2026 11:36:19 +0530 Subject: [PATCH 9/9] refactor: simplify loading state --- src/components/Files/GenerateReportDropdown.tsx | 2 +- src/components/Files/ReportSubTab.tsx | 2 +- src/pages/Encounters/ReportViewer.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Files/GenerateReportDropdown.tsx b/src/components/Files/GenerateReportDropdown.tsx index 90b9e95ef0a..0871b21d999 100644 --- a/src/components/Files/GenerateReportDropdown.tsx +++ b/src/components/Files/GenerateReportDropdown.tsx @@ -59,7 +59,7 @@ export function GenerateReportDropdown({ >
- {(isLoading || !templatesData) && ( + {isLoading && (
{t("loading")} diff --git a/src/components/Files/ReportSubTab.tsx b/src/components/Files/ReportSubTab.tsx index 7b1e9cdc69a..68ee2de56f9 100644 --- a/src/components/Files/ReportSubTab.tsx +++ b/src/components/Files/ReportSubTab.tsx @@ -121,7 +121,7 @@ export function ReportSubTab({ const handleView = (report: ReportReadList) => { if (getViewUrl) { navigate(getViewUrl(report.id)); - } else if (resolvedFacilityId) { + } else if (resolvedFacilityId && patientId) { navigate( buildReportPath(resolvedFacilityId, report.id, { patientId, diff --git a/src/pages/Encounters/ReportViewer.tsx b/src/pages/Encounters/ReportViewer.tsx index 9a637be1939..bd1f72457d3 100644 --- a/src/pages/Encounters/ReportViewer.tsx +++ b/src/pages/Encounters/ReportViewer.tsx @@ -92,7 +92,7 @@ export default function ReportViewer({ facility?.permissions, ); - const { data: initialReport } = useQuery({ + const { data: initialReport, isLoading: isLoadingInitialReport } = useQuery({ queryKey: ["report", reportId], queryFn: query(reportApi.retrieveReport, { pathParams: { id: reportId! }, @@ -397,7 +397,7 @@ export default function ReportViewer({ } }, [pdfUrl, t]); - if (isLoadingTemplate || isLoadingReports) { + if (isLoadingInitialReport || isLoadingTemplate || isLoadingReports) { return ; }