All files / react-app/src/components/RHF FieldArray.tsx

100% Statements 10/10
92.85% Branches 13/14
100% Functions 7/7
100% Lines 9/9

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79                  72x 22x           22x 2x     22x 22x 1x                                   1x                   1x                                                        
import { useEffect } from "react";
import { FieldValues, useFieldArray } from "react-hook-form";
import { FieldArrayProps } from "shared-types";
import { Plus, Trash2 } from "lucide-react";
import { Button } from "../Inputs";
import { slotInitializer } from "./utils";
import { Field } from "./Field";
import { cn } from "@/utils";
 
export const RHFFieldArray = <TFields extends FieldValues>(props: FieldArrayProps<TFields>) => {
  const fieldArr = useFieldArray<any>({
    control: props.control,
    name: props.name,
    shouldUnregister: true,
  });
 
  const onAppend = () => {
    fieldArr.append(props.fields.reduce(slotInitializer(), {}) as never);
  };
 
  useEffect(() => {
    if (fieldArr.fields.length) return;
    fieldArr.append(props.fields.reduce(slotInitializer(), {}) as never, {
      shouldFocus: false,
    });
  }, [fieldArr, props.fields]);
 
  return (
    <div className={"flex flex-col gap-6 w-full"}>
      {fieldArr.fields.map((FLD, index) => {
        return (
          <div className={cn("flex flex-row gap-6", props.fieldArrayClassName)} key={FLD.id}>
            {props.fields.map((SLOT, i) => {
              return <Field key={`${SLOT.name}-${i}`} {...props} index={index} SLOT={SLOT} />;
            })}
            {/* FieldArray Removal */}
            {index >= 1 && !props.removeText && (
              <Trash2
                className="self-end mb-2 cursor-pointer stroke-primary"
                data-testid={`removeRowButton-${index}`}
                onClick={() => fieldArr.remove(index)}
              />
            )}
            {/* FieldGroup Removal */}
            {index >= 1 && props.removeText && (
              <Button
                className="self-end m-2 mr-0"
                variant={"destructive"}
                data-testid={`removeGroupButton-${index}`}
                onClick={() => {
                  fieldArr.remove(index);
                }}
              >
                {props.removeText ?? "Remove Group"}
              </Button>
            )}
            {props.divider && <div className="w-full border-slate-300 border-b-[1px]" />}
          </div>
        );
      })}
      {props.lastDivider && (
        <div className={cn("w-full border-slate-300 border-b-[1px]", props.lastDivider)} />
      )}
      <div className={cn("flex items-center", props.appendClassName)}>
        <Button
          type="button"
          size="sm"
          onClick={onAppend}
          data-testid={`appendRowButton-${props.name}`}
          variant={props.appendVariant ?? "outline"}
        >
          <Plus className="h-5 w-5 mr-2" />
          {props.appendText || "New Row"}
        </Button>
      </div>
    </div>
  );
};