generated from StanfordBDHG/NextJSTemplate
-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# Labs actions ## ♻️ Current situation & Problem As a clinician, I want to modify labs values. ### 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).
- Loading branch information
1 parent
056798b
commit 6c63e93
Showing
8 changed files
with
484 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
// | ||
// 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 { Dialog } from '@radix-ui/react-dialog' | ||
import { type ComponentProps } from 'react' | ||
import { z } from 'zod' | ||
import { | ||
getObservationTypeUnits, | ||
getUnitOfObservationType, | ||
} from '@/app/(dashboard)/patients/clientUtils' | ||
import { type Observation } from '@/app/(dashboard)/patients/utils' | ||
import { ObservationType } from '@/modules/firebase/utils' | ||
import { Button } from '@/packages/design-system/src/components/Button' | ||
import { DatePicker } from '@/packages/design-system/src/components/DatePicker' | ||
import { | ||
DialogContent, | ||
DialogHeader, | ||
DialogTitle, | ||
} from '@/packages/design-system/src/components/Dialog' | ||
import { Input } from '@/packages/design-system/src/components/Input' | ||
import { | ||
Select, | ||
SelectContent, | ||
SelectItem, | ||
SelectTrigger, | ||
SelectValue, | ||
} from '@/packages/design-system/src/components/Select' | ||
import { Field } from '@/packages/design-system/src/forms/Field' | ||
import { useForm } from '@/packages/design-system/src/forms/useForm' | ||
|
||
export const labFormSchema = z.object({ | ||
type: z.nativeEnum(ObservationType), | ||
effectiveDateTime: z.date(), | ||
unit: z.string(), | ||
value: z.number(), | ||
}) | ||
|
||
export type LabFormSchema = z.infer<typeof labFormSchema> | ||
|
||
interface LabFormProps { | ||
observation?: Observation | ||
onSubmit: (data: LabFormSchema) => Promise<void> | ||
} | ||
|
||
export const LabForm = ({ observation, onSubmit }: LabFormProps) => { | ||
const isEdit = !!observation | ||
const defaultType = observation?.type ?? ObservationType.potassium | ||
const form = useForm({ | ||
formSchema: labFormSchema, | ||
defaultValues: { | ||
type: defaultType, | ||
effectiveDateTime: | ||
observation?.effectiveDateTime ? | ||
new Date(observation.effectiveDateTime) | ||
: new Date(), | ||
unit: observation?.unit ?? getUnitOfObservationType(defaultType).unit, | ||
value: observation?.value, | ||
}, | ||
}) | ||
|
||
const [formType, formUnit] = form.watch(['type', 'unit']) | ||
const units = getObservationTypeUnits(formType) | ||
|
||
const handleSubmit = form.handleSubmit(async (data) => { | ||
await onSubmit(data) | ||
}) | ||
|
||
return ( | ||
<form onSubmit={handleSubmit}> | ||
<Field | ||
control={form.control} | ||
name="type" | ||
label="Type" | ||
render={({ field }) => ( | ||
<Select | ||
onValueChange={(type) => { | ||
field.onChange(type) | ||
form.setValue( | ||
'unit', | ||
getUnitOfObservationType(type as ObservationType, formUnit) | ||
.unit, | ||
) | ||
}} | ||
{...field} | ||
> | ||
<SelectTrigger> | ||
<SelectValue placeholder="Type" /> | ||
</SelectTrigger> | ||
<SelectContent> | ||
{Object.values(ObservationType).map((type) => ( | ||
<SelectItem key={type} value={type}> | ||
{type} | ||
</SelectItem> | ||
))} | ||
</SelectContent> | ||
</Select> | ||
)} | ||
/> | ||
<Field | ||
control={form.control} | ||
name="unit" | ||
label="Unit" | ||
render={({ field }) => ( | ||
<Select {...field} key={formType}> | ||
<SelectTrigger> | ||
<SelectValue placeholder="Unit" /> | ||
</SelectTrigger> | ||
<SelectContent> | ||
{units.map((unit) => ( | ||
<SelectItem key={unit.unit} value={unit.unit}> | ||
{unit.unit} | ||
</SelectItem> | ||
))} | ||
</SelectContent> | ||
</Select> | ||
)} | ||
/> | ||
<Field | ||
control={form.control} | ||
name="value" | ||
label="Value" | ||
render={({ field }) => ( | ||
<Input | ||
{...field} | ||
type="number" | ||
onChange={(event) => | ||
field.onChange(event.currentTarget.valueAsNumber) | ||
} | ||
/> | ||
)} | ||
/> | ||
<Field | ||
control={form.control} | ||
name="effectiveDateTime" | ||
label="Date" | ||
render={({ field }) => ( | ||
<DatePicker | ||
mode="single" | ||
selected={field.value} | ||
onSelect={(date) => field.onChange(date)} | ||
defaultMonth={field.value} | ||
toYear={new Date().getFullYear()} | ||
/> | ||
)} | ||
/> | ||
<Button type="submit" isPending={form.formState.isSubmitting}> | ||
{isEdit ? 'Edit' : 'Create'} observation | ||
</Button> | ||
</form> | ||
) | ||
} | ||
|
||
type LabFormDialogProps = LabFormProps & | ||
Pick<ComponentProps<typeof Dialog>, 'open' | 'onOpenChange'> | ||
|
||
export const LabFormDialog = ({ | ||
open, | ||
onOpenChange, | ||
observation, | ||
...props | ||
}: LabFormDialogProps) => ( | ||
<Dialog open={open} onOpenChange={onOpenChange}> | ||
<DialogContent> | ||
<DialogHeader> | ||
<DialogTitle>{observation ? 'Edit' : 'Create'} observation</DialogTitle> | ||
</DialogHeader> | ||
<LabForm {...props} observation={observation} /> | ||
</DialogContent> | ||
</Dialog> | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// | ||
// 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 { Pencil, Trash } from 'lucide-react' | ||
import { LabFormDialog } from '@/app/(dashboard)/patients/[id]/LabForm' | ||
import { | ||
deleteObservation, | ||
updateObservation, | ||
} from '@/app/(dashboard)/patients/actions' | ||
import { type Observation } from '@/app/(dashboard)/patients/utils' | ||
import { type ResourceType } from '@/modules/firebase/utils' | ||
import { RowDropdownMenu } from '@/packages/design-system/src/components/DataTable' | ||
import { DropdownMenuItem } from '@/packages/design-system/src/components/DropdownMenu' | ||
import { ConfirmDeleteDialog } from '@/packages/design-system/src/molecules/ConfirmDeleteDialog' | ||
import { useOpenState } from '@/packages/design-system/src/utils/useOpenState' | ||
|
||
interface LabMenuProps { | ||
userId: string | ||
resourceType: ResourceType | ||
observation: Observation | ||
} | ||
|
||
export const LabMenu = ({ | ||
userId, | ||
resourceType, | ||
observation, | ||
}: LabMenuProps) => { | ||
const deleteConfirm = useOpenState() | ||
const editObservation = useOpenState() | ||
|
||
const handleDelete = async () => { | ||
await deleteObservation({ | ||
userId, | ||
resourceType, | ||
observationId: observation.id, | ||
observationType: observation.type, | ||
}) | ||
deleteConfirm.close() | ||
} | ||
|
||
return ( | ||
<> | ||
<LabFormDialog | ||
onSubmit={async (data) => { | ||
await updateObservation({ | ||
userId, | ||
resourceType, | ||
observationId: observation.id, | ||
...data, | ||
}) | ||
editObservation.close() | ||
}} | ||
open={editObservation.isOpen} | ||
onOpenChange={editObservation.setIsOpen} | ||
observation={observation} | ||
/> | ||
<ConfirmDeleteDialog | ||
open={deleteConfirm.isOpen} | ||
onOpenChange={deleteConfirm.setIsOpen} | ||
entityName="observation" | ||
onDelete={handleDelete} | ||
/> | ||
<RowDropdownMenu> | ||
<DropdownMenuItem onClick={editObservation.open}> | ||
<Pencil /> | ||
Edit | ||
</DropdownMenuItem> | ||
<DropdownMenuItem onClick={deleteConfirm.open}> | ||
<Trash /> | ||
Delete | ||
</DropdownMenuItem> | ||
</RowDropdownMenu> | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.