All files / src/componentsV2/Payment/components CardNumberField.tsx

96.29% Statements 26/27
77.27% Branches 17/22
100% Functions 8/8
100% Lines 26/26

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                149x                   149x   2x 13x     224x   224x 224x 102x       224x     224x   224x   224x 68x 68x   68x     68x   68x 4x 4x     68x     224x 68x     224x 38x     224x     68x                                            
import React, { useState } from "react";
import { useFormContext } from "react-hook-form";
import { formatCardNumber } from "@utils/index";
import { GiveInput, InputProps } from "@shared/GiveInputs/GiveInput";
import { InputAdornment } from "@mui/material";
import { getCardBrandIcon } from "@sections/Checkout/Payment/inputs/CardNumberInput";
import { isEmpty } from "lodash";
 
export const CARD_LENGTHS = {
  AMEX: 17,
  OTHERS: 19,
};
 
type ICardNumberFieldProps = InputProps & {
  handleCardNumberCheck?: (value: string) => void;
  onCardTypeChange?: (cardType: string) => void;
};
 
const CardNumberField = ({
  sx,
  handleCardNumberCheck = () => null,
  onCardTypeChange = () => null,
  ...rest
}: ICardNumberFieldProps) => {
  const { setValue, clearErrors, watch } = useFormContext();
 
  const inputVal = watch("payment.cardNumber");
  const derivedCard = React.useMemo(
    () => formatCardNumber(inputVal || ""),
    [inputVal],
  );
 
  const cardType = derivedCard?.cardType || "";
 
  const maxCardNumberLength =
    cardType && cardType === "AMEX" ? CARD_LENGTHS.AMEX : CARD_LENGTHS.OTHERS;
 
  const type = isEmpty(inputVal) ? "hide" : cardType?.toUpperCase() ?? "hide";
 
  const normalizeInput = (value: string) => {
    Iif (!value) return value;
    const card = formatCardNumber(value);
    const allowedLength =
      card?.cardType && card?.cardType === "AMEX"
        ? CARD_LENGTHS.AMEX
        : CARD_LENGTHS.OTHERS;
    const isApprovedLength = card?.formattedNumber?.length === allowedLength;
 
    if (isApprovedLength) {
      clearErrors("payment.cardNumber");
      handleCardNumberCheck(value);
    }
 
    return card.formattedNumber;
  };
 
  const handleChange = (value: string) => {
    setValue("payment.cardNumber", normalizeInput(value));
  };
 
  React.useEffect(() => {
    onCardTypeChange(cardType);
  }, [cardType]);
 
  return (
    <GiveInput
      {...rest}
      onChange={(event) => handleChange(event.target.value)}
      maxLength={maxCardNumberLength}
      sx={{
        letterSpacing: "2px",
        "& .MuiFormHelperText-root": {
          letterSpacing: "0px",
        },
        ...sx,
      }}
      InputProps={{
        endAdornment: (
          <InputAdornment position="start" sx={{ alignItems: "center" }}>
            {getCardBrandIcon(type)}
          </InputAdornment>
        ),
        inputMode: "numeric",
      }}
    />
  );
};
 
export default CardNumberField;