0

I'm implementing a form with react-hook-form and useFieldArray where users can add multiple account sets (cash account + trade account + currency) and set one as default using a toggle switch. However, the Switch component from shadcn/ui isn't responding immediately when clicked. Only one account should be default at any time (radio button behavior). Currently, clicking the Switch doesn't change its visual state immediately.

this is the form:

export function CustodianForm() {
  const form = useForm<CustodianFormInput>({
    resolver: zodResolver(custodianFormSchema),
    defaultValues: initialData || defaultCustodianFormValues,
  });

  const {
    fields: cashFields,
    append: appendCash,
    remove: removeCash,
  } = useFieldArray({
    control: form.control,
    name: "accounts",
  });

  useEffect(() => {
    const accounts = form.getValues("accounts");
    if (accounts.length === 1 && !accounts[0].isdefault) {
      form.setValue("accounts.0.isdefault", true);
    }
  }, [cashFields.length, form]);

  const handleAppendAccount = () => {
    appendCash({
      cashAccountNumber: "",
      tradeAccountNumber: "",
      currency: "",
      isdefault: false,
    });
  };

  const handleSetDefault = (index: number) => {
    const currentAccounts = form.getValues("accounts");
    const updatedAccounts = currentAccounts.map((account, i) => ({
      ...account,
      isdefault: i === index,
    }));
    form.setValue("accounts", updatedAccounts);
  };

  const handleRemoveAccount = (index: number) => {
    const isRemovingDefault = form.getValues(`accounts.${index}.isdefault`);
    removeCash(index);

    if (isRemovingDefault && cashFields.length > 1) {
      setTimeout(() => {
        form.setValue("accounts.0.isdefault", true);
      }, 0);
    }
  };

  const onSubmit = (values: CustodianFormInput) => {
    console.log("Submitted values:", values);
    form.reset();
    onClose();
  };

  return (
    <Form {...form}>
      <form
        onSubmit={form.handleSubmit(onSubmit)}
        className="font-poppins space-y-[8px] max-h-[80vh] overflow-y-auto scrollbar-thin scrollbar-thumb-zinc-50 pr-4 scrollbar-track-transparent"
      >
        <div className="grid grid-cols-2 gap-6">
          <FormField
            control={form.control}
            name="custodianArabicName"
            render={({ field }) => (
              <FormItemWrapper>
                <FormLabel>Custodian Arabic Name</FormLabel>
                <FormControl>
                  <Input
                    placeholder="سوق"
                    {...field}
                    className="bg-zinc-50 text-right"
                    dir="rtl"
                  />
                </FormControl>
              </FormItemWrapper>
            )}
          />
          <FormField
            control={form.control}
            name="custodianEnglishName"
            render={({ field }) => (
              <FormItemWrapper>
                <FormLabel>Custodian English Name</FormLabel>
                <FormControl>
                  <Input
                    placeholder="Enter custodian name"
                    {...field}
                    className="bg-zinc-50"
                  />
                </FormControl>
              </FormItemWrapper>
            )}
          />
        </div>
        {cashFields.length > 1 && (
          <div className="font-bold font-medium pb-[5px]">
            Custodian Accounts
          </div>
        )}
        {cashFields.length > 1 && (
          <div className="col-span-3 flex items-center gap-6">
            <div className="w-[228px]">
              <FormLabel>Cash Account Number</FormLabel>
            </div>
            <div className="w-[228px]">
              <FormLabel>Trade Account Number</FormLabel>
            </div>
            <div className="w-[223px]">
              <FormLabel>Account Currency</FormLabel>
            </div>
            <div className="w-[82px] text-center">
              <FormLabel>Set Default</FormLabel>
            </div>
          </div>
        )}
        <div
          className={`col-span-3 ${cashFields.length > 1 ? "pb-[20px]" : ""}`}
        >
          {cashFields.map((field, index) => (
            <div key={field.id} className="flex gap-6 items-start">
              <FormField
                control={form.control}
                name={`accounts.${index}.cashAccountNumber`}
                render={({ field }) => (
                  <FormItemWrapper>
                    {cashFields.length === 1 && (
                      <FormLabel>Cash Account Number</FormLabel>
                    )}
                    <FormControl>
                      <Input
                        placeholder="Cash account number"
                        {...field}
                        className={`${
                          cashFields.length === 1 ? "w-[265px]" : "w-[225px]"
                        } bg-zinc-50`}
                      />
                    </FormControl>
                  </FormItemWrapper>
                )}
              />
              <FormField
                control={form.control}
                name={`accounts.${index}.tradeAccountNumber`}
                render={({ field }) => (
                  <FormItemWrapper>
                    {cashFields.length === 1 && (
                      <FormLabel>Trade Account Number</FormLabel>
                    )}
                    <FormControl>
                      <Input
                        placeholder="Trade account number"
                        {...field}
                        className={`${
                          cashFields.length === 1 ? "w-[265px]" : "w-[225px]"
                        } bg-zinc-50`}
                      />
                    </FormControl>
                  </FormItemWrapper>
                )}
              />
              <FormField
                control={form.control}
                name={`accounts.${index}.currency`}
                render={({ field }) => (
                  <FormItemWrapper>
                    {cashFields.length === 1 && (
                      <FormLabel>Account Currnency</FormLabel>
                    )}
                    <FormControl>
                      <Select
                        onValueChange={field.onChange}
                        defaultValue={field.value}
                      >
                        <SelectTrigger
                          className={`${
                            cashFields.length === 1 ? "w-[265px]" : "w-[225px]"
                          } bg-zinc-50`}
                        >
                          <SelectValue placeholder="Select currency" />
                        </SelectTrigger>
                        <SelectContent>
                          {currencies.map((currency) => (
                            <SelectItem
                              key={currency.code}
                              value={currency.code}
                            >
                              {currency.code}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    </FormControl>
                  </FormItemWrapper>
                )}
              />
              {cashFields.length === 1 && (
                <span
                  onClick={handleAppendAccount}
                  className="text-sm cursor-pointer text-indigo-950 hover:text-black pt-[27px]"
                >
                  + Add
                </span>
              )}
              {cashFields.length > 1 && (
                <div className="flex justify-center w-[82px] h-[36px] pt-[10px]">
                  <FormField
                    control={form.control}
                    name={`accounts.${index}.isdefault`}
                    render={({ field }) => (
                      <FormItemWrapper>
                        <FormControl>
                          <Switch
                            checked={field.value}
                            onCheckedChange={(checked) => {
                              field.onChange(checked);
                              if (checked) {
                                handleSetDefault(index);
                              }
                            }}
                            className="data-[state=checked]:bg-blue-500"
                          />
                        </FormControl>
                      </FormItemWrapper>
                    )}
                  />
                </div>
              )}
              {cashFields.length > 1 && (
                <span
                  onClick={() => handleRemoveAccount(index)}
                  className="text-sm cursor-pointer text-red-500 font-semibold hover:text-red-700 pt-[10px]"
                >
                  Remove
                </span>
              )}
            </div>
          ))}
          {cashFields.length > 1 && (
            <span
              onClick={handleAppendAccount}
              className="text-sm cursor-pointer text-indigo-950 hover:text-black"
            >
              + Add
            </span>
          )}
        </div>
        <div>
          <FormField
            control={form.control}
            name="company"
            render={({ field }) => (
              <FormItemWrapper>
                <FormLabel>Company Profile</FormLabel>
                <FormControl>
                  <Select
                    onValueChange={field.onChange}
                    defaultValue={field.value}
                  >
                    <SelectTrigger className="w-full max-w-[450px] bg-zinc-50">
                      <SelectValue placeholder="Select company" />
                    </SelectTrigger>

                    <SelectContent>
                      {companies.map((company) => (
                        <SelectItem key={company.value} value={company.value}>
                          {company.label}
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                </FormControl>
              </FormItemWrapper>
            )}
          />
        </div>
        <FileUploader />
        <div className="flex justify-end">
          <Button type="submit" className="bg-blue-500 hover:bg-blue-700">
            Save
          </Button>
        </div>
      </form>
    </Form>
  );
}

How can I make the Switch component respond immediately to clicks while maintaining the "only one default account" requirement?

1
  • Hi @J_Max, could you please upload a minimum reproducible example? I'd like to try reproducing this issue but the code you have currently provided is missing context. Thank you Commented May 23 at 21:23

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.