From 31d353071f6818f8f2e981ac27ccb5a332928308 Mon Sep 17 00:00:00 2001 From: Alex Lipovka Date: Tue, 18 Feb 2025 21:57:43 +0400 Subject: [PATCH] Refactor LinkToEdit - Uses context to get custom path extraction - Searches through all targets within provenance - Always uses latest provenance --- .../LinkToEdit/__tests__/LinkToEdit.test.ts | 66 +++++++++++++++++++ src/components/LinkToEdit/context.ts | 11 ++++ src/components/LinkToEdit/index.tsx | 38 +++++++++++ src/components/LinkToEdit/utils.ts | 30 +++++++++ src/components/ResourceTable/index.tsx | 21 ------ src/components/index.ts | 1 + .../PatientDetails/PatientOrders/index.tsx | 3 +- .../components/LinkToEdit/index.tsx | 32 --------- .../components/StandardCard/prepare.tsx | 2 +- .../PatientDetails/PatientResources/utils.tsx | 3 +- 10 files changed, 151 insertions(+), 56 deletions(-) create mode 100644 src/components/LinkToEdit/__tests__/LinkToEdit.test.ts create mode 100644 src/components/LinkToEdit/context.ts create mode 100644 src/components/LinkToEdit/index.tsx create mode 100644 src/components/LinkToEdit/utils.ts delete mode 100644 src/containers/PatientDetails/PatientOverviewDynamic/components/LinkToEdit/index.tsx diff --git a/src/components/LinkToEdit/__tests__/LinkToEdit.test.ts b/src/components/LinkToEdit/__tests__/LinkToEdit.test.ts new file mode 100644 index 00000000..22fd3efe --- /dev/null +++ b/src/components/LinkToEdit/__tests__/LinkToEdit.test.ts @@ -0,0 +1,66 @@ +import { Provenance } from 'fhir/r4b'; +import { describe } from 'vitest'; + +import { getLinkToEditUrl } from 'src/components/LinkToEdit/utils'; + +describe('getSourceFromProvenance', () => { + test('getSourceFromProvenance for empty Provenance', () => { + const provenance = {} as Provenance; + const pathname = '/patients/patient1/resources'; + + expect(getLinkToEditUrl({ provenance, pathname })).toBeUndefined(); + }); + + test('getSourceFromProvenance for undefined Provenance', () => { + expect(getLinkToEditUrl({})).toBeUndefined(); + }); + + test('getSourceFromProvenance for Provenance with source reference', () => { + const provenance: Provenance = { + resourceType: 'Provenance', + entity: [ + { + role: 'source', + what: { + reference: 'QuestionnaireResponse/getme', + }, + }, + ], + agent: [ + { + who: {}, + }, + ], + target: [{}], + recorded: '', + }; + const pathname = '/patients/patient1/resources'; + + expect(getLinkToEditUrl({ provenance, pathname })).toEqual('/patients/patient1/documents/getme'); + }); + + test('getSourceFromProvenance for Provenance with source reference and custom to', () => { + const provenance: Provenance = { + resourceType: 'Provenance', + entity: [ + { + role: 'source', + what: { + reference: 'QuestionnaireResponse/getme', + }, + }, + ], + agent: [ + { + who: {}, + }, + ], + target: [{}], + recorded: '', + }; + const pathname = '/patients/patient1/resources'; + const to = '/custom'; + + expect(getLinkToEditUrl({ provenance, pathname, to })).toEqual('/custom/getme'); + }); +}); diff --git a/src/components/LinkToEdit/context.ts b/src/components/LinkToEdit/context.ts new file mode 100644 index 00000000..1e1dbefe --- /dev/null +++ b/src/components/LinkToEdit/context.ts @@ -0,0 +1,11 @@ +import { createContext } from 'react'; + +import { getLinkToEditUrl, GetLinkToEditUrlProps } from 'src/components/LinkToEdit/utils'; + +export type LinkToEditContextType = { + getLinkToEditUrl: (props: GetLinkToEditUrlProps) => string | undefined; +}; + +export const LinkToEditContext = createContext({ + getLinkToEditUrl, +}); diff --git a/src/components/LinkToEdit/index.tsx b/src/components/LinkToEdit/index.tsx new file mode 100644 index 00000000..586e83e2 --- /dev/null +++ b/src/components/LinkToEdit/index.tsx @@ -0,0 +1,38 @@ +import { Resource, Provenance } from 'fhir/r4b'; +import { useContext } from 'react'; +import { Link, useLocation } from 'react-router-dom'; +import { fromFHIRReference } from 'sdc-qrf'; + +import { LinkToEditContext } from 'src/components/LinkToEdit/context'; + +interface LinkToEditProps { + name?: string; + resource: Resource; + provenanceList: Provenance[]; + to?: string; +} + +export function LinkToEdit(props: LinkToEditProps) { + const { name, resource, provenanceList, to } = props; + + const location = useLocation(); + const provenance = provenanceList + .filter((provenance) => + provenance.target.find( + (target) => + fromFHIRReference(target)?.id === resource.id && + fromFHIRReference(target)?.resourceType === resource.resourceType, + ), + ) + .sort((a, b) => new Date(b.recorded).getTime() - new Date(a.recorded).getTime())[0]; + + const { getLinkToEditUrl } = useContext(LinkToEditContext); + + const customPathTo = getLinkToEditUrl({ provenance, pathname: location.pathname, to }); + + if (!customPathTo) { + return <>{name}; + } + + return {name}; +} diff --git a/src/components/LinkToEdit/utils.ts b/src/components/LinkToEdit/utils.ts new file mode 100644 index 00000000..d37a9f04 --- /dev/null +++ b/src/components/LinkToEdit/utils.ts @@ -0,0 +1,30 @@ +import { Provenance } from 'fhir/r4b'; +import { fromFHIRReference } from 'sdc-qrf'; + +export type GetLinkToEditUrlProps = { + provenance?: Provenance; + pathname?: string; + to?: string; +}; + +export function getLinkToEditUrl(props: GetLinkToEditUrlProps): string | undefined { + const { provenance, pathname, to } = props; + + const entity = provenance?.entity?.[0]?.what; + const qrId = fromFHIRReference(entity)?.id; + const baseUrl = pathname?.split('/').slice(0, 3).join('/'); + + if (!qrId) { + return undefined; + } + + if (to) { + return `${to}/${qrId}`; + } + + if (!baseUrl) { + return undefined; + } + + return `${baseUrl}/documents/${qrId}`; +} diff --git a/src/components/ResourceTable/index.tsx b/src/components/ResourceTable/index.tsx index a5aa4130..957a6413 100644 --- a/src/components/ResourceTable/index.tsx +++ b/src/components/ResourceTable/index.tsx @@ -3,8 +3,6 @@ import { Empty } from 'antd'; import { ColumnsType } from 'antd/lib/table'; import { Provenance, Resource } from 'fhir/r4b'; import { ReactNode } from 'react'; -import { Link, useLocation } from 'react-router-dom'; -import { fromFHIRReference } from 'sdc-qrf'; import { RenderRemoteData, SearchParams, extractBundleResources, ResourcesMap } from '@beda.software/fhir-react'; @@ -77,22 +75,3 @@ export function ResourceTable(props: ResourceTableProps) ); } - -export function LinkToEdit(props: { name?: string; resource: Resource; provenanceList: Provenance[] }) { - const { name, resource, provenanceList } = props; - const location = useLocation(); - const provenance = provenanceList.find( - (p) => - fromFHIRReference(p.target[0])?.id === resource.id && - fromFHIRReference(p.target[0])?.resourceType === resource.resourceType, - ); - const entity = provenance?.entity?.[0]?.what; - const qrId = fromFHIRReference(entity)?.id; - const pathname = location.pathname.split('/').slice(0, 3).join('/'); - - if (qrId) { - return {name}; - } - - return <>{name}; -} diff --git a/src/components/index.ts b/src/components/index.ts index fa495c91..906aba0c 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -11,6 +11,7 @@ export * from './DatePicker'; export * from './Empty'; export * from './EncounterStatusBadge'; export * from './EncountersTable'; +export * from './LinkToEdit'; export * from './Modal'; export * from './ModalChangeActiveHealthcareService'; export * from './ModalEditHealthcareService'; diff --git a/src/containers/PatientDetails/PatientOrders/index.tsx b/src/containers/PatientDetails/PatientOrders/index.tsx index 924e675c..793b1e6e 100644 --- a/src/containers/PatientDetails/PatientOrders/index.tsx +++ b/src/containers/PatientDetails/PatientOrders/index.tsx @@ -8,9 +8,10 @@ import styled from 'styled-components'; import { WithId } from '@beda.software/fhir-react'; +import { LinkToEdit } from 'src/components/LinkToEdit'; import { Modal } from 'src/components/Modal'; import { QuestionnaireResponseForm } from 'src/components/QuestionnaireResponseForm'; -import { ResourceTable, LinkToEdit } from 'src/components/ResourceTable'; +import { ResourceTable } from 'src/components/ResourceTable'; import { questionnaireIdLoader } from 'src/hooks/questionnaire-response-form-data'; import { formatHumanDate } from 'src/utils/date'; import { selectCurrentUserRoleResource } from 'src/utils/role'; diff --git a/src/containers/PatientDetails/PatientOverviewDynamic/components/LinkToEdit/index.tsx b/src/containers/PatientDetails/PatientOverviewDynamic/components/LinkToEdit/index.tsx deleted file mode 100644 index 4c49d494..00000000 --- a/src/containers/PatientDetails/PatientOverviewDynamic/components/LinkToEdit/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Resource, Provenance } from 'fhir/r4b'; -import { Link, useLocation } from 'react-router-dom'; -import { fromFHIRReference } from 'sdc-qrf'; - -interface LinkToEditProps { - name?: string; - resource: Resource; - provenanceList: Provenance[]; - to?: string; -} -export function LinkToEdit(props: LinkToEditProps) { - const { name, resource, provenanceList, to } = props; - const location = useLocation(); - const provenance = provenanceList.find((provenance) => { - const targets = provenance.target || []; - - return targets.find((target) => { - return ( - fromFHIRReference(target)?.id === resource.id && - fromFHIRReference(target)?.resourceType === resource.resourceType - ); - }); - }); - const entity = provenance?.entity?.[0]?.what; - const qrId = fromFHIRReference(entity)?.id; - - if (qrId) { - return {name}; - } - - return <>{name}; -} diff --git a/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx b/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx index 0d4890d9..7ed5669a 100644 --- a/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx +++ b/src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/prepare.tsx @@ -19,8 +19,8 @@ import { extractExtension } from 'sdc-qrf'; import { WithId, extractBundleResources, formatFHIRDate, parseFHIRDateTime } from '@beda.software/fhir-react'; +import { LinkToEdit } from 'src/components/LinkToEdit'; import { PatientActivitySummary } from 'src/containers/PatientDetails/PatientActivitySummary'; -import { LinkToEdit } from 'src/containers/PatientDetails/PatientOverviewDynamic/components/LinkToEdit'; import { OverviewCard } from 'src/containers/PatientDetails/PatientOverviewDynamic/components/StandardCard/types'; import medicationIcon from 'src/containers/PatientDetails/PatientOverviewDynamic/images/medication.svg'; import { formatHumanDate } from 'src/utils/date'; diff --git a/src/containers/PatientDetails/PatientResources/utils.tsx b/src/containers/PatientDetails/PatientResources/utils.tsx index e5c9458b..51e15df2 100644 --- a/src/containers/PatientDetails/PatientResources/utils.tsx +++ b/src/containers/PatientDetails/PatientResources/utils.tsx @@ -15,7 +15,8 @@ import { extractExtension } from 'sdc-qrf'; import { WithId } from '@beda.software/fhir-react'; -import { ResourceTable, Option, LinkToEdit } from 'src/components/ResourceTable'; +import { LinkToEdit } from 'src/components/LinkToEdit'; +import { ResourceTable, Option } from 'src/components/ResourceTable'; import { compileAsArray } from 'src/utils'; import { formatHumanDate, formatHumanDateTime } from 'src/utils/date';