diff --git a/packages/esm-patient-registration-app/src/patient-registration/field/dob/dob.component.tsx b/packages/esm-patient-registration-app/src/patient-registration/field/dob/dob.component.tsx index ec5eabc3b..2f1ed260d 100644 --- a/packages/esm-patient-registration-app/src/patient-registration/field/dob/dob.component.tsx +++ b/packages/esm-patient-registration-app/src/patient-registration/field/dob/dob.component.tsx @@ -1,12 +1,12 @@ -import React, { type ChangeEvent, useCallback, useContext } from 'react'; -import { ContentSwitcher, Layer, Switch, TextInput } from '@carbon/react'; +import React, { useCallback } from 'react'; +import { ContentSwitcher, Layer, Switch } from '@carbon/react'; import { useTranslation } from 'react-i18next'; -import { PatientRegistrationContext } from '../../patient-registration-context'; import { OpenmrsDatePicker, useConfig } from '@openmrs/esm-framework'; import { type RegistrationConfig } from '../../../config-schema'; import styles from '../field.scss'; -import { usePatientRegistrationContext } from '../../patient-registration-hooks'; -import { Controller } from 'react-hook-form'; +import { Controller, useFormContext } from 'react-hook-form'; +import useZodSchema from '../../useZodSchema'; +import { NumberInput } from '@carbon/react'; const calcBirthdate = (yearDelta, monthDelta, dateOfBirth) => { const { enabled, month, dayOfMonth } = dateOfBirth.useEstimatedDateOfBirth; @@ -27,62 +27,67 @@ export const DobField: React.FC = () => { fieldConfigurations: { dateOfBirth }, } = useConfig(); const allowEstimatedBirthDate = dateOfBirth?.allowEstimatedDateOfBirth; - const { watch, control, setValue } = usePatientRegistrationContext(); + const { watch, control, setValue } = useFormContext(); const dobUnknown = watch('birthdateEstimated'); const today = new Date(); - const monthsEstimated = watch('monthsEstimated'); - const yearsEstimated = watch('yearsEstimated'); + + const { updateZodSchema } = useZodSchema(); + + // useEffect(() => { + // const yearsEstimatedSchema = z + // .number({ + // invalid_type_error: t('yearsEstimatedTypeError', 'Years estimated must be a number'), + // }) + // .min(0) + // .max(140, { + // message: t('maxError', 'Max error'), + // }); + // updateZodSchema('yearsEstimated', dobUnknown ? yearsEstimatedSchema : yearsEstimatedSchema.optional()); + // }, [t, dobUnknown]); const onToggle = useCallback( (e: { name?: string | number }) => { setValue('birthdateEstimated', e.name === 'unknown'); setValue('birthdate', ''); - setValue('yearsEstimated', 0); + setValue('yearsEstimated', undefined); setValue('monthsEstimated', undefined); // setFieldTouched('birthdateEstimated', true, false); }, [setValue], ); - const onDateChange = useCallback( - (birthdate: Date) => { - setValue('birthdate', birthdate); - // setFieldTouched('birthdate', true, false); - }, - [setValue], - ); + // TODO: Make this validated as different fields + // const onEstimatedYearsChange = useCallback( + // (ev: ChangeEvent) => { + // const years = +ev.target.value; - const onEstimatedYearsChange = useCallback( - (ev: ChangeEvent) => { - const years = +ev.target.value; + // if (!isNaN(years) && years < 140 && years >= 0) { + // setValue('yearsEstimated', years); + // setValue('birthdate', calcBirthdate(years, monthsEstimated, dateOfBirth)); + // } + // }, + // [setValue, dateOfBirth, monthsEstimated], + // ); - if (!isNaN(years) && years < 140 && years >= 0) { - setValue('yearsEstimated', years); - setValue('birthdate', calcBirthdate(years, monthsEstimated, dateOfBirth)); - } - }, - [setValue, dateOfBirth, monthsEstimated], - ); + // const onEstimatedMonthsChange = useCallback( + // (ev: ChangeEvent) => { + // const months = +ev.target.value; - const onEstimatedMonthsChange = useCallback( - (ev: ChangeEvent) => { - const months = +ev.target.value; - - if (!isNaN(months)) { - setValue('monthsEstimated', months); - setValue('birthdate', calcBirthdate(yearsEstimated, months, dateOfBirth)); - } - }, - [setValue, dateOfBirth, yearsEstimated], - ); + // if (!isNaN(months)) { + // setValue('monthsEstimated', months); + // setValue('birthdate', calcBirthdate(yearsEstimated, months, dateOfBirth)); + // } + // }, + // [setValue, dateOfBirth, yearsEstimated], + // ); - const updateBirthdate = useCallback(() => { - const months = +monthsEstimated % 12; - const years = +yearsEstimated + Math.floor(monthsEstimated / 12); - setValue('yearsEstimated', years); - setValue('monthsEstimated', months > 0 ? months : undefined); - setValue('birthdate', calcBirthdate(years, months, dateOfBirth)); - }, [setValue, monthsEstimated, yearsEstimated, dateOfBirth]); + // const updateBirthdate = useCallback(() => { + // const months = +monthsEstimated % 12; + // const years = +yearsEstimated + Math.floor(monthsEstimated / 12); + // setValue('yearsEstimated', years); + // setValue('monthsEstimated', months > 0 ? months : undefined); + // setValue('birthdate', calcBirthdate(years, months, dateOfBirth)); + // }, [setValue, monthsEstimated, yearsEstimated, dateOfBirth]); return (
@@ -108,10 +113,10 @@ export const DobField: React.FC = () => { )} @@ -123,20 +128,19 @@ export const DobField: React.FC = () => { ( - - )} + render={({ field, fieldState: { isTouched, error } }) => { + return ( + + ); + }} />
@@ -144,17 +148,14 @@ export const DobField: React.FC = () => { control={control} name="monthsEstimated" render={({ field, fieldState: { isTouched, error } }) => ( - )} /> diff --git a/packages/esm-patient-registration-app/src/patient-registration/input/basic-input/input/input.component.tsx b/packages/esm-patient-registration-app/src/patient-registration/input/basic-input/input/input.component.tsx index f6f7ea5f7..e38db2b49 100644 --- a/packages/esm-patient-registration-app/src/patient-registration/input/basic-input/input/input.component.tsx +++ b/packages/esm-patient-registration-app/src/patient-registration/input/basic-input/input/input.component.tsx @@ -132,7 +132,7 @@ interface InputProps extends TextInputProps { export const Input: React.FC = ({ checkWarning, ...props }) => { const { t } = useTranslation(); - const { formState, getFieldState, control } = useContext(PatientRegistrationContext); + const { getFieldState, control, watch } = useContext(PatientRegistrationContext); const { error } = getFieldState(props.name); /* @@ -155,7 +155,7 @@ export const Input: React.FC = ({ checkWarning, ...props }) => { t('nonCodedCauseOfDeathRequired', 'Non-coded cause of death is required') */ - const value = props.value || ''; + const value = watch(props.name) as string; const invalidText = error?.message; const warnText = useMemo(() => { if (!invalidText && typeof checkWarning === 'function') { @@ -183,7 +183,6 @@ export const Input: React.FC = ({ checkWarning, ...props }) => { invalidText={invalidText} warn={!!warnText} warnText={warnText} - value={value} /> )} diff --git a/packages/esm-patient-registration-app/src/patient-registration/patient-registration-rhf.component.tsx b/packages/esm-patient-registration-app/src/patient-registration/patient-registration-rhf.component.tsx index 3046690be..8ec47408b 100644 --- a/packages/esm-patient-registration-app/src/patient-registration/patient-registration-rhf.component.tsx +++ b/packages/esm-patient-registration-app/src/patient-registration/patient-registration-rhf.component.tsx @@ -69,7 +69,7 @@ export const PatientRegistration: React.FC = ({ savePa .filter((s) => s); }, [config.sections, config.sectionDefinitions]); - const zodSchema = useZodSchema(); + const { zodSchema } = useZodSchema(); const methods = useForm({ defaultValues: initialFormValues, @@ -85,12 +85,6 @@ export const PatientRegistration: React.FC = ({ savePa reset, } = methods; - useEffect(() => { - reset(initialFormValues, { - keepDirtyValues: true, - }); - }, [initialFormValues]); - const onFormSubmit = async (values: FormValues) => { const abortController = new AbortController(); // helpers.setSubmitting(true); diff --git a/packages/esm-patient-registration-app/src/patient-registration/useZodSchema.ts b/packages/esm-patient-registration-app/src/patient-registration/useZodSchema.ts index 14c583234..c6f305e26 100644 --- a/packages/esm-patient-registration-app/src/patient-registration/useZodSchema.ts +++ b/packages/esm-patient-registration-app/src/patient-registration/useZodSchema.ts @@ -1,9 +1,26 @@ import { getGlobalStore } from '@openmrs/esm-framework'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { z } from 'zod'; +import type { FormValues } from './patient-registration.types'; +import { useTranslation } from 'react-i18next'; export function getZodSchemaStore() { - return getGlobalStore('patient-registration-zod-schema', z.object({ firstName: z.string() })); + return getGlobalStore>>( + 'patient-registration-zod-schema', + z.object({ + firstName: z.string({ + required_error: 'First name is required', + }), + yearsEstimated: z + .number({ + invalid_type_error: 'Years estimated must be a number', + }) + .min(0) + .max(140, { + message: 'Max error', + }), + }), + ); } export function addFieldSchemaToZod(fieldName: string, schema: z.ZodSchema) { @@ -14,13 +31,28 @@ export function addFieldSchemaToZod(fieldName: string, schema: z.ZodSchema) { })); } +type T = keyof FormValues; + export default function useZodSchema() { + const { t } = useTranslation(); const [zodSchema, setZodSchema] = useState(getZodSchemaStore().getState()); + const updateZodSchema = useCallback((key: T, value: z.ZodSchema) => { + getZodSchemaStore().setState({ + [key]: value, + }); + }, []); useEffect(() => { const unsubscribe = getZodSchemaStore().subscribe(setZodSchema); return () => { unsubscribe(); }; }, [setZodSchema]); - return zodSchema; + const results = useMemo( + () => ({ + zodSchema, + updateZodSchema, + }), + [zodSchema, updateZodSchema], + ); + return results; }