Preview:
  props,
  ref,
) => <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />);

export default function PhoneOTPVerification() {
  const [inputValue, setInputValue] = useState(['', '', '', '', '', '']);
  const [isVerified, setIsVerified] = useState(false);
  const [showInvalidOTPModal, setShowInvalidOTPModal] = useState(false);
  const [open, setOpen] = React.useState(false);
  const [errorMessage, setErrorMessage] = React.useState('');
  const [phoneNumber, setPhoneNumber] = useState('');
  const [snackbarSeverity, setSnackbarSeverity] = React.useState('success');
  const [snackbarOpen, setSnackbarOpen] = React.useState(false);
  const [snackbarMessage, setSnackbarMessage] = React.useState('');

  const navigate = useNavigate();

  const handleClose = (event?: React.SyntheticEvent | Event, reason?: string) => {
    if (reason === 'clickaway') {
      return;
    }

    setOpen(false);
  };

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>, index: number) => {
    // Only allow digit characters
    const value = e.target.value.replace(/\D/g, '');
    // Create a new array with the updated value
    const newValue = [...inputValue];
    newValue[index] = value;
    setInputValue(newValue);
  };

  const handleKeyDown = (e: { key: string; }) => {
    if (e.key === 'Backspace') {
      setInputValue(inputValue.slice(0, -1)); // Remove the last character from the input value
    }
  };
  const { userGuid } = useParams();
  const verifyPhoneNumber = async () => {
    // Join the inputValue array into a single string
    const userOtp = inputValue.join('');
    // Check if the length is 6 (since we have 6 input fields)
    if (userOtp.length === 6) {
      const response = await trackPromise(api.verifyOtp(userOtp, userGuid));
      if (response?.data?.Output?.phoneVerified) {
        setIsVerified(true);
        navigate(`/accounts/signup/identity-verification/${userGuid}`);
      } else {
        setOpen(true);
        setErrorMessage('Invalid OTP');
      }
    } else {
      setIsVerified(false);
    }
  };

  const resentOtp = async () => {
    const response = await trackPromise(api.resendOtp(userGuid));
    console.log('otp resend response:', response);
    // show success sbackbart nessga if otp resend successfully
    if (response?.data?.Output?.phoneNumber) {
      setPhoneNumber(response?.data?.Output?.phoneNumber);
      setSnackbarSeverity('success');
      setSnackbarMessage('OTP resend successfully');
      setSnackbarOpen(true);
    } else {
      setSnackbarSeverity('error');
      setSnackbarMessage('OTP resend failed. Try again.');
      setSnackbarOpen(true);
    }
  };

  // useEffect(() => {
  //   resentOtp();
  // }, []);

  return (
    <>
      <main className="otp-verify-container">
        <header className="header">
          <img src={Headericon} alt="Header Image" />
        </header>
        <section className="verification-section">
          <h1 className="verification-title">Phone Number Verification</h1>
          <article className="verification-content">
            <div className="verification-icon">
              <img src={SMSIcon} alt="SMS Icon" />
            </div>
            <div className="verification-subtitle">Enter 6 Digit OTP</div>
            <div className="verification-message">
              <span className="verification-message-text">
                We have sent an OTP on
                {' '}
                <span className="verification-message-phone">{phoneNumber}</span>
              </span>
              <button
                onClick={resentOtp}
                className="resend-link"
              >
                Resend OTP
              </button>
            </div>
            <div className="verification-input mb-5">
              {[...Array(6)].map((_, index) => (
                <input
                  key={index}
                  type="text"
                  maxLength={1}
                  className="otp-input"
                  value={inputValue[index] || ''}
                  onChange={(e) => handleChange(e, index)}
                />
              ))}
              <button type="button" onClick={verifyPhoneNumber}>
                Verify
              </button>
            </div>
          </article>
        </section>
        <InvalidOTPModal
          show={showInvalidOTPModal}
          handleClose={() => setShowInvalidOTPModal(false)}
        />

      </main>
      <Snackbar
        open={open}
        autoHideDuration={3000}
        onClose={handleClose}
        anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
      >
        <Alert onClose={handleClose} severity="error" sx={{ width: '100%', backgroundColor: '#C13254' }}>
          {/* Oops! Something went wrong. Please try again later. */}
          {errorMessage}
        </Alert>
      </Snackbar>

      {/* snacbar for otp resend */}
      <Snackbar
        open={snackbarOpen}
        autoHideDuration={3000}
        onClose={() => setSnackbarOpen(false)}
        anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
      >
        <MuiAlert
          onClose={() => setSnackbarOpen(false)}
          variant="filled"
          elevation={6}
          severity={snackbarSeverity as MuiAlertProps['severity']}
          sx={{ width: '100%' }}
        >
          {snackbarMessage}
        </MuiAlert>
      </Snackbar>

    </>
  );
}
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter