Skip to content

Commit

Permalink
Add birth date to patients and users (#26)
Browse files Browse the repository at this point in the history
# Add birth date to patients and users

## ♻️ Current situation & Problem
Patients and users need to have their date of birth set.



https://github.com/user-attachments/assets/a5cabc6b-73da-4f2b-92d6-999fab6fcc26



### 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
arkadiuszbachorski authored Aug 12, 2024
1 parent ed6152f commit 465a113
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 35 deletions.
26 changes: 23 additions & 3 deletions app/(dashboard)/patients/PatientForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { z } from 'zod'
import { type User } from '@/modules/firebase/utils'
import { Button } from '@/packages/design-system/src/components/Button'
import { DatePicker } from '@/packages/design-system/src/components/DatePicker'
import { Input } from '@/packages/design-system/src/components/Input'
import {
Select,
Expand All @@ -25,10 +26,11 @@ import {
} from '@/packages/design-system/src/modules/auth/user'

export const patientFormSchema = z.object({
email: z.string().min(1, 'Email is required'),
email: z.string().email().min(1, 'Email is required'),
displayName: z.string(),
invitationCode: z.string(),
clinician: z.string(),
clinician: z.string().min(1, 'Clinician is required'),
dateOfBirth: z.date().optional(),
})

export type PatientFormSchema = z.infer<typeof patientFormSchema>
Expand All @@ -40,7 +42,10 @@ interface PatientFormProps {
email: string | null
}>
userInfo?: Pick<UserInfo, 'email' | 'displayName' | 'uid'>
user?: Pick<User, 'organization' | 'invitationCode' | 'clinician'>
user?: Pick<
User,
'organization' | 'invitationCode' | 'clinician' | 'dateOfBirth'
>
onSubmit: (data: PatientFormSchema) => Promise<void>
clinicianPreselectId?: string
}
Expand All @@ -60,6 +65,7 @@ export const PatientForm = ({
displayName: userInfo?.displayName ?? '',
invitationCode: user?.invitationCode ?? '',
clinician: user?.clinician ?? clinicianPreselectId ?? '',
dateOfBirth: user?.dateOfBirth ? new Date(user.dateOfBirth) : undefined,
},
})

Expand All @@ -81,6 +87,20 @@ export const PatientForm = ({
label="Display name"
render={({ field }) => <Input {...field} />}
/>
<Field
control={form.control}
name="dateOfBirth"
label="Date of Birth"
render={({ field }) => (
<DatePicker
mode="single"
selected={field.value}
onSelect={(date) => field.onChange(date)}
defaultMonth={field.value}
toYear={new Date().getFullYear()}
/>
)}
/>
{isEdit && (
<Field
control={form.control}
Expand Down
1 change: 1 addition & 0 deletions app/(dashboard)/patients/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ const PatientPage = async ({ params }: PatientPageProps) => {
invitationCode: form.invitationCode,
clinician: form.clinician,
organization: clinician.organization,
dateOfBirth: form.dateOfBirth?.toISOString(),
}
if (resourceType === 'user') {
await callables.updateUserInformation({
Expand Down
3 changes: 2 additions & 1 deletion app/(dashboard)/patients/invite/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ const InvitePatientPage = async () => {
type: UserType.patient,
clinician: form.clinician,
organization: clinician.organization,
dateOfBirth: form.dateOfBirth?.toISOString(),
},
})
redirect(routes.patients.patient(result.data.code))
redirect(routes.patients.patient(result.data.id))
}

return (
Expand Down
21 changes: 19 additions & 2 deletions app/(dashboard)/users/UserForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
UserType,
} from '@/modules/firebase/utils'
import { Button } from '@/packages/design-system/src/components/Button'
import { DatePicker } from '@/packages/design-system/src/components/DatePicker'
import { Input } from '@/packages/design-system/src/components/Input'
import {
Select,
Expand All @@ -28,9 +29,10 @@ import { type UserInfo } from '@/packages/design-system/src/modules/auth/user'

export const userFormSchema = z
.object({
email: z.string().min(1, 'Email is required'),
email: z.string().email().min(1, 'Email is required'),
displayName: z.string(),
invitationCode: z.string(),
dateOfBirth: z.date().optional(),
organizationId: z.string().optional(),
type: z.nativeEnum(UserType),
})
Expand All @@ -49,7 +51,7 @@ export type UserFormSchema = z.infer<typeof userFormSchema>
interface UserFormProps {
organizations: Array<Pick<Organization, 'name' | 'id'>>
userInfo?: Pick<UserInfo, 'email' | 'displayName' | 'uid'>
user?: Pick<User, 'organization' | 'invitationCode'>
user?: Pick<User, 'organization' | 'invitationCode' | 'dateOfBirth'>
type?: UserType
onSubmit: (data: UserFormSchema) => Promise<void>
}
Expand All @@ -74,6 +76,7 @@ export const UserForm = ({
authUser.user.organization
: user?.organization,
invitationCode: user?.invitationCode ?? '',
dateOfBirth: user?.dateOfBirth ? new Date(user.dateOfBirth) : undefined,
},
})

Expand All @@ -95,6 +98,20 @@ export const UserForm = ({
label="Display name"
render={({ field }) => <Input {...field} />}
/>
<Field
control={form.control}
name="dateOfBirth"
label="Date of Birth"
render={({ field }) => (
<DatePicker
mode="single"
selected={field.value}
onSelect={(date) => field.onChange(date)}
defaultMonth={field.value}
toYear={new Date().getFullYear()}
/>
)}
/>
{isEdit && (
<Field
control={form.control}
Expand Down
5 changes: 3 additions & 2 deletions app/(dashboard)/users/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//
// SPDX-License-Identifier: MIT
//
import { deleteField, updateDoc } from '@firebase/firestore'
import { updateDoc } from '@firebase/firestore'
import { Users } from 'lucide-react'
import { revalidatePath } from 'next/cache'
import { notFound } from 'next/navigation'
Expand Down Expand Up @@ -45,8 +45,9 @@ const UserPage = async ({ params }: UserPageProps) => {
}
const userData = {
invitationCode: form.invitationCode,
organization: form.organizationId ?? deleteField(),
organization: form.organizationId,
type: form.type,
dateOfBirth: form.dateOfBirth?.toISOString(),
}
if (resourceType === 'user') {
await callables.updateUserInformation({
Expand Down
3 changes: 2 additions & 1 deletion app/(dashboard)/users/invite/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ const InviteUserPage = async () => {
user: {
...(form.organizationId ? { organization: form.organizationId } : {}),
type: form.type,
dateOfBirth: form.dateOfBirth?.toISOString(),
},
})
redirect(routes.users.user(result.data.code))
redirect(routes.users.user(result.data.id))
}

return (
Expand Down
4 changes: 4 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,8 @@ SPDX-License-Identifier: MIT
.interactive-opacity {
@apply focus-ring transition-opacity hover:opacity-60;
}

.hide-all-hidden [aria-hidden="true"] {
display: none;
}
}
4 changes: 2 additions & 2 deletions modules/firebase/models/baseTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ export interface FHIRExtension {
}

export interface FHIRPeriod {
start?: Date
end?: Date
start?: string
end?: string
}

export interface FHIRRatio {
Expand Down
7 changes: 4 additions & 3 deletions modules/firebase/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ export enum UserType {

export interface User {
type: UserType
dateOfBirth?: Date
dateOfBirth?: string | null
clinician?: string
dateOfEnrollment?: Date
dateOfEnrollment?: string
invitationCode?: string
messagesSettings?: UserMessagesSettings
organization?: string
Expand Down Expand Up @@ -199,9 +199,10 @@ export const getCallables = (functions: Functions) => ({
clinician?: string
language?: string
timeZone?: string
dateOfBirth?: string | null
}
},
{ code: string }
{ id: string }
>(functions, 'createInvitation'),
getUsersInformation: httpsCallable<
GetUsersInformationInput,
Expand Down
5 changes: 5 additions & 0 deletions packages/design-system/src/components/Calendar/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,16 @@ export const Calendar = ({
<DayPicker
showOutsideDays={showOutsideDays}
className={cn('p-3', className)}
captionLayout="dropdown-buttons"
fromYear={1900}
toYear={2100}
classNames={{
months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
month: 'space-y-4',
caption: 'flex justify-center pt-1 relative items-center',
caption_label: 'text-sm font-medium',
vhidden: 'hidden',
caption_dropdowns: 'hide-all-hidden flex gap-2 text-sm items-center',
nav: 'space-x-1 flex items-center',
nav_button: cn(
buttonVariance({ variant: 'outline' }),
Expand Down
46 changes: 25 additions & 21 deletions packages/design-system/src/components/DatePicker/DatePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,34 @@
import { format, isDate } from 'date-fns'
import { Calendar as CalendarIcon } from 'lucide-react'
import { type ComponentProps } from 'react'
import { type DayPicker } from 'react-day-picker'
import { cn } from '../../utils/className'
import { Button } from '../Button'
import { Calendar } from '../Calendar'
import { Popover, PopoverTrigger, PopoverContent } from '../Popover'

export type DatePickerProps = ComponentProps<typeof DayPicker>
export type DatePickerProps = ComponentProps<typeof Calendar>

export const DatePicker = ({ selected, ...props }: DatePickerProps) => (
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
className={cn(
'!w-[280px] !justify-start !text-left',
!selected && '!text-muted-foreground',
)}
>
<CalendarIcon className="size-4" />
{selected && isDate(selected) ? format(selected, 'PPP') : 'Pick a date'}
</Button>
</PopoverTrigger>
<PopoverContent className="!w-auto !p-0">
<Calendar {...props} />
</PopoverContent>
</Popover>
)
export const DatePicker = (props: DatePickerProps) => {
const { selected } = props
return (
<Popover>
<PopoverTrigger asChild>
<Button
variant="outline"
className={cn(
'!w-full !justify-start !bg-surface-primary !text-left !text-sm',
!selected && '!text-muted-foreground',
)}
>
<CalendarIcon className="size-4" />
{selected && isDate(selected) ?
format(selected, 'PPP')
: 'Pick a date'}
</Button>
</PopoverTrigger>
<PopoverContent className="!w-auto !p-0">
<Calendar {...props} />
</PopoverContent>
</Popover>
)
}

0 comments on commit 465a113

Please sign in to comment.