Reputation: 1371
I have a pretty tricky birthdate validation.
As soon as the user tries to put a birthdate younger than 18 years old, the form updates to the date of today minus 18 years. Now, as I've been looking into it more closely, somehow I wish to integrate a notice, so that the user basically is aware, that his/hers birthdate was not accepted. For this I was trying to show a span handling an error message in my Form Component:
{errors.birthdate && (
<span className="text-xs text-red-700">
{errors.birthdate.message}
</span>
)}
I also have a function for validation there:
const validate = (date) =>
isOlderThen18Years(date) || "You must be at least 18 years old";
What is happening, as for resetting a date I am using useEffect in SelectBirthDay:
useEffect(() => {
if (!isOlderThen18Years(value)) {
onChange(
set(new Date(), { year: getYear(value) }),
);
}
}, [value, onChange]);
So this resets the date, but how do I show the error message? So both is happening simultaneously? Surele I could work with some kind of alert. But is it possible to actually show the span in Form Component depending on useEffect outcome in selectBirthDay component?
Upvotes: 0
Views: 3116
Reputation: 6949
You were very close by passing the error message to your onChange
handler in <SelectBirthDay />
.
I think a good option would be to separate your date selection as a component and then just handle the info message there. This way it's separated from the <Form />
component which doesn't have to know about this info message for the user as it is not really a validation message for the form field.
I also would suggest to move the generation of the years to the <SelectBirthYear />
component.
<SelectBirthDate />
import { useState } from "react";
import { SelectBirthDay } from "./SelectBirthDay";
import { SelectBirthMonth } from "./SelectBirthMonth";
import { SelectBirthYear } from "./SelectBirthYear";
export const SelectBirthDate = ({ onChange, ...field }) => {
const [invalidMessage, setInvalidMessage] = useState();
const handleChange = (value, invalidMessage) => {
onChange(value);
setInvalidMessage(invalidMessage);
};
return (
<>
<div className="sm:col-span-2 grid grid-cols-3 gap-4 mb-2">
<div className="mt-1">
<SelectBirthYear onChange={handleChange} {...field} />
</div>
<div className="mt-1">
<SelectBirthMonth onChange={handleChange} {...field} />
</div>
<div className="mt-1">
<SelectBirthDay onChange={handleChange} {...field} />
</div>
</div>
<span className="mt-2 text-sm text-gray-500">{invalidMessage}</span>
</>
);
};
<SelectBirthDay />
export const SelectBirthDay = ({ value, onChange }) => {
const handleChange = (date) => onChange(set(value, { date: date.getDate() }));
const days = eachDayOfInterval({
start: startOfMonth(value),
end: endOfMonth(value)
});
useEffect(() => {
if (!isOlderThen18Years(value)) {
onChange(
set(new Date(), { year: getYear(value) }),
"Selected Date was not older then 18 years - automatically reset to the earliest possible date"
);
}
}, [value, onChange]);
return ...
<Form />
<Controller
control={control}
name="birthdate"
rules={{ validate }}
render={({ field: { ref, ...field } }) => (
<SelectBirthDate {...field} />
)}
/>
{errors.birthdate && (
<span className="text-xs text-red-700">
{errors.birthdate.message}
</span>
)}
Upvotes: 2