diff --git a/frontend/src/app/patients/Components/PersonForm.tsx b/frontend/src/app/patients/Components/PersonForm.tsx index cf23019be26..154ae4ddfea 100644 --- a/frontend/src/app/patients/Components/PersonForm.tsx +++ b/frontend/src/app/patients/Components/PersonForm.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useState, useEffect, useRef } from "react"; -import { SchemaOf } from "yup"; +import { AnyObjectSchema } from "yup"; import { useTranslation } from "react-i18next"; import { ComboBox, Label, Textarea } from "@trussworks/react-uswds"; @@ -13,11 +13,7 @@ import RadioGroup from "../../commonComponents/RadioGroup"; import RequiredMessage from "../../commonComponents/RequiredMessage"; import { showError } from "../../utils/srToast"; import FormGroup from "../../commonComponents/FormGroup"; -import { - PersonErrors, - PersonUpdateFields, - usePersonSchemata, -} from "../personSchema"; +import { PersonErrors, usePersonSchemata } from "../personSchema"; import { TestResultDeliveryPreference } from "../TestResultDeliveryPreference"; import Input from "../../commonComponents/Input"; import Select from "../../commonComponents/Select"; @@ -103,7 +99,7 @@ const PersonForm = (props: Props) => { getValidationError, } = usePersonSchemata(); - const schemata: Record> = { + const schemata: Record = { [PersonFormView.APP]: personSchema, [PersonFormView.PXP]: personUpdateSchema, [PersonFormView.SELF_REGISTRATION]: selfRegistrationSchema, diff --git a/frontend/src/app/patients/personSchema.ts b/frontend/src/app/patients/personSchema.ts index f5b7ec9be38..1bbcc2015d8 100644 --- a/frontend/src/app/patients/personSchema.ts +++ b/frontend/src/app/patients/personSchema.ts @@ -25,7 +25,8 @@ const phoneUtil = PhoneNumberUtil.getInstance(); const MAX_LENGTH = 256; const NOTES_MAX_LENGTH = 10000; -type TranslatedSchema = (t: TFunction) => yup.SchemaOf; +// eslint-disable-next-line +type TranslatedSchema = (t: TFunction) => yup.ObjectSchema; type PartialBy = Omit & Partial>; @@ -219,18 +220,20 @@ const getPhoneNumberSchema = (t: TFunction) => { hasPhoneType ) .when("unknownPhoneNumber", { - is: false, - then: yup.array().min(1, t("patient.form.errors.phoneNumbers") || ""), + is: undefined, + then: () => + yup.array().min(1, t("patient.form.errors.phoneNumbers") || ""), }); }; const getRequiredAddressSchema = (t: TFunction, key: string) => { return yup.string().when("unknownAddress", { is: false, - then: yup - .string() - .max(MAX_LENGTH, t("patient.form.errors.fieldLength") || "") - .required(t(key) || ""), + then: () => + yup + .string() + .max(MAX_LENGTH, t("patient.form.errors.fieldLength") || "") + .required(t(key) || ""), }); }; @@ -242,11 +245,12 @@ const updateFieldSchemata: ( lookupId: yup.string().nullable(), role: yup .mixed() + .nullable() .oneOf( [...getValues(ROLE_VALUES), "UNKNOWN", "", null], t("patient.form.errors.role") || "" ), - telephone: yup.mixed().optional(), + telephone: yup.string().nullable().optional(), phoneNumbers: getPhoneNumberSchema(t), emails: yup .array() @@ -267,39 +271,46 @@ const updateFieldSchemata: ( country: yup.string().required(t("patient.form.errors.country") || ""), race: yup .mixed() - .oneOf(getValues(RACE_VALUES), t("patient.form.errors.race") || ""), + .oneOf(getValues(RACE_VALUES), t("patient.form.errors.race") || "") + .required(), ethnicity: yup .mixed() .oneOf( getValues(ETHNICITY_VALUES), t("patient.form.errors.ethnicity") || "" - ), + ) + .required(), gender: yup .mixed() - .oneOf(getValues(GENDER_VALUES), t("patient.form.errors.gender") || ""), + .oneOf(getValues(GENDER_VALUES), t("patient.form.errors.gender") || "") + .required(), genderIdentity: yup .mixed() + .nullable() .oneOf( - [...getValues(GENDER_IDENTITY_VALUES), null], + [...getValues(GENDER_IDENTITY_VALUES), "", null], t("patient.form.errors.genderIdentity") || "" ) - .nullable(), + .notRequired(), residentCongregateSetting: yup.boolean().nullable(), employedInHealthcare: yup.boolean().nullable(), tribalAffiliation: yup .mixed() + .nullable() .oneOf( [...getValues(TRIBAL_AFFILIATION_VALUES), "", null], t("patient.form.errors.tribalAffiliation") || "" ), preferredLanguage: yup .mixed() + .nullable() .oneOf( [...languages, "", null], t("patient.form.errors.preferredLanguage") || "" ), testResultDelivery: yup .mixed() + .nullable() .oneOf( [...Object.values(TestResultDeliveryPreferences), "", null], t("patient.form.errors.testResultDelivery") || "" @@ -315,7 +326,7 @@ const updatePhoneNumberSchemata: ( ) => Record = (t) => ({ number: yup .string() - .max(MAX_LENGTH, t("patient.form.errors.fieldLength") || "") + .max(MAX_LENGTH, () => t("patient.form.errors.fieldLength") || "") .test( "phone-number", t("patient.form.errors.telephone") || "", @@ -327,7 +338,8 @@ const updatePhoneNumberSchemata: ( .oneOf( getValues(PHONE_TYPE_VALUES), t("patient.form.errors.phoneNumbersType") || "" - ), + ) + .required(t("patient.form.errors.phoneNumbersType") || ""), }); const translateUpdateEmailSchemata = (t: TFunction) => { diff --git a/frontend/src/app/signUp/IdentityVerification/PersonalDetailsForm.tsx b/frontend/src/app/signUp/IdentityVerification/PersonalDetailsForm.tsx index 390a9b64873..7a775fbaeca 100644 --- a/frontend/src/app/signUp/IdentityVerification/PersonalDetailsForm.tsx +++ b/frontend/src/app/signUp/IdentityVerification/PersonalDetailsForm.tsx @@ -84,6 +84,7 @@ const PersonalDetailsForm = ({ setSubmitted(true); return; } + // @ts-ignore setErrors(validation.errors); focusOnce.current = true; showError(FORM_ERROR_MSG, FORM_ERROR_TITLE); diff --git a/frontend/src/app/signUp/IdentityVerification/utils.ts b/frontend/src/app/signUp/IdentityVerification/utils.ts index 00393aa8d02..3bb20f8c340 100644 --- a/frontend/src/app/signUp/IdentityVerification/utils.ts +++ b/frontend/src/app/signUp/IdentityVerification/utils.ts @@ -40,7 +40,9 @@ export const initAnswers = (questionSet: Question[]): Nullable => return answers; }, {} as Nullable); -export const buildSchema = (questionSet: Question[]): yup.SchemaOf => +export const buildSchema = ( + questionSet: Question[] +): yup.ObjectSchema => yup.object( questionSet.reduce((answers, _question, index) => { answers[getAnswerKey(index)] = yup @@ -101,8 +103,8 @@ const experianStreetRegex = new RegExp("^([a-zA-Z0-9# \\-'.]{1,60})$", "m"); // this is the regex experian uses for zip validation const experianZipRegex = new RegExp("^(\\d{5}(-?\\d{4})?){1}$", "m"); -export const personalDetailsSchema: yup.SchemaOf = - yup.object().shape({ +export const personalDetailsSchema: yup.ObjectSchema = + yup.object({ firstName: yup.string().required("First name is required"), middleName: yup.string().nullable(), lastName: yup.string().required("Last name is required"), @@ -115,13 +117,13 @@ export const personalDetailsSchema: yup.SchemaOf = .email("A valid email address is required") .required("A valid email address is required"), phoneNumber: yup - .mixed() + .string() .test( "phone-number", "A valid phone number is required", phoneNumberIsValid ) - .required(), + .required("A valid phone number is required"), streetAddress1: yup .string() .matches(experianStreetRegex, "A valid street address is required") diff --git a/frontend/src/app/signUp/Organization/OrganizationForm.tsx b/frontend/src/app/signUp/Organization/OrganizationForm.tsx index 7df01e78c2d..6f835270ec4 100644 --- a/frontend/src/app/signUp/Organization/OrganizationForm.tsx +++ b/frontend/src/app/signUp/Organization/OrganizationForm.tsx @@ -101,6 +101,7 @@ const OrganizationForm = () => { setErrors(initOrgErrors()); return; } + // @ts-ignore setErrors(validation.errors); focusOnce.current = true; showError(FORM_ERROR_MSG, FORM_ERROR_TITLE); diff --git a/frontend/src/app/signUp/Organization/utils.tsx b/frontend/src/app/signUp/Organization/utils.tsx index 59461e07a0e..5df201ac754 100644 --- a/frontend/src/app/signUp/Organization/utils.tsx +++ b/frontend/src/app/signUp/Organization/utils.tsx @@ -92,13 +92,15 @@ export const initOrgErrors = (): Record< workPhoneNumber: "", }); -export const organizationSchema: yup.SchemaOf = yup - .object() - .shape({ +export const organizationSchema: yup.ObjectSchema = + yup.object({ name: yup.string().required("Organization name is required"), type: yup - .mixed() - .oneOf(Object.keys(OrganizationTypeEnum), "Organization type is required") + .string() + .oneOf( + Object.keys(OrganizationTypeEnum) as OrganizationType[], + "Organization type is required" + ) .required(), state: yup.string().required("State is required"), firstName: yup.string().required("First name is required"), @@ -109,7 +111,7 @@ export const organizationSchema: yup.SchemaOf = yup .email("A valid email address is required") .required("A valid email address is required"), workPhoneNumber: yup - .mixed() + .string() .test("", "A valid phone number is required", phoneNumberIsValid) .required(), }); diff --git a/frontend/src/app/supportAdmin/PendingOrganizations/utils.tsx b/frontend/src/app/supportAdmin/PendingOrganizations/utils.tsx index c1025cb6b9d..4d0210b6e3b 100644 --- a/frontend/src/app/supportAdmin/PendingOrganizations/utils.tsx +++ b/frontend/src/app/supportAdmin/PendingOrganizations/utils.tsx @@ -1,7 +1,3 @@ -import * as yup from "yup"; - -import { phoneNumberIsValid } from "../../patients/personSchema"; - export interface PendingOrganizationFormValues { name: string; adminFirstName: string | undefined; @@ -15,17 +11,3 @@ export interface EditOrgMutationResponse { editPendingOrganization: string; }; } - -const phoneNumberIsValidOrEmpty = (input: any) => - input === "" || phoneNumberIsValid(input); - -export const pendingOrganizationSchema: yup.SchemaOf = - yup.object().shape({ - name: yup.string().required("Organization name is required"), - adminFirstName: yup.string(), - adminLastName: yup.string(), - adminEmail: yup.string().email("A valid email address is required"), - adminPhone: yup - .mixed() - .test("", "A valid phone number is required", phoneNumberIsValidOrEmpty), - }); diff --git a/frontend/src/app/utils/yupHelpers.ts b/frontend/src/app/utils/yupHelpers.ts index e395755b2a3..0f64fbf2c55 100644 --- a/frontend/src/app/utils/yupHelpers.ts +++ b/frontend/src/app/utils/yupHelpers.ts @@ -4,7 +4,7 @@ type Errors = Record; interface FormValidProps { data: T; - schema: yup.SchemaOf; + schema: yup.AnySchema; } interface Success { @@ -48,7 +48,7 @@ export const isFormValid = async ({ interface FieldValidProps { data: T; field: keyof T; - schema: yup.SchemaOf; + schema: yup.AnyObjectSchema; errors: Errors; }