Skip to content
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

List lab values #28

Merged
merged 8 commits into from
Aug 13, 2024
Merged
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
41 changes: 41 additions & 0 deletions app/(dashboard)/patients/[id]/Labs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// This source file is part of the Stanford Biodesign Digital Health ENGAGE-HF open-source project
//
// SPDX-FileCopyrightText: 2023 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//
'use client'
import { createColumnHelper } from '@tanstack/table-core'

Check warning on line 9 in app/(dashboard)/patients/[id]/Labs.tsx

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/[id]/Labs.tsx#L9

Added line #L9 was not covered by tests
import { type LabsData } from '@/app/(dashboard)/patients/utils'
import { DataTable } from '@/packages/design-system/src/components/DataTable'

Check warning on line 11 in app/(dashboard)/patients/[id]/Labs.tsx

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/[id]/Labs.tsx#L11

Added line #L11 was not covered by tests

interface LabsProps extends LabsData {}

type Observation = LabsData['observations'][number]

const columnHelper = createColumnHelper<Observation>()
const columns = [

Check warning on line 18 in app/(dashboard)/patients/[id]/Labs.tsx

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/[id]/Labs.tsx#L17-L18

Added lines #L17 - L18 were not covered by tests
columnHelper.accessor('effectiveDateTime', {
header: 'Date',
cell: (props) => {
const value = props.getValue()

Check warning on line 22 in app/(dashboard)/patients/[id]/Labs.tsx

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/[id]/Labs.tsx#L21-L22

Added lines #L21 - L22 were not covered by tests
const date = value ? new Date(value) : undefined
return date?.toLocaleDateString() ?? ''
},
}),
columnHelper.accessor('type', {
header: 'Type',
}),
columnHelper.accessor('value', {
header: 'Value',
cell: (props) => {
const observation = props.row.original
return `${observation.value} ${observation.unit}`

Check warning on line 34 in app/(dashboard)/patients/[id]/Labs.tsx

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/[id]/Labs.tsx#L32-L34

Added lines #L32 - L34 were not covered by tests
},
}),
]

export const Labs = ({ observations }: LabsProps) => {
return <DataTable columns={columns} data={observations} />

Check warning on line 40 in app/(dashboard)/patients/[id]/Labs.tsx

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/[id]/Labs.tsx#L39-L40

Added lines #L39 - L40 were not covered by tests
}
9 changes: 9 additions & 0 deletions app/(dashboard)/patients/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
} from '@/app/(dashboard)/patients/PatientForm'
import {
getFormProps,
getLabsData,
getMedicationsData,
} from '@/app/(dashboard)/patients/utils'
import { getAuthenticatedOnlyApp } from '@/modules/firebase/guards'
Expand All @@ -39,6 +40,7 @@
import { getUserName } from '@/packages/design-system/src/modules/auth/user'
import { PageTitle } from '@/packages/design-system/src/molecules/DashboardLayout'
import { GenerateHealthSummary } from './GenerateHealthSummary'
import { Labs } from './Labs'

Check warning on line 43 in app/(dashboard)/patients/[id]/page.tsx

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/[id]/page.tsx#L43

Added line #L43 was not covered by tests
import { DashboardLayout } from '../../DashboardLayout'
import { Medications, type MedicationsFormSchema } from '../Medications'

Expand Down Expand Up @@ -70,6 +72,7 @@
enum Tab {
information = 'information',
medications = 'medications',
labs = 'labs',

Check warning on line 75 in app/(dashboard)/patients/[id]/page.tsx

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/[id]/page.tsx#L75

Added line #L75 was not covered by tests
}

const PatientPage = async ({ params }: PatientPageProps) => {
Expand Down Expand Up @@ -176,6 +179,9 @@
<TabsTrigger value={Tab.medications} className="grow">
Medications
</TabsTrigger>
<TabsTrigger value={Tab.labs} className="grow">
Labs
</TabsTrigger>
</TabsList>
<TabsContent value={Tab.information}>
<PatientForm
Expand All @@ -194,6 +200,9 @@
}}
/>
</TabsContent>
<TabsContent value={Tab.labs}>
<Labs {...await getLabsData({ userId, resourceType })} />
</TabsContent>
</Tabs>
</DashboardLayout>
)
Expand Down
39 changes: 38 additions & 1 deletion app/(dashboard)/patients/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
import { query, where } from 'firebase/firestore'
import { getAuthenticatedOnlyApp } from '@/modules/firebase/guards'
import { mapAuthData } from '@/modules/firebase/user'
import { getDocsData, UserType } from '@/modules/firebase/utils'
import {

Check warning on line 12 in app/(dashboard)/patients/utils.ts

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/utils.ts#L12

Added line #L12 was not covered by tests
getDocsData,
ObservationType,
type ResourceType,
UserType,
} from '@/modules/firebase/utils'
import { getUserOrganizations } from '@/modules/user/queries'

export const getUserClinicians = async () => {
Expand Down Expand Up @@ -120,4 +125,36 @@
return { medications }
}

export const getLabsData = async ({

Check warning on line 128 in app/(dashboard)/patients/utils.ts

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/utils.ts#L128

Added line #L128 was not covered by tests
userId,
resourceType,
}: {
userId: string
resourceType: ResourceType
}) => {
const { refs } = await getAuthenticatedOnlyApp()
const rawObservations = await Promise.all(
Object.values(ObservationType).map(async (type) => {
return {

Check warning on line 138 in app/(dashboard)/patients/utils.ts

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/utils.ts#L134-L138

Added lines #L134 - L138 were not covered by tests
type,
data: await getDocsData(
refs.userObservation({ userId, resourceType, observationType: type }),
),
}
}),
)

const observations = rawObservations.flatMap((observations) =>
observations.data.map((observation) => ({

Check warning on line 148 in app/(dashboard)/patients/utils.ts

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/utils.ts#L147-L148

Added lines #L147 - L148 were not covered by tests
effectiveDateTime: observation.effectiveDateTime,
value: observation.valueQuantity?.value,
unit: observation.valueQuantity?.unit,
type: observations.type,
})),
)

return { observations }

Check warning on line 156 in app/(dashboard)/patients/utils.ts

View check run for this annotation

Codecov / codecov/patch

app/(dashboard)/patients/utils.ts#L156

Added line #L156 was not covered by tests
}

export type LabsData = Awaited<ReturnType<typeof getLabsData>>
export type MedicationsData = Awaited<ReturnType<typeof getMedicationsData>>
4 changes: 4 additions & 0 deletions modules/firebase/models/baseTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export interface FHIRPeriod {
end?: string
}

export interface FHIRResource extends FHIRElement {
resourceType: string
}

export interface FHIRRatio {
numerator?: FHIRSimpleQuantity
denominator?: FHIRSimpleQuantity
Expand Down
28 changes: 28 additions & 0 deletions modules/firebase/models/medication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
type FHIRElement,
type FHIRRatio,
type FHIRReference,
type FHIRPeriod,
type FHIRResource,
} from './baseTypes.js'

export interface FHIRMedication extends FHIRElement {
Expand Down Expand Up @@ -64,6 +66,32 @@
videoPath: string
}

export interface FHIRObservationComponent {
code: FHIRCodeableConcept
valueQuantity?: FHIRSimpleQuantity
}

export enum FHIRObservationStatus {
registered = 'registered',
preliminary = 'preliminary',
final = 'final',
amended = 'amended',
corrected = 'corrected',
cancelled = 'cancelled',
entered_in_error = 'entered-in-error',
unknown = 'unknown',

Check warning on line 82 in modules/firebase/models/medication.ts

View check run for this annotation

Codecov / codecov/patch

modules/firebase/models/medication.ts#L75-L82

Added lines #L75 - L82 were not covered by tests
}

export interface FHIRObservation extends FHIRResource {
status: FHIRObservationStatus
code: FHIRCodeableConcept
component?: FHIRObservationComponent[]
valueQuantity?: FHIRSimpleQuantity
effectivePeriod?: FHIRPeriod
effectiveDateTime?: string
effectiveInstant?: string
}

export const getMedicationRequestData = (medication: {
medication: string
drug: string
Expand Down
59 changes: 56 additions & 3 deletions modules/firebase/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
type FHIRMedication,
type FHIRMedicationRequest,
type MedicationClass,
type FHIRObservation,
} from '@/modules/firebase/models/medication'
import { strategy } from '@/packages/design-system/src/utils/misc'

Check warning on line 25 in modules/firebase/utils.ts

View check run for this annotation

Codecov / codecov/patch

modules/firebase/utils.ts#L25

Added line #L25 was not covered by tests

export interface Organization {
id: string
Expand Down Expand Up @@ -77,14 +79,37 @@
medicationClasses: 'medicationClasses',
drugs: 'drugs',
medicationRequests: 'medicationRequests',
creatinineObservations: 'creatinineObservations',
eGfrObservations: 'eGfrObservations',
potassiumObservations: 'potassiumObservations',
}

export type ResourceType = 'invitation' | 'user'

export const userPath = (resourceType: ResourceType) =>
resourceType === 'invitation' ?
collectionNames.invitations
: collectionNames.users
strategy(

Check warning on line 90 in modules/firebase/utils.ts

View check run for this annotation

Codecov / codecov/patch

modules/firebase/utils.ts#L90

Added line #L90 was not covered by tests
{
invitation: collectionNames.invitations,
user: collectionNames.users,
},
resourceType,
)

export enum ObservationType {
creatinine = 'creatinine',
eGFR = 'eGFR',
potassium = 'potassium',

Check warning on line 101 in modules/firebase/utils.ts

View check run for this annotation

Codecov / codecov/patch

modules/firebase/utils.ts#L99-L101

Added lines #L99 - L101 were not covered by tests
}

export const observationPath = (type: ObservationType) =>
strategy(

Check warning on line 105 in modules/firebase/utils.ts

View check run for this annotation

Codecov / codecov/patch

modules/firebase/utils.ts#L104-L105

Added lines #L104 - L105 were not covered by tests
{
[ObservationType.creatinine]: collectionNames.creatinineObservations,
[ObservationType.eGFR]: collectionNames.eGfrObservations,
[ObservationType.potassium]: collectionNames.potassiumObservations,
},
type,
)

export const getCollectionRefs = (db: Firestore) => ({
users: () =>
Expand Down Expand Up @@ -125,6 +150,19 @@
db,
collectionNames.medicationClasses,
) as CollectionReference<MedicationClass>,
userObservation: ({
userId,
resourceType,
observationType,
}: {
userId: string
resourceType: ResourceType
observationType: ObservationType
}) =>
collection(

Check warning on line 162 in modules/firebase/utils.ts

View check run for this annotation

Codecov / codecov/patch

modules/firebase/utils.ts#L162

Added line #L162 was not covered by tests
db,
`/${userPath(resourceType)}/${userId}/${observationPath(observationType)}`,
) as CollectionReference<FHIRObservation>,
})

export const getDocumentsRefs = (db: Firestore) => ({
Expand Down Expand Up @@ -157,6 +195,21 @@
db,
`/${userPath(resourceType)}/${userId}/${collectionNames.medicationRequests}/${medicationRequestId}`,
) as DocumentReference<FHIRMedicationRequest>,
userObservation: ({
userId,
resourceType,
observationType,
observationId,
}: {
userId: string
resourceType: ResourceType
observationType: ObservationType
observationId: string
}) =>
doc(

Check warning on line 209 in modules/firebase/utils.ts

View check run for this annotation

Codecov / codecov/patch

modules/firebase/utils.ts#L209

Added line #L209 was not covered by tests
db,
`/${userPath(resourceType)}/${userId}/${observationPath(observationType)}/${observationId}`,
) as DocumentReference<FHIRObservation>,
})

interface Result<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import { type Meta, type StoryObj } from '@storybook/react'
import { DataTable } from './DataTable'
import { peopleColumns, peopleData, type Person } from './DataTable.mocks'
import { Button } from '../Button'

const meta: Meta<typeof DataTable> = {
title: 'Components/DataTable',
Expand Down Expand Up @@ -36,3 +37,16 @@ export const Paginated: Story = {
pageSize: 2,
},
}

export const HeaderAction: Story = {
args: {
...Default.args,
header: (
<>
<Button className="ml-auto" size="sm">
Action
</Button>
</>
),
},
}
7 changes: 5 additions & 2 deletions packages/design-system/src/components/DataTable/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
useReactTable,
} from '@tanstack/react-table'
import { type TableOptions } from '@tanstack/table-core'
import { useState } from 'react'
import { type ReactNode, useState } from 'react'
import { useDebouncedCallback } from 'use-debounce'
import { fuzzyFilter } from './DataTable.utils'
import { GlobalFilterInput } from './GlobalFilterInput'
Expand Down Expand Up @@ -46,6 +46,7 @@ export interface DataTableProps<Data>
* */
entityName?: string
pageSize?: number
header?: ReactNode
}

export const DataTable = <Data,>({
Expand All @@ -54,6 +55,7 @@ export const DataTable = <Data,>({
entityName,
data,
pageSize = 50,
header,
...props
}: DataTableProps<Data>) => {
const [sorting, setSorting] = useState<SortingState>([])
Expand Down Expand Up @@ -95,11 +97,12 @@ export const DataTable = <Data,>({
const pageCount = table.getPageCount()
return (
<div className={cn('rounded-md border bg-surface-primary', className)}>
<header className="flex border-b p-4">
<header className="flex items-center border-b p-4">
<GlobalFilterInput
onChange={(event) => setGlobalFilterDebounced(event.target.value)}
entityName={entityName}
/>
{header}
</header>
<Table>
<TableHeader>
Expand Down
8 changes: 8 additions & 0 deletions packages/design-system/src/utils/misc/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,11 @@
* */
export const times = <T>(length: number, callback: (index: number) => T) =>
new Array(length).fill(undefined).map((_, index) => callback(index))

/**
* Utility to dynamically resolve strategy pattern
*/
export const strategy = <T extends string | number | symbol, F>(
record: Record<T, F>,
enumValue: T,
) => record[enumValue]

Check warning on line 63 in packages/design-system/src/utils/misc/misc.ts

View check run for this annotation

Codecov / codecov/patch

packages/design-system/src/utils/misc/misc.ts#L63

Added line #L63 was not covered by tests
Loading