Почему моя условная проверка не работает с использованием zod и формы реагирования?

Добрый день! У меня возникли небольшие проблемы после рефакторинга моего кода. Я создал условное поле, в котором, если пользователь выберет Yes, ниже появится дополнительное поле, в котором пользователь должен на него ответить. А если пользователь выбрал No, это будет просто пустая строка.

Проблема, с которой я сталкиваюсь сейчас, заключается в том, что выбранное Yes дополнительное поле не установлено как обязательное.

Шаги.ts

const steps = [
  {
    id: 'Step 1',
    name: 'General Information',
    fields: ['title', 'email', 'fullname', 'contact_person', 'department']
  },
  {
    id: 'Step 2',
    name: 'Date, Time and Purpose',
    fields: ['event_date, start_time', 'end_time', 'purpose']
  },
  {
    id: "Step 3",
    name: "Dry Run",
    fields: ['does_have_dry_run', 'dry_run_date', 'dry_run_start_time', 'dry_run_end_time', 'does_have_assistance', 'name_of_assistance']
  },
  {
    id: "Step 4",
    name: "Type of Service",
    fields: ['meeting_type_option', 'meeting_type_service', 'meeting_type_link']
  },
  {
    id: "Steps 5",
    name: "Type of Service",

  }
]

Форма.tsx


const CreateScheduleDialog = ({ open, setOpen, pickedDate }: Props) => {

  const [optionalDate, setOptionalDate] = useState<Date | undefined>(
    new Date()
  );
  const [step, setStep] = useState(0);
  const currentStep = steps[step];


  const form = useForm<CreateAppointmentSchemaType>({
    resolver: zodResolver(CreateAppointmentSchema),
    defaultValues: {
      does_have_dry_run: false,
      dry_run_date: new Date(),
      dry_run_start_time: '',
      dry_run_end_time: '',
   
    }
  })

  type FieldName = keyof CreateAppointmentSchemaType;


  const nextStep = async () => {
    const fields = steps[step].fields as FieldName[];
    const isValid = await form.trigger(fields, { shouldFocus: true });

    if (!isValid) return;

    setStep((prevStep) => prevStep + 1);
  };

  const prevStep = () => {
    if (step > 0) {
      setStep(step - 1);
    }
  };

  const handleClick = () => {
    form.resetField("dry_run_date");
    form.resetField("dry_run_start_time");
    form.resetField("dry_run_end_time");
  };

  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button disabled = {open !== false ? false : true} className='w-full' color = "primary-foreground">Add Schedule</Button>
      </DialogTrigger>
      <DialogContent className = {cn(`max-w-[400px] md:max-w-[800px]`)}>
        <DialogHeader>
          <DialogTitle>{currentStep.name}</DialogTitle>
          <DialogDescription>
            Step {step + 1} of {steps.length}
          </DialogDescription>
        </DialogHeader>
        <Form {...form}>
        
          {step == 2 && (
            <div className='flex flex-col gap-y-2'>
              <FormField
                control = {form.control}
                name = "does_have_dry_run"
                render = {({ field }) => (
                  <FormItem className = "space-y-3">
                    <FormLabel>
                      (Optional) Preferred Meeting Date / Dry Run
                    </FormLabel>
                    <FormControl>
                      <RadioGroup
                        onValueChange = {(value) =>
                          field.onChange(value === "true")
                        }
                        defaultValue = {String(field.value)}
                        className = "flex flex-col space-y-1"
                      >
                        <FormItem className = "flex items-center space-x-3 space-y-0">
                          <FormControl>
                            <RadioGroupItem
                              onClick = {handleClick}

                              value = "false" />
                          </FormControl>
                          <FormLabel className = "font-normal">
                            None / No
                          </FormLabel>
                        </FormItem>
                        <FormItem className = "flex items-center space-x-3 space-y-0">
                          <FormControl>
                            <RadioGroupItem value = "true" />
                          </FormControl>
                          <FormLabel className = "font-normal">
                            Yes
                          </FormLabel>
                        </FormItem>
                      </RadioGroup>
                    </FormControl>

                    {field.value === true && (
                      <FormItem>
                        <div className = "flex flex-col gap-2 pt-2">
                          <Label>(Dry Run) Time of Event</Label>
                          <div className = "flex flex-col gap-2">
                            <FormField
                              control = {form.control}
                              name = "dry_run_date"
                              render = {({ field }) => (
                                <FormItem className = "flex flex-col">
                                  <FormLabel>Date</FormLabel>
                                  <Popover>
                                    <PopoverTrigger asChild>
                                      <FormControl>
                                        <Button
                                          variant = {"outline"}
                                          className = {cn(
                                            "w-[240px] pl-3 text-left font-normal",
                                            !field.value &&
                                            "text-muted-foreground"
                                          )}
                                        >
                                          {field.value ? (
                                            format(field.value, "PPP")
                                          ) : (
                                            <span>Pick a date</span>
                                          )}
                                          <CalendarIcon className = "ml-auto h-4 w-4 opacity-50" />
                                        </Button>
                                      </FormControl>
                                    </PopoverTrigger>
                                    <PopoverContent
                                      className = "w-auto p-0"
                                      align = "start"
                                    >
                                      <Calendar
                                        mode = "single"
                                        disabled = {(date) =>
                                          new Date(date) <= new Date()
                                        } // Disable past dates and today's date
                                        selected = {optionalDate}
                                        onSelect = {field.onChange}
                                        initialFocus
                                      />
                                    </PopoverContent>
                                  </Popover>
                                  <FormMessage />
                                </FormItem>
                              )}
                            />
                            <FormField
                              control = {form.control}
                              name = "dry_run_start_time"
                              render = {({ field }) => (
                                <FormItem>
                                  <FormLabel>Start</FormLabel>
                                  <FormControl>
                                    <Input type = "time" placeholder = "Start" {...field} />
                                  </FormControl>
                                  <FormMessage />
                                </FormItem>
                              )}
                            />
                            <FormField
                              control = {form.control}
                              name = "dry_run_end_time"
                              render = {({ field }) => (
                                <FormItem>
                                  <FormLabel>End</FormLabel>
                                  <FormControl>
                                    <Input type = "time" placeholder = "End" {...field} />
                                  </FormControl>
                                  <FormMessage />
                                </FormItem>
                              )}
                            />

                          </div>
                        </div>
                      </FormItem>
                    )}

                    <FormMessage />
                  </FormItem>
                )}
              />

          
            </div>
          )}
         
        </Form>
        <DialogFooter>
          <Button onClick = {prevStep} disabled = {step === 0}>Back</Button>
          {step === steps.length - 1 ? (
            <Button
              disabled = {!form.formState.isValid}>
              Submit
            </Button>
          ) : (
            <Button
              onClick = {nextStep}
            >
              Next
            </Button>
          )}
        </DialogFooter>
      </DialogContent>

    </Dialog>
  )
}

Теперь я создал зод, в котором использую .superRefine, чтобы добавить проверку, но он не работает должным образом.

зод.ц

import { z } from "zod";


export const CreateAppointmentSchema = z.object({

  // //SET 3
  does_have_dry_run: z.boolean({
    required_error: "Please select if yes or no"
  }),
  dry_run_date: z.coerce.date().optional(),
  dry_run_start_time: z.string().optional(),
  dry_run_end_time: z.string().optional(),

  })
  .superRefine(({
    does_have_dry_run,
    dry_run_date,
    dry_run_start_time,
    dry_run_end_time,

    }, ctx) => {
    if (does_have_dry_run === true) {
      if (!dry_run_date) {
        ctx.addIssue({
          code: 'custom',
          message: 'Please provide information in the missing field.',
          path: ['dry_run_date']
        })
      }
      if (!dry_run_start_time) {
        ctx.addIssue({
          code: 'custom',
          message: 'Please provide information in the missing field.',
          path: ['dry_run_start_time']
        })
      }
      if (!dry_run_end_time) {
        ctx.addIssue({
          code: 'custom',
          message: 'Please provide information in the missing field.',
          path: ['dry_run_end_time']
        })
      }
    }

});

export type CreateAppointmentSchemaType = z.infer<typeof CreateAppointmentSchema>
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

если пользователь выберет «да» в раскрывающемся списке, следующие поля будут обязательными. Вы можете изменить свою схему zod таким образом, чтобы получить желаемые результаты.

const CreateAppointmentSchema = z
  .object({
    dryrun: z.string(),
    dry_run_start_time: z.string(),
    dry_run_end_time: z.string(),
  })
  .partial()
  .superRefine((v, ctx) => {
    if (v.dryrun == "no" || (v.dry_run_start_time && v.dry_run_end_time))
      return true;

    if (!v.dry_run_start_time) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: "dryrun start time is  required",
        path: ["dry_run_start_time"],
      });
    }
    if (!v.dry_run_end_time) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: "dryrun end time is  required",
        path: ["dry_run_end_time"],
      });
    }
  });

вот также рабочий пример решения: https://replit.com/@MubashirWaheed/zodValidation#app/page.tsx

Другие вопросы по теме