From 7fc061718167fb7bf28057b297004ef4d26ab3ab Mon Sep 17 00:00:00 2001 From: Arkadiusz Bachorski <60391032+arkadiuszbachorski@users.noreply.github.com> Date: Sat, 24 Aug 2024 12:02:12 +0200 Subject: [PATCH] Update appointments (#35) # Update appointments ## :recycle: Current situation & Problem Updates appointments according to the discussions that emerged on the meetings. ### Code of Conduct & Contributing Guidelines By submitting creating this pull request, you agree to follow our [Code of Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md): - [x] I agree to follow the [Code of Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md). --- .../patients/[id]/AppointmentForm.tsx | 52 +++---------------- .../patients/[id]/Appointments.tsx | 11 ++-- app/(dashboard)/patients/actions.tsx | 28 ++++++++-- app/(dashboard)/patients/utils.ts | 9 +++- modules/firebase/models/baseTypes.ts | 13 +++-- modules/firebase/models/medication.ts | 7 +-- 6 files changed, 51 insertions(+), 69 deletions(-) diff --git a/app/(dashboard)/patients/[id]/AppointmentForm.tsx b/app/(dashboard)/patients/[id]/AppointmentForm.tsx index 13bcd157..01aeb1fd 100644 --- a/app/(dashboard)/patients/[id]/AppointmentForm.tsx +++ b/app/(dashboard)/patients/[id]/AppointmentForm.tsx @@ -9,10 +9,6 @@ import { type ComponentProps } from 'react' import { z } from 'zod' import { type Appointment } from '@/app/(dashboard)/patients/utils' -import { - FHIRAppointmentStatus, - stringifyAppointmentStatus, -} from '@/modules/firebase/models/medication' import { Button } from '@/packages/design-system/src/components/Button' import { DatePicker } from '@/packages/design-system/src/components/DatePicker' import { @@ -21,23 +17,16 @@ import { DialogHeader, DialogTitle, } from '@/packages/design-system/src/components/Dialog' -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/packages/design-system/src/components/Select' +import { Input } from '@/packages/design-system/src/components/Input' import { Textarea } from '@/packages/design-system/src/components/Textarea' import { Field } from '@/packages/design-system/src/forms/Field' import { useForm } from '@/packages/design-system/src/forms/useForm' export const appointmentFormSchema = z.object({ - status: z.nativeEnum(FHIRAppointmentStatus), start: z.date(), - end: z.date(), comment: z.string().nullable(), patientInstruction: z.string().nullable(), + providerName: z.string(), }) export type AppointmentFormSchema = z.infer @@ -55,11 +44,10 @@ export const AppointmentForm = ({ const form = useForm({ formSchema: appointmentFormSchema, defaultValues: { - status: appointment?.status, start: appointment ? new Date(appointment.start) : undefined, - end: appointment ? new Date(appointment.end) : undefined, comment: appointment?.comment ?? null, patientInstruction: appointment?.patientInstruction ?? null, + providerName: appointment?.providerName ?? '', }, }) @@ -69,25 +57,6 @@ export const AppointmentForm = ({ return (
- ( - - )} - /> ( - field.onChange(date)} - defaultMonth={field.value} - fromDate={new Date()} - showTimePicker - /> - )} + name="providerName" + label="Provider" + render={({ field }) => } /> stringifyAppointmentStatus(props.getValue()), + columnHelper.accessor('providerName', { + header: 'Provider name', + cell: (props) => props.getValue(), }), columnHelper.accessor('start', { header: 'Start', cell: dateTimeColumn, }), - columnHelper.accessor('end', { - header: 'End', - cell: dateTimeColumn, - }), columnHelper.display({ id: 'actions', cell: (props) => ( diff --git a/app/(dashboard)/patients/actions.tsx b/app/(dashboard)/patients/actions.tsx index 8a6b5d73..f749c589 100644 --- a/app/(dashboard)/patients/actions.tsx +++ b/app/(dashboard)/patients/actions.tsx @@ -7,6 +7,7 @@ // 'use server' import { addDoc, deleteDoc, setDoc } from '@firebase/firestore' +import { addHours } from 'date-fns' import { revalidatePath } from 'next/cache' import { type AllergyFormSchema } from '@/app/(dashboard)/patients/[id]/AllergyForm' import { type AppointmentFormSchema } from '@/app/(dashboard)/patients/[id]/AppointmentForm' @@ -14,9 +15,11 @@ import { type LabFormSchema } from '@/app/(dashboard)/patients/[id]/LabForm' import { getUnitOfObservationType } from '@/app/(dashboard)/patients/clientUtils' import { getAuthenticatedOnlyApp } from '@/modules/firebase/guards' import { AllergyType } from '@/modules/firebase/models/allergy' +import { ExtensionURL } from '@/modules/firebase/models/baseTypes' import { FHIRAllergyIntoleranceCriticality, FHIRAllergyIntoleranceType, + FHIRAppointmentStatus, FHIRObservationStatus, } from '@/modules/firebase/models/medication' import { @@ -193,13 +196,28 @@ export const updateAllergy = async ( return 'success' } -const getAppointmentData = (payload: AppointmentFormSchema) => ({ - status: payload.status, +const getAppointmentData = ( + payload: AppointmentFormSchema & { userId: string }, +) => ({ + status: FHIRAppointmentStatus.booked, start: payload.start.toISOString(), - end: payload.end.toISOString(), + end: addHours(payload.start, 1).toISOString(), comment: payload.comment, patientInstruction: payload.patientInstruction, - participant: [], + extension: [ + { url: ExtensionURL.providerName, valueString: payload.providerName }, + ], + participant: [ + { + actor: { + display: null, + type: null, + identifier: null, + reference: `users/${payload.userId}`, + }, + type: null, + }, + ], }) export const createAppointment = async ( @@ -238,7 +256,7 @@ export const updateAppointment = async ( appointmentId: payload.appointmentId, }), getAppointmentData(payload), - { mergeFields: ['created'] }, + { merge: true }, ) revalidatePath(routes.patients.patient(payload.userId)) return 'success' diff --git a/app/(dashboard)/patients/utils.ts b/app/(dashboard)/patients/utils.ts index c8ef1530..a85f3f13 100644 --- a/app/(dashboard)/patients/utils.ts +++ b/app/(dashboard)/patients/utils.ts @@ -9,6 +9,7 @@ import { groupBy } from 'es-toolkit' import { query, where } from 'firebase/firestore' import { getAuthenticatedOnlyApp } from '@/modules/firebase/guards' import { AllergyType } from '@/modules/firebase/models/allergy' +import { ExtensionURL } from '@/modules/firebase/models/baseTypes' import { type FHIRAllergyIntolerance, FHIRAllergyIntoleranceCriticality, @@ -205,9 +206,15 @@ export const getAppointmentsData = async ({ resourceType: ResourceType }) => { const { refs } = await getAuthenticatedOnlyApp() - const appointments = await getDocsData( + const rawAppointments = await getDocsData( refs.appointments({ userId, resourceType }), ) + const appointments = rawAppointments.map((appointment) => ({ + ...appointment, + providerName: appointment.extension?.find( + (extension) => extension.url === (ExtensionURL.providerName as string), + )?.valueString, + })) return { appointments, userId, resourceType } } diff --git a/modules/firebase/models/baseTypes.ts b/modules/firebase/models/baseTypes.ts index fadd7bec..97ea2519 100644 --- a/modules/firebase/models/baseTypes.ts +++ b/modules/firebase/models/baseTypes.ts @@ -31,6 +31,11 @@ export interface FHIRExtension { valueQuantities?: FHIRSimpleQuantity[] valueReference?: FHIRReference valueMedicationRequest?: FHIRMedicationRequest + valueString?: string +} + +export enum ExtensionURL { + providerName = 'http://engagehf.bdh.stanford.edu/fhir/StructureDefinition/Appointment/extension/providerName', } export interface FHIRPeriod { @@ -53,10 +58,10 @@ export interface FHIRRatio { // // eslint-disable-next-line @typescript-eslint/no-unused-vars export interface FHIRReference { - reference?: string - type?: string - identifier?: string - display?: string + reference?: string | null + type?: string | null + identifier?: string | null + display?: string | null } export interface FHIRSimpleQuantity { diff --git a/modules/firebase/models/medication.ts b/modules/firebase/models/medication.ts index 33e5f864..a3baafda 100644 --- a/modules/firebase/models/medication.ts +++ b/modules/firebase/models/medication.ts @@ -5,8 +5,6 @@ // // SPDX-License-Identifier: MIT // - -import { startCase } from 'es-toolkit' import { type FHIRSimpleQuantity, type FHIRCodeableConcept, @@ -15,6 +13,7 @@ import { type FHIRReference, type FHIRPeriod, type FHIRResource, + type FHIRExtension, } from './baseTypes.js' export interface FHIRMedication extends FHIRElement { @@ -125,10 +124,8 @@ export enum FHIRAppointmentStatus { waitlist = 'waitlist', } -export const stringifyAppointmentStatus = (status: FHIRAppointmentStatus) => - startCase(status) - export interface FHIRAppointment { + extension?: FHIRExtension[] status: FHIRAppointmentStatus created: string start: string