Skip to content

Commit

Permalink
Fix validation error with multiple choice & other fields on VSR edit …
Browse files Browse the repository at this point in the history
…page
  • Loading branch information
benjaminJohnson2204 committed Apr 18, 2024
1 parent adef760 commit ad3b163
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 17 deletions.
3 changes: 3 additions & 0 deletions frontend/src/components/VSRForm/VSRFormTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface IVSRFormInput {
age: number;
ethnicity: string[];
other_ethnicity: string;
form_ethnicity: string;
employment_status: string;
income_level: string;
size_of_home: string;
Expand All @@ -29,13 +30,15 @@ export interface IVSRFormInput {
branch: string[];
conflicts: string[];
other_conflicts: string;
form_conflicts: string;
dischargeStatus: string;
serviceConnected: boolean;
lastRank: string;
militaryID: number;
petCompanion: boolean;
hearFrom: string;
other_hearFrom: string;
form_hearFrom: string;

selectedFurnitureItems: Record<string, FurnitureInput>;
additionalItems: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface MultipleChoiceWithOtherInputDetailProps {
title: string;
name: keyof IEditVSRFormInput;
otherName: keyof IEditVSRFormInput;
formName: keyof IEditVSRFormInput;
options: string[];
allowMultiple: boolean;
formProps: UseFormReturn<IEditVSRFormInput>;
Expand All @@ -23,32 +24,72 @@ export const MultipleChoiceWithOtherInputDetail = ({
title,
name,
otherName,
formName,
options,
allowMultiple,
formProps,
...props
}: MultipleChoiceWithOtherInputDetailProps) => {
/**
* Callback fired when one of the inputs (multiple choice or "Other" text input) changes,
* to handle the change and update all our form inputs
*
* @param fieldValue the new value of the multiple choice field
* @param otherFieldValue the new value of the "Other" field
* @param otherJustChanged whether the "Other" field just changed (if true), or the multiple
* choice field just changed (if false)
* @param onOtherChange callback to fire when "Other" input changes; since this changes often
* (every time the user presses a key), we want this to be fast, so we use the field.onChange
* instead of formProps.setValue()
*/
const handleInputChange = (
fieldValue: string | string[],
otherFieldValue: string,
otherJustChanged: boolean,
onOtherChange: (value: string) => unknown,
) => {
// Whether either field is non-empty (used to determine whether there is a form error)
const isNonEmpty =
(allowMultiple ? (fieldValue as string[]).length > 0 : fieldValue.toString().length > 0) ||
otherFieldValue.length > 0;

// Update both fields to their new values. If we don't allow multiple, clear the
// field (multiple vs. other) that didn't just change
if (otherJustChanged) {
formProps.setValue(name, allowMultiple ? fieldValue : "");
onOtherChange(otherFieldValue);
} else {
formProps.setValue(name, fieldValue);
formProps.setValue(otherName, allowMultiple ? otherFieldValue : "");
}

// Update our formName phantom field to store whether the field is empty and
// throw a validation error if so
formProps.setValue(formName, isNonEmpty ? "full" : "");
};

return (
<FieldDetail title={title}>
<Controller
name={name}
name={formName}
control={formProps.control}
rules={vsrInputFieldValidators[name]}
render={({ field }) => (
render={() => (
<MultipleChoice
label=""
options={options}
value={field.value as string | string[]}
value={formProps.getValues()[name] as string | string[]}
onChange={(value) => {
field.onChange(value);
if (!allowMultiple && value.length > 0) {
// If user can't enter multiple options, clear the "other" text field when they select an option
formProps.setValue(otherName, "");
}
handleInputChange(
value,
formProps.getValues()[otherName] as string,
false,
(otherValue) => formProps.setValue(otherName, otherValue),
);
}}
required={false}
error={!!formProps.formState.errors[name]}
helperText={formProps.formState.errors[name]?.message as string}
error={!!formProps.formState.errors[formName]}
helperText={formProps.formState.errors[formName]?.message as string}
allowMultiple={allowMultiple}
{...props}
/>
Expand All @@ -66,12 +107,12 @@ export const MultipleChoiceWithOtherInputDetail = ({
value={field.value}
onChange={(e) => {
const value = e.target.value;
field.onChange(value);
if (!allowMultiple && value.length > 0) {
// If user can't enter multiple options, clear the chips field when
// they enter something into the "other" text field
formProps.setValue(name, "");
}
handleInputChange(
formProps.getValues()[name] as string | string[],
value,
true,
field.onChange,
);
}}
variant={"outlined"}
required={false}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const AdditionalInfo = ({ vsr, isEditing, formProps }: AdditionalInfoProp
const isHearFromChip = hearFromOptions.includes(vsr.hearFrom);
formProps.setValue("hearFrom", isHearFromChip ? vsr.hearFrom : "");
formProps.setValue("other_hearFrom", isHearFromChip ? "" : vsr.hearFrom);
formProps.setValue("form_hearFrom", vsr.hearFrom.length > 0 ? "full" : "");
}, [vsr]);

return (
Expand All @@ -39,6 +40,7 @@ export const AdditionalInfo = ({ vsr, isEditing, formProps }: AdditionalInfoProp
<ListDetail
title="Are you interested in a companionship animal (pet)?"
values={[vsr.petCompanion ? "Yes" : "No"]}
isEmpty={false}
/>
)}
</div>
Expand All @@ -47,13 +49,14 @@ export const AdditionalInfo = ({ vsr, isEditing, formProps }: AdditionalInfoProp
<MultipleChoiceWithOtherInputDetail
name="hearFrom"
otherName="other_hearFrom"
formName="form_hearFrom"
title="How did you hear about us?"
formProps={formProps}
options={hearFromOptions}
allowMultiple={false}
/>
) : (
<ListDetail title="How did you hear about us?" values={[vsr.hearFrom]} />
<ListDetail title="How did you hear about us?" values={[vsr.hearFrom]} isEmpty={false} />
)}
</div>
</VSRIndividualAccordion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const MilitaryBackground = ({ vsr, isEditing, formProps }: MilitaryBackgr
}
}
formProps.setValue("conflicts", conflictChips);
formProps.setValue("form_conflicts", vsr.conflicts.length > 0 ? "full" : "");
formProps.setValue("dischargeStatus", vsr.dischargeStatus);
formProps.setValue("serviceConnected", vsr.serviceConnected);
formProps.setValue("lastRank", vsr.lastRank);
Expand Down Expand Up @@ -63,6 +64,7 @@ export const MilitaryBackground = ({ vsr, isEditing, formProps }: MilitaryBackgr
<MultipleChoiceWithOtherInputDetail
name="conflicts"
otherName="other_conflicts"
formName="form_conflicts"
title="Conflicts"
formProps={formProps}
options={conflictsOptions}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const PersonalInformation = ({ vsr, isEditing, formProps }: PersonalInfor
}
}
formProps.setValue("ethnicity", ethnicityChips);
formProps.setValue("form_ethnicity", vsr.ethnicity.length > 0 ? "full" : "");
formProps.setValue("employment_status", vsr.employmentStatus);
formProps.setValue("income_level", vsr.incomeLevel);
formProps.setValue("size_of_home", vsr.sizeOfHome);
Expand Down Expand Up @@ -193,6 +194,7 @@ export const PersonalInformation = ({ vsr, isEditing, formProps }: PersonalInfor
title="Ethnicity"
name="ethnicity"
otherName="other_ethnicity"
formName="form_ethnicity"
options={ethnicityOptions}
allowMultiple
formProps={formProps}
Expand Down

0 comments on commit ad3b163

Please sign in to comment.