diff --git a/apps/expo/src/app/(app)/profile/about.tsx b/apps/expo/src/app/(app)/profile/about.tsx index ea8db70..048aadb 100644 --- a/apps/expo/src/app/(app)/profile/about.tsx +++ b/apps/expo/src/app/(app)/profile/about.tsx @@ -12,9 +12,17 @@ import { DemographicsInfo } from '@/components/organisms/DemographicsInfo'; import { usePatient } from '@/context/PatientContext'; import { getCodeFromConcept } from '@/fhirpath/utils'; import { palette } from '@/theme/colors'; +import { + ETHNICITY_EXTENSION_URL, + GENDER_IDENTITY_EXTENSION_URL, + RACE_EXTENSION_URL, +} from '@/types/patient'; import { api } from '@/utils/api'; +import { getEthnicityExtension, getGenderIdentityExtension, getRaceExtension } from '@/utils/fhir'; import { MaterialCommunityIcons } from '@expo/vector-icons'; +import { type Extension } from '@careforge/canvas'; + const About = () => { const [goalModalOpen, setGoalModalOpen] = useState(false); const [demographicsModalOpen, setDemographicsModalOpen] = useState(false); @@ -41,9 +49,36 @@ const About = () => { }, }); - const handleDemographicsSave = useCallback((_form: DemographicsFormType) => { - Alert.alert('TODO: update patient resource'); - }, []); + const handleDemographicsSave = useCallback( + (form: DemographicsFormType) => { + const raceExtension = getRaceExtension({ raceCodes: form.race }); + const ethnicityExtension = getEthnicityExtension({ ethnicityCodes: form.ethnicity }); + const genderIdentityExtension = getGenderIdentityExtension({ + genderCode: form.genderIdentity, + }); + + const newPatientExtension: Extension[] = [ + ...(patient?.extension?.filter( + ({ url }) => + url !== RACE_EXTENSION_URL && + url !== ETHNICITY_EXTENSION_URL && + url !== GENDER_IDENTITY_EXTENSION_URL, + ) ?? []), + ...(raceExtension ? [raceExtension] : []), + ...(ethnicityExtension ? [ethnicityExtension] : []), + ...(genderIdentityExtension ? [genderIdentityExtension] : []), + ]; + + updatePatientMutation.mutate({ + id: patient!.id, + resource: { + ...patient, + extension: newPatientExtension, + }, + }); + }, + [patient, updatePatientMutation], + ); if (isLoading) { return ( diff --git a/apps/expo/src/components/organisms/DemographicsForm.tsx b/apps/expo/src/components/organisms/DemographicsForm.tsx index cbaff8d..44f7879 100644 --- a/apps/expo/src/components/organisms/DemographicsForm.tsx +++ b/apps/expo/src/components/organisms/DemographicsForm.tsx @@ -1,21 +1,39 @@ import React from 'react'; import { View } from 'react-native'; import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'; +import { getEthnicityCodes, getGenderIdentityCode, getRaceCodes } from '@/fhirpath/patient'; +import { + ETHNICITY_DISPLAY_TO_CODE, + EthnicityCodeSchema, + ethnicityOptions, + GENDER_DISPLAY_TO_CODE, + GenderCodeSchema, + genderIdentityOptions, + RACE_DISPLAY_TO_CODE, + RaceCodeSchema, + raceOptions, +} from '@/types/patient'; import { zodResolver } from '@hookform/resolvers/zod'; -import { useForm } from 'react-hook-form'; +import { Controller, useForm } from 'react-hook-form'; import { z } from 'zod'; import { type Patient } from '@careforge/canvas'; import { Button } from '../atoms/Button'; +import { Checkbox } from '../atoms/Checkbox'; +import { RadioButton } from '../atoms/RadioButton'; import { Text } from '../atoms/Text'; -const DemographicsFormSchema = z.object({}); +const DemographicsFormSchema = z.object({ + genderIdentity: GenderCodeSchema.optional(), + race: RaceCodeSchema.array().optional(), + ethnicity: EthnicityCodeSchema.array().optional(), +}); export type DemographicsFormType = z.infer; export const DemographicsForm = ({ - patient: _patient, + patient, onSubmit, onCancel, isMutating, @@ -25,23 +43,107 @@ export const DemographicsForm = ({ onCancel: () => void; isMutating?: boolean; }) => { + const genderCode = getGenderIdentityCode(patient); + const raceCodes = getRaceCodes(patient); + const ethnicityCodes = getEthnicityCodes(patient); + const { formState: { isValid }, handleSubmit, + control, + watch, } = useForm({ resolver: zodResolver(DemographicsFormSchema), - defaultValues: {}, + defaultValues: { + genderIdentity: genderCode, + race: raceCodes, + ethnicity: ethnicityCodes, + }, }); + const currentGender = watch('genderIdentity'); + return ( Edit Demographics - TODO + Gender + + {genderIdentityOptions.map((option) => ( + ( + { + onChange(GENDER_DISPLAY_TO_CODE[option]); + }} + /> + )} + /> + ))} + + + + Race + {raceOptions.map((option) => ( + ( + { + const code = RACE_DISPLAY_TO_CODE[option]; + if (value?.includes(code)) { + const newValue = value ? [...value] : []; + newValue.splice(newValue.indexOf(code), 1); + + onChange(newValue); + } else { + onChange([...(value ?? []), code]); + } + }} + /> + )} + /> + ))} + + + Ethnicity + {ethnicityOptions.map((option) => ( + ( + { + const code = ETHNICITY_DISPLAY_TO_CODE[option]; + if (value?.includes(code)) { + const newValue = value ? [...value] : []; + newValue.splice(newValue.indexOf(code), 1); + + onChange(newValue); + } else { + onChange([...(value ?? []), code]); + } + }} + /> + )} + /> + ))} - +