Skip to content

Commit

Permalink
Prp 329 Date of birth error propagation
Browse files Browse the repository at this point in the history
  • Loading branch information
microwavenby authored May 19, 2023
1 parent 2c2274e commit 2a82e9b
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 41 deletions.
30 changes: 22 additions & 8 deletions participant/app/components/DateInput.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import type { ReactElement } from "react";
import { Fieldset, DateInputGroup, FormGroup } from "@trussworks/react-uswds";
import {
Fieldset,
DateInputGroup,
FormGroup,
Label,
ErrorMessage,
} from "@trussworks/react-uswds";
import Required from "app/components/Required";
import { TextField } from "app/components/TextField";
import { TextInput } from "@trussworks/react-uswds";
import { useField } from "remix-validated-form";
import type { i18nKey, legendStyleType } from "~/types";
import { Trans, useTranslation } from "react-i18next";

Expand Down Expand Up @@ -37,20 +44,24 @@ export const DateInput = (props: DateInputProps): ReactElement => {
values,
} = props;
const { t } = useTranslation();
const { error, clearError, validate } = useField(name);
const legendElement = (
<div>
<Trans i18nKey={legendKey} />
{required ? <Required /> : ""}
</div>
);
const onBlurFunc = () => {
clearError();
validate();
};
const hintKey = DMYorder ? `${dateKey}.hintDMY` : `${dateKey}.hintMDY`;
const hintElement =
hint && t(hintKey) ? (
<div className="usa-hint" id="dateOfBirthHint">
<Trans i18nKey={hintKey} />
</div>
) : undefined;

const orderedFields: DateFieldTypes[] = DMYorder
? ["day", "month", "year"]
: ["month", "day", "year"];
Expand All @@ -61,21 +72,24 @@ export const DateInput = (props: DateInputProps): ReactElement => {
className={`usa-form-group--${field}`}
key={`${keyBase}-${field}`}
>
<TextField
<Label htmlFor={`${name}.${field}`}>{t(`${dateKey}.${field}`)}</Label>
<TextInput
id={`${name}.${field}`}
labelKey={`${dateKey}.${field}`}
name={`${name}.${field}`}
size={maxLength}
inputType="text"
type="input"
type="text"
required={required}
requiredStar={false}
onBlur={onBlurFunc}
defaultValue={values && values[field]?.toString()}
/>
</FormGroup>
);
});
return (
<Fieldset legend={legendElement} legendStyle={legendStyle}>
{error && (
<ErrorMessage id={`${name}-error-message`}>{error}</ErrorMessage>
)}
{hintElement}
<DateInputGroup>{orderedDateFields}</DateInputGroup>
</Fieldset>
Expand Down
71 changes: 42 additions & 29 deletions participant/app/utils/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,40 +91,53 @@ export const participantSchema = zfd.formData({
),
preferredName: zfd.text(z.string().optional()),

dob: z.object({
day: zfd.numeric(
z
.number()
.min(1, {
message:
"Date of birth must include a valid month, day, and year.",
})
.max(31, {
message:
"Date of birth must include a valid month, day, and year.",
})
),
month: zfd.numeric(
z
.number()
.min(1, {
dob: z
.object({
day: zfd.numeric(),
month: zfd.numeric(),
year: zfd.numeric(),
})
.superRefine((val, ctx) => {
if (!val.year || !val.month || !val.day) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
"Date of birth must include a valid month, day, and year.",
})
.max(12, {
});
return z.NEVER;
}
const date = new Date(val.year, val.month - 1, val.day);
const now = new Date();
if (date.valueOf() == undefined) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Enter a valid date of birth",
});
return z.NEVER;
}
if (date.getMonth() != val.month - 1 || date.getDate() != val.day) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message:
"Date of birth must include a valid month, day, and year.",
})
),
year: zfd.numeric(
z
.number()
.min(1912, { message: "Enter a valid date of birth." })
.max(2023, {
});
return z.NEVER;
}
if (date.getFullYear() < now.getFullYear() - 110) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Enter a valid date of birth.",
});
return z.NEVER;
}
if (date > now) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Date of birth must be today or in the past.",
})
),
}),
});
return z.NEVER;
}
}),
adjunctive: zfd.text(
z.enum(["yes", "no"], {
required_error:
Expand Down
8 changes: 4 additions & 4 deletions participant/tests/utils/isValidDetails.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ it("should have an error if dob.month is incorrect", async () => {
);
expect(validationResult.data).toBeUndefined();
expect(validationResult.error?.fieldErrors).toStrictEqual({
"participant[0].dob.month":
"participant[0].dob":
"Date of birth must include a valid month, day, and year.",
});
});
Expand Down Expand Up @@ -136,7 +136,7 @@ it("should have an error if dob.day is incorrect", async () => {
);
expect(validationResult.data).toBeUndefined();
expect(validationResult.error?.fieldErrors).toStrictEqual({
"participant[0].dob.day":
"participant[0].dob":
"Date of birth must include a valid month, day, and year.",
});
});
Expand Down Expand Up @@ -169,7 +169,7 @@ it("should have an error if dob.year is too early", async () => {
);
expect(validationResult.data).toBeUndefined();
expect(validationResult.error?.fieldErrors).toStrictEqual({
"participant[0].dob.year": "Enter a valid date of birth.",
"participant[0].dob": "Enter a valid date of birth.",
});
});

Expand All @@ -186,7 +186,7 @@ it("should have an error if dob.year is back to the future", async () => {
);
expect(validationResult.data).toBeUndefined();
expect(validationResult.error?.fieldErrors).toStrictEqual({
"participant[0].dob.year": "Date of birth must be today or in the past.",
"participant[0].dob": "Date of birth must be today or in the past.",
});
});

Expand Down

0 comments on commit 2a82e9b

Please sign in to comment.