-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[ENG-485] feat: refactor ReportViewer and associated routes to use associatingId and reportType for improved report handling #16440
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 5 commits
06ff9f9
fdbf065
eb749aa
b5c1910
b53e6bf
e63a165
7387bf9
35b2dc2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,10 @@ | ||
| import { useQuery } from "@tanstack/react-query"; | ||
| import dayjs from "dayjs"; | ||
| import { SearchIcon } from "lucide-react"; | ||
| import { FileText, Plus, SearchIcon } from "lucide-react"; | ||
| import { navigate } from "raviger"; | ||
| import { useState } from "react"; | ||
| import { useTranslation } from "react-i18next"; | ||
| import { toast } from "sonner"; | ||
|
|
||
| import { cn } from "@/lib/utils"; | ||
|
|
||
|
|
@@ -26,30 +29,33 @@ import { | |
| } from "@/components/ui/table"; | ||
| import { TooltipComponent } from "@/components/ui/tooltip"; | ||
|
|
||
| import { PERMISSION_LIST_TEMPLATE } from "@/common/Permissions"; | ||
| import Loading from "@/components/Common/Loading"; | ||
| import { FilterBadges, FilterButton } from "@/components/Files/FileFilters"; | ||
| import { EmptyState } from "@/components/ui/empty-state"; | ||
| import { usePermissions } from "@/context/PermissionContext"; | ||
|
|
||
| import useFilters from "@/hooks/useFilters"; | ||
| import useReportManager from "@/hooks/useReportManager"; | ||
|
|
||
| import query from "@/Utils/request/query"; | ||
| import queryClient from "@/Utils/request/queryClient"; | ||
| import TemplateReportSheet from "@/pages/Encounters/TemplateBuilder/TemplateReportSheet"; | ||
| import NavigationHelper from "@/components/ui/multi-filter/utils/navigation-helper"; | ||
| import { useCurrentFacilitySilently } from "@/pages/Facility/utils/useCurrentFacility"; | ||
| import { | ||
| ReportRead, | ||
| ReportReadList, | ||
| ReportType, | ||
| } from "@/types/emr/report/report"; | ||
| import { navigate } from "raviger"; | ||
| import { toast } from "sonner"; | ||
| import templateApi from "@/types/emr/template/templateApi"; | ||
|
|
||
| interface ReportTabProps { | ||
| associatingId: string; | ||
| reportType?: ReportType; | ||
| facilityId?: string; | ||
| patientId?: string; | ||
| encounterId?: string; | ||
| billingAccountId?: string; | ||
| } | ||
|
|
||
| export function ReportSubTab({ | ||
|
|
@@ -58,6 +64,7 @@ export function ReportSubTab({ | |
| facilityId, | ||
| patientId, | ||
| encounterId, | ||
| billingAccountId, | ||
| }: ReportTabProps) { | ||
| const { t } = useTranslation(); | ||
| const { facility } = useCurrentFacilitySilently(); | ||
|
|
@@ -72,7 +79,6 @@ export function ReportSubTab({ | |
| viewFile, | ||
| downloadFile, | ||
| archiveReport, | ||
| refetch, | ||
| Dialogs, | ||
| } = useReportManager({ | ||
| associatingId, | ||
|
|
@@ -98,13 +104,32 @@ export function ReportSubTab({ | |
| return iconMap[reportType] || "l-file-alt"; | ||
| }; | ||
|
|
||
| const canNavigateToPreview = !!(facilityId && patientId && encounterId); | ||
| const canNavigateToEncounterPreview = !!( | ||
| facilityId && | ||
| patientId && | ||
| encounterId | ||
| ); | ||
| const canNavigateToBillingPreview = !!(facilityId && billingAccountId); | ||
| const canNavigateToPatientPreview = !!(patientId && !encounterId); | ||
|
|
||
| const handleView = (report: ReportReadList) => { | ||
| if (canNavigateToPreview) { | ||
| if (canNavigateToEncounterPreview) { | ||
| navigate( | ||
| `/facility/${facilityId}/patient/${patientId}/encounter/${encounterId}/report/${report.id}`, | ||
| ); | ||
| } else if (canNavigateToBillingPreview) { | ||
| navigate( | ||
| `/facility/${facilityId}/billing/account/${billingAccountId}/report/${report.id}`, | ||
| ); | ||
| } else if (canNavigateToPatientPreview) { | ||
| const effectiveFacilityId = facilityId ?? facility?.id; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can move defining effectiveFacilityId to 116 and use it in other blocks as well; allows to remove the else block in 130.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. replacing with switch |
||
| if (effectiveFacilityId) { | ||
| navigate( | ||
| `/facility/${effectiveFacilityId}/patient/${patientId}/report/${report.id}`, | ||
| ); | ||
| } else { | ||
| viewFile(report); | ||
| } | ||
| } else { | ||
| viewFile(report); | ||
| } | ||
|
abhimanyurajeesh marked this conversation as resolved.
|
||
|
|
@@ -374,20 +399,12 @@ export function ReportSubTab({ | |
| </Button> | ||
| </div> | ||
| {facility && ( | ||
| <TemplateReportSheet | ||
| facilityId={facility.id} | ||
| associatingId={associatingId} | ||
| permissions={facility.permissions ?? []} | ||
| <GenerateReportDropdown | ||
| facilityId={facilityId ?? facility.id} | ||
| patientId={patientId} | ||
| encounterId={encounterId} | ||
| billingAccountId={billingAccountId} | ||
| reportType={reportType} | ||
| trigger={ | ||
| <Button variant="outline_primary"> | ||
| <CareIcon icon="l-plus" className="mr-1" /> | ||
| <span>{t("generate_report")}</span> | ||
| </Button> | ||
| } | ||
| onSuccess={() => { | ||
| refetch(); | ||
| }} | ||
| /> | ||
| )} | ||
| </div> | ||
|
|
@@ -426,3 +443,102 @@ export function ReportSubTab({ | |
| </div> | ||
| ); | ||
| } | ||
|
|
||
| function GenerateReportDropdown({ | ||
| facilityId, | ||
| patientId, | ||
| encounterId, | ||
| billingAccountId, | ||
| reportType, | ||
| }: { | ||
| facilityId: string; | ||
| patientId?: string; | ||
| encounterId?: string; | ||
| billingAccountId?: string; | ||
| reportType?: ReportType; | ||
| }) { | ||
| const { t } = useTranslation(); | ||
| const { facility } = useCurrentFacilitySilently(); | ||
| const { hasPermission } = usePermissions(); | ||
|
|
||
| const canListTemplate = hasPermission( | ||
| PERMISSION_LIST_TEMPLATE, | ||
| facility?.permissions, | ||
| ); | ||
|
|
||
| const { data: templatesData } = useQuery({ | ||
| queryKey: ["templates", facilityId, reportType], | ||
| queryFn: query(templateApi.listTemplates, { | ||
| queryParams: { | ||
| facility: facilityId, | ||
| template_type: reportType, | ||
| status: "active", | ||
| }, | ||
| }), | ||
| enabled: canListTemplate && !!reportType, | ||
| }); | ||
|
|
||
| const getTemplateUrl = (slug: string) => { | ||
| if (encounterId && patientId) { | ||
| return `/facility/${facilityId}/patient/${patientId}/encounter/${encounterId}/report/template/${slug}`; | ||
| } | ||
| if (billingAccountId) { | ||
| return `/facility/${facilityId}/billing/account/${billingAccountId}/report/template/${slug}`; | ||
| } | ||
| if (patientId) { | ||
| return `/facility/${facilityId}/patient/${patientId}/report/template/${slug}`; | ||
| } | ||
| return null; | ||
| }; | ||
|
|
||
| const templates = (templatesData?.results ?? []).flatMap((template) => { | ||
| const url = getTemplateUrl(template.slug); | ||
| return url ? [{ template, url }] : []; | ||
| }); | ||
|
|
||
| if (templates.length === 0) return null; | ||
|
abhimanyurajeesh marked this conversation as resolved.
Outdated
|
||
|
|
||
| if (templates.length === 1) { | ||
|
abhimanyurajeesh marked this conversation as resolved.
Outdated
|
||
| return ( | ||
| <Button | ||
| variant="outline_primary" | ||
| onClick={() => navigate(templates[0].url)} | ||
| > | ||
| <Plus className="size-4" /> | ||
| <span>{t("generate_report")}</span> | ||
| </Button> | ||
| ); | ||
| } | ||
|
|
||
| return ( | ||
| <DropdownMenu> | ||
| <DropdownMenuTrigger asChild> | ||
| <Button variant="outline_primary"> | ||
| <Plus className="size-4" /> | ||
| <span>{t("generate_report")}</span> | ||
| </Button> | ||
| </DropdownMenuTrigger> | ||
| <DropdownMenuContent | ||
| align="end" | ||
| className="w-full max-w-[calc(100vw-3rem)] sm:max-w-xs p-0" | ||
| > | ||
| <div className="px-2 pt-2"> | ||
| <div className="max-h-[30vh] overflow-y-auto pb-2"> | ||
| {templates.map(({ template, url }) => { | ||
| return ( | ||
| <DropdownMenuItem | ||
| key={template.id} | ||
| onClick={() => navigate(url)} | ||
| > | ||
| <FileText className="size-4 shrink-0" /> | ||
| <span className="truncate">{template.name}</span> | ||
| </DropdownMenuItem> | ||
| ); | ||
| })} | ||
| </div> | ||
| <NavigationHelper hideRightArrow /> | ||
|
abhimanyurajeesh marked this conversation as resolved.
|
||
| </div> | ||
| </DropdownMenuContent> | ||
| </DropdownMenu> | ||
| ); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Associating Id is encounterId, patientId or accountId based on report type, so we can derive the url based on that.
Remove patientId, encounterId and billingAccountId props.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cant remove patient id, can remove the encounter id and billingAccountID