"use client";
import { useState, useEffect, useCallback } from "react";
import {
Mail,
Loader2,
Check,
RefreshCw,
AlertCircle,
ArrowLeft,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
InputOTP,
InputOTPGroup,
InputOTPSlot,
InputOTPSeparator,
} from "@/components/ui/input-otp";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { cn } from "@/lib/utils";
export const title = "React Dialog Block Email Verification";
export default function DialogEmailVerification() {
const [open, setOpen] = useState(false);
const [otp, setOtp] = useState("");
const [isVerifying, setIsVerifying] = useState(false);
const [isResending, setIsResending] = useState(false);
const [isVerified, setIsVerified] = useState(false);
const [error, setError] = useState<string | null>(null);
const [resendCooldown, setResendCooldown] = useState(0);
const email = "[email protected]";
// Countdown timer for resend
useEffect(() => {
if (resendCooldown > 0) {
const timer = setTimeout(() => {
setResendCooldown((prev) => prev - 1);
}, 1000);
return () => clearTimeout(timer);
}
}, [resendCooldown]);
const handleVerify = useCallback(async () => {
if (otp.length !== 6) return;
setIsVerifying(true);
setError(null);
await new Promise((resolve) => setTimeout(resolve, 1500));
// Simulate verification (in real app: verify with backend)
if (otp === "123456") {
setIsVerified(true);
} else {
setError("Invalid verification code. Please try again.");
setOtp("");
}
setIsVerifying(false);
}, [otp]);
// Auto-verify when 6 digits entered
useEffect(() => {
if (otp.length === 6 && !isVerifying && !isVerified) {
handleVerify();
}
}, [otp, isVerifying, isVerified, handleVerify]);
const handleResend = async () => {
setIsResending(true);
setError(null);
await new Promise((resolve) => setTimeout(resolve, 1000));
setIsResending(false);
setResendCooldown(60); // 60 second cooldown
setOtp("");
};
const handleClose = () => {
setOpen(false);
setTimeout(() => {
setOtp("");
setError(null);
setIsVerified(false);
setResendCooldown(0);
}, 200);
};
if (isVerified) {
return (
<Dialog open={open} onOpenChange={setOpen}>
<div className="flex min-h-[350px] items-center justify-center">
<DialogTrigger asChild>
<Button variant="outline">
<Mail className="mr-2 h-4 w-4" />
Verify Email
</Button>
</DialogTrigger>
</div>
<DialogContent className="sm:max-w-md">
<div className="flex flex-col items-center justify-center py-8 text-center">
<div className="flex h-12 w-12 items-center justify-center rounded-full border-2 border-primary">
<Check className="h-6 w-6 text-primary" />
</div>
<h3 className="mt-4 text-lg font-semibold">Email Verified</h3>
<p className="mt-1 text-sm text-muted-foreground">
Your email address has been successfully verified.
</p>
<p className="mt-2 text-xs text-muted-foreground">{email}</p>
<Button onClick={handleClose} className="mt-6">
Continue
</Button>
</div>
</DialogContent>
</Dialog>
);
}
return (
<Dialog open={open} onOpenChange={setOpen}>
<div className="flex min-h-[350px] items-center justify-center">
<DialogTrigger asChild>
<Button variant="outline">
<Mail className="mr-2 h-4 w-4" />
Verify Email
</Button>
</DialogTrigger>
</div>
<DialogContent className="sm:max-w-md">
<DialogHeader className="text-center">
<div className="flex justify-center mb-2">
<div className="flex h-12 w-12 items-center justify-center rounded-full border">
<Mail className="h-6 w-6" />
</div>
</div>
<DialogTitle>Check your email</DialogTitle>
<DialogDescription>
We sent a verification code to
</DialogDescription>
<p className="text-sm font-medium">{email}</p>
</DialogHeader>
<div className="space-y-6 py-4">
{/* Error Alert */}
{error && (
<Alert variant="destructive">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
{/* OTP Input */}
<div className="flex flex-col items-center space-y-4">
<InputOTP
maxLength={6}
value={otp}
onChange={setOtp}
disabled={isVerifying}
>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
<p className="text-xs text-muted-foreground">
Enter the 6-digit code from your email
</p>
</div>
{/* Verify Button */}
<Button
className="w-full"
onClick={handleVerify}
disabled={otp.length !== 6 || isVerifying}
>
{isVerifying ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Verifying...
</>
) : (
<>
<Check className="mr-2 h-4 w-4" />
Verify Email
</>
)}
</Button>
{/* Resend Section */}
<div className="text-center space-y-2">
<p className="text-sm text-muted-foreground">
Didn't receive the code?
</p>
{resendCooldown > 0 ? (
<p className="text-sm text-muted-foreground">
Resend available in{" "}
<span className="font-medium">{resendCooldown}s</span>
</p>
) : (
<Button
variant="link"
size="sm"
className="h-auto p-0"
onClick={handleResend}
disabled={isResending}
>
{isResending ? (
<>
<Loader2 className="mr-1 h-3 w-3 animate-spin" />
Sending...
</>
) : (
<>
<RefreshCw className="mr-1 h-3 w-3" />
Resend code
</>
)}
</Button>
)}
</div>
{/* Help Text */}
<div className="rounded-lg border p-3 text-center">
<p className="text-xs text-muted-foreground">
Check your spam folder if you don't see the email.
<br />
The code expires in 10 minutes.
</p>
</div>
</div>
<div className="flex items-center justify-between pt-2 border-t">
<Button variant="ghost" size="sm" onClick={handleClose}>
<ArrowLeft className="mr-1 h-4 w-4" />
Go back
</Button>
<Button variant="link" size="sm" className="text-xs">
Use different email
</Button>
</div>
</DialogContent>
</Dialog>
);
}