add input fields for age range
This commit is contained in:
parent
634f35657e
commit
cad4b78f47
@ -41,6 +41,7 @@ import Modal from "react-modal";
|
|||||||
import { type RouterInputs } from "~/utils/api";
|
import { type RouterInputs } from "~/utils/api";
|
||||||
import { PlatformLinkButton } from "~/pages/resources/[id]";
|
import { PlatformLinkButton } from "~/pages/resources/[id]";
|
||||||
import { ResourcePhoto } from "~/components/ResourcePhoto";
|
import { ResourcePhoto } from "~/components/ResourcePhoto";
|
||||||
|
import { FieldLabel } from "~/components/forms/inputLabel";
|
||||||
|
|
||||||
// Required for accessibility
|
// Required for accessibility
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
||||||
@ -379,6 +380,33 @@ function ResourceSummarySubForm({
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<FieldLabel
|
||||||
|
heading="Age Range"
|
||||||
|
subheading="Specify the minimum and maximum age range supported by the resource"
|
||||||
|
/>
|
||||||
|
<div className="mt-2 flex flex-row space-x-4">
|
||||||
|
<GenericInput
|
||||||
|
type="number"
|
||||||
|
placeholder="minimum age"
|
||||||
|
details={register("ages.min", {
|
||||||
|
required: "Field required",
|
||||||
|
valueAsNumber: true,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<span className="text-xl">-</span>
|
||||||
|
<GenericInput
|
||||||
|
type="number"
|
||||||
|
placeholder="maximum age"
|
||||||
|
details={register("ages.max", {
|
||||||
|
required: "Field required",
|
||||||
|
valueAsNumber: true,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<MultiSelectorMany
|
<MultiSelectorMany
|
||||||
details={register("payment_options", { required: "Field required" })}
|
details={register("payment_options", { required: "Field required" })}
|
||||||
label="Price Category"
|
label="Price Category"
|
||||||
|
16
src/components/forms/inputLabel.tsx
Normal file
16
src/components/forms/inputLabel.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export const FieldLabel = ({
|
||||||
|
heading,
|
||||||
|
subheading,
|
||||||
|
}: {
|
||||||
|
heading: string;
|
||||||
|
subheading: string;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<label className="text-md block font-semibold">{heading}</label>
|
||||||
|
<span className="block text-sm italic text-neutral-400">
|
||||||
|
{subheading}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -4,6 +4,7 @@ import {
|
|||||||
useFormContext,
|
useFormContext,
|
||||||
type UseFormRegisterReturn,
|
type UseFormRegisterReturn,
|
||||||
} from "react-hook-form";
|
} from "react-hook-form";
|
||||||
|
import { FieldLabel } from "./inputLabel";
|
||||||
|
|
||||||
// generics
|
// generics
|
||||||
interface ToStringable {
|
interface ToStringable {
|
||||||
@ -60,10 +61,7 @@ function MultiSelectorMany<T extends ToStringable>({
|
|||||||
<SelectorContext.Provider value={{ type: "many", updateCallback }}>
|
<SelectorContext.Provider value={{ type: "many", updateCallback }}>
|
||||||
<SelectedManyContext.Provider value={selected}>
|
<SelectedManyContext.Provider value={selected}>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="text-md block font-semibold">{label}</label>
|
<FieldLabel heading={label} subheading="Select all that apply" />
|
||||||
<span className="block text-sm italic text-neutral-400">
|
|
||||||
Select all that apply
|
|
||||||
</span>
|
|
||||||
<input {...details} readOnly type="text" className="hidden" />
|
<input {...details} readOnly type="text" className="hidden" />
|
||||||
<div className="mt-2 space-x-2 space-y-2 overflow-x-auto">
|
<div className="mt-2 space-x-2 space-y-2 overflow-x-auto">
|
||||||
{children}
|
{children}
|
||||||
@ -100,10 +98,7 @@ function MultiSelector<T extends ToStringable>({
|
|||||||
>
|
>
|
||||||
<SelectedUniqueContext.Provider value={selected}>
|
<SelectedUniqueContext.Provider value={selected}>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<label className="text-md block font-semibold">{label}</label>
|
<FieldLabel heading={label} subheading="Select one from below" />
|
||||||
<span className="block text-sm italic text-neutral-400">
|
|
||||||
Select one from below
|
|
||||||
</span>
|
|
||||||
<input {...details} readOnly type="text" className="hidden" />
|
<input {...details} readOnly type="text" className="hidden" />
|
||||||
<div className="space-x-2 space-y-2 overflow-x-auto">{children}</div>
|
<div className="space-x-2 space-y-2 overflow-x-auto">{children}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -50,16 +50,18 @@ function GenericInput<TFieldName extends InternalFieldName>({
|
|||||||
type = "text",
|
type = "text",
|
||||||
details,
|
details,
|
||||||
}: {
|
}: {
|
||||||
label: string;
|
label?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
type: HTMLInputTypeAttribute;
|
type: HTMLInputTypeAttribute;
|
||||||
details: UseFormRegisterReturn<TFieldName>;
|
details: UseFormRegisterReturn<TFieldName>;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<section className="w-full space-y-1">
|
<section className="w-full space-y-1">
|
||||||
<label className="text-md block px-1 font-semibold text-neutral-600">
|
{label ? (
|
||||||
{label}
|
<label className="text-md block px-1 font-semibold text-neutral-600">
|
||||||
</label>
|
{label}
|
||||||
|
</label>
|
||||||
|
) : undefined}
|
||||||
<input
|
<input
|
||||||
className="block h-8 w-full rounded-lg border border-neutral-600 px-2 py-1"
|
className="block h-8 w-full rounded-lg border border-neutral-600 px-2 py-1"
|
||||||
{...details}
|
{...details}
|
||||||
|
@ -25,7 +25,14 @@ const AuditoryResourceSchema = z.object({
|
|||||||
required: z.boolean().default(false),
|
required: z.boolean().default(false),
|
||||||
notice: z.string().nullable().transform(emptyStringToUndefined),
|
notice: z.string().nullable().transform(emptyStringToUndefined),
|
||||||
}),
|
}),
|
||||||
ages: z.object({ min: z.number().int(), max: z.number().int() }),
|
ages: z.object({ min: z.number().int(), max: z.number().int() }).refine(
|
||||||
|
(ages) => {
|
||||||
|
return ages.min < ages.max;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "Minimum supported age must be less than maximum supported age.",
|
||||||
|
}
|
||||||
|
),
|
||||||
skills: z.array(z.nativeEnum(Skill)),
|
skills: z.array(z.nativeEnum(Skill)),
|
||||||
skill_levels: z.array(z.nativeEnum(SkillLevel)),
|
skill_levels: z.array(z.nativeEnum(SkillLevel)),
|
||||||
payment_options: z.array(z.nativeEnum(PaymentType)),
|
payment_options: z.array(z.nativeEnum(PaymentType)),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user