🔐 OtpInput
The OtpInput
component handles OTP verification after phone login.
It uses the OtpInput
UI from @zezosoft/zezo-ott-react-ui-kit
and verifies the OTP with the verifyOtp
API.
✨ Features
- Verifies 4-digit OTP from the user
- Validates OTP format before submitting
- Pulls
phone
andhash
from the query string - Uses React Query for API mutation
- Shows success/error toasts
- Automatically redirects to
/
on success - Includes back navigation button
- Auto-fails gracefully if query params are missing
🔌 Props
Prop | Type | Description | Optional | Default |
---|---|---|---|---|
countryCode | string | Country dialing code (e.g. +91 ) | No | — |
phoneNumber | string | Phone number to show on the screen | No | — |
onSubmit | (otp: string) => void | Callback to submit the OTP | Yes | — |
isLoading | boolean | Show loading spinner on submit button | Yes | false |
goBack | () => void | Callback to handle back button | Yes | — |
error | string | Display error message below OTP field | Yes | — |
otpLength | number | OTP length to be accepted (e.g., 4 or 6) | Yes | 4 |
resetTime | number | Countdown time in seconds to re-request OTP | Yes | 120 |
title | string | Heading text to show above the input | Yes | ”Enter OTP” |
📦 Usage
"use client";
/* eslint-disable @typescript-eslint/no-explicit-any */
import { OtpInput as ZezoOtpInput } from "@zezosoft/zezo-ott-react-ui-kit";
import { useMutation } from "@tanstack/react-query";
import { useRouter, useSearchParams } from "next/navigation";
import React, { useEffect, useRef, useState } from "react";
import { zezoClient } from "@/lib/zezoClient";
const OtpInput: React.FC = () => {
const router = useRouter();
const searchParams = useSearchParams();
const phone = searchParams.get("phone");
const hash = searchParams.get("hash");
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | undefined>();
const hasSubmittedRef = useRef(false);
useEffect(() => {
if (!phone || !hash) {
router.push("/login");
}
}, [phone, hash, router]);
const verifyOtpMutation = useMutation({
mutationKey: ["verifyOtp"],
mutationFn: (payload: { phone: string; hash: string; otp: number }) =>
zezoClient().auth.verifyOTP(payload),
onSuccess: (data) => {
setIsLoading(false);
hasSubmittedRef.current = false;
if (data?.data === "success") {
router.push("/");
} else {
const errMsg = data?.data || "Failed to verify OTP";
setError(errMsg);
}
},
onError: (err: any) => {
setIsLoading(false);
hasSubmittedRef.current = false;
const errMsg = err?.message || "Something went wrong";
setError(errMsg);
},
});
const handleSubmit = (otp: string) => {
if (hasSubmittedRef.current) return;
if (otp.length !== 4 || isNaN(Number(otp))) {
const errMsg = "Please enter a valid OTP";
setError(errMsg);
return;
}
if (!phone || !hash) {
return;
}
setError(undefined);
setIsLoading(true);
hasSubmittedRef.current = true;
verifyOtpMutation.mutate({
phone,
hash,
otp: Number(otp),
});
};
return (
<ZezoOtpInput
title="Enter OTP"
countryCode="+91"
phoneNumber={phone || ""}
onSubmit={handleSubmit}
isLoading={isLoading || verifyOtpMutation.isPending}
error={error}
goBack={() => router.back()}
otpLength={4}
resetTime={120}
/>
);
};
export default OtpInput;
🖼️ UI Preview
Here’s how the verifyOtp
component looks in action:
Last updated on