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 103 104 105 106 107 108 109 110 111 112 113 114 | 20x 20x 20x 20x 20x 20x 10x 10x 10x 20x 19x 4x 4x 4x 1x 1x 3x 3x 1x 2x 1x 19x 19x 19x 4x | import { WHATSAPP_OTP_RESEND_COOLDOWN_SECONDS } from "@interioring/utils/constants/whatsapp";
import { type FormEvent, useEffect, useState } from "react";
import {
useResendWhatsAppRecipientOtp,
useVerifyWhatsAppRecipient,
} from "../../../hooks/queries/useWhatsAppRecipientQueries";
import { ApiError, type WhatsAppRecipient } from "../../../lib/api";
import { Button } from "../../ui/button";
import { DrawerDialog } from "../../ui/drawer-dialog";
import { Input } from "../../ui/input";
interface Props {
proId: string;
recipient?: WhatsAppRecipient;
onClose: () => void;
}
export function OtpVerifyDialog({ proId, recipient, onClose }: Props) {
const [code, setCode] = useState("");
const [error, setError] = useState<string | null>(null);
const [cooldown, setCooldown] = useState(WHATSAPP_OTP_RESEND_COOLDOWN_SECONDS);
const verifyMut = useVerifyWhatsAppRecipient(proId);
const resendMut = useResendWhatsAppRecipientOtp(proId);
useEffect(() => {
Iif (cooldown <= 0) return;
const t = setInterval(() => setCooldown((s) => Math.max(s - 1, 0)), 1000);
return () => clearInterval(t);
}, [cooldown]);
if (!recipient) return null;
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
setError(null);
if (!/^\d{4,8}$/.test(code)) {
setError("Enter the 6-digit code we sent on WhatsApp.");
return;
}
try {
await verifyMut.mutateAsync({ id: recipient.id, code });
onClose();
} catch (err) {
if (err instanceof ApiError) setError(err.message);
else setError("Could not verify the code.");
}
};
const handleResend = async () => {
setError(null);
try {
const result = await resendMut.mutateAsync(recipient.id);
setCooldown(result.cooldownSeconds);
} catch (err) {
if (err instanceof ApiError) setError(err.message);
else setError("Could not resend the code.");
}
};
const masked = recipient.number.replace(/(\+91)(\d{5})(\d{5})/, "$1 $2 $3");
return (
<DrawerDialog
open
onClose={onClose}
title="Verify WhatsApp recipient"
footer={
<div className="flex items-center justify-between gap-2">
<Button
variant="ghost"
size="sm"
disabled={cooldown > 0 || resendMut.isPending}
onClick={handleResend}
>
{cooldown > 0 ? `Resend in ${cooldown}s` : "Resend code"}
</Button>
<div className="flex gap-2">
<Button variant="outline" onClick={onClose}>
Cancel
</Button>
<Button
type="submit"
form="otp-verify-form"
disabled={verifyMut.isPending}
>
{verifyMut.isPending ? "Verifying…" : "Verify"}
</Button>
</div>
</div>
}
>
<form id="otp-verify-form" onSubmit={handleSubmit} className="flex flex-col gap-4">
<p className="text-sm text-foreground-muted">
Enter the 6-digit code we just sent to{" "}
<span className="font-medium text-foreground-default">{masked}</span>.
</p>
<Input
type="text"
inputMode="numeric"
pattern="[0-9]*"
maxLength={6}
value={code}
onChange={(e) =>
setCode(e.target.value.replace(/\D/g, "").slice(0, 6))
}
placeholder="123456"
autoFocus
/>
{error && <p className="text-sm text-error" role="alert">{error}</p>}
</form>
</DrawerDialog>
);
}
|