All files / src/validation/hooks useTaxIdValidator.ts

38.46% Statements 10/26
18.75% Branches 3/16
66.66% Functions 2/3
43.47% Lines 10/23

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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102                                            70x         210x   210x             210x                                                                 210x   420x   420x             420x               420x         210x                
import { useState, useRef, useCallback } from "react";
import * as Yup from "yup";
 
import { DECLINED_SUSPENDED_BP_ERROR } from "@constants/constants";
import { createTaxIdValidator } from "@validation/fields";
import { checkTaxIDAvailability } from "@components/Merchants/CreateMerchantPanel/modals/utils";
import { TinType } from "@validation/types";
 
export interface UseTaxIdValidatorConfig {
  required: boolean;
  availabilityCheck: boolean;
  defaultTaxID?: string;
}
 
export interface UseTaxIdValidatorReturn {
  getTaxIDSchema: (type: "ssn" | "ein") => Yup.StringSchema;
  isDeclinedOrNotApproved: boolean;
  isLinked: boolean;
  id: number;
  isLoading: boolean;
}
 
export const useTaxIdValidator = ({
  required,
  availabilityCheck,
  defaultTaxID,
}: UseTaxIdValidatorConfig): UseTaxIdValidatorReturn => {
  const [isLoading, setIsLoading] = useState(false);
 
  const checkedTaxID = useRef({
    isDeclinedOrNotApproved: false,
    isLinked: false,
    taxId: "",
    id: 0,
  });
 
  const validateAvailability = useCallback(
    async (value: string | undefined): Promise<boolean> => {
      if (!value) return !required;
 
      const cleaned = value.replace(/(\s|-)/g, "");
 
      if (cleaned.length < 9) return true;
      if (cleaned === defaultTaxID) return true;
 
      if (checkedTaxID.current.taxId !== cleaned) {
        setIsLoading(true);
        try {
          const result = await checkTaxIDAvailability(cleaned);
          checkedTaxID.current = {
            ...result,
            id: result?.id ?? 0,
            taxId: cleaned,
          };
        } catch (err) {
          console.error("Tax ID availability check failed:", err);
        } finally {
          setIsLoading(false);
        }
      }
 
      // allow if linked; reject if declined/suspended
      return checkedTaxID.current.isLinked
        ? true
        : !checkedTaxID.current.isDeclinedOrNotApproved;
    },
    [required, defaultTaxID],
  );
 
  const getTaxIDSchema = useCallback(
    (type: TinType): Yup.StringSchema => {
      const label = type === "ssn" ? "SSN" : "Tax ID";
 
      let schema = createTaxIdValidator({
        required,
        type: type.toUpperCase() as "SSN" | "EIN",
        requiredMessage: `${label} is required`,
        invalidMessage: `Please enter a valid ${label}`,
      });
 
      Iif (availabilityCheck) {
        schema = schema.test(
          "link-tax-id",
          DECLINED_SUSPENDED_BP_ERROR,
          validateAvailability,
        );
      }
 
      return schema as Yup.StringSchema;
    },
    [required, availabilityCheck, validateAvailability],
  );
 
  return {
    getTaxIDSchema,
    isDeclinedOrNotApproved: checkedTaxID.current.isDeclinedOrNotApproved,
    isLinked: checkedTaxID.current.isLinked,
    id: checkedTaxID.current.id,
    isLoading,
  };
};