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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | 35x 35x 35x 35x 35x 35x 35x 35x 7x 7x 7x 7x 1x 1x 6x 1x 1x 5x 5x 1x 1x 4x 4x 2x 2x 1x 35x 6x 7x 1x | import { parseIndianPhone } from "@interioring/utils/validation/phone";
import { type FormEvent, useId, useState } from "react";
import { useCreateWhatsAppRecipient } from "../../../hooks/queries/useWhatsAppRecipientQueries";
import { ApiError } from "../../../lib/api";
import { Button } from "../../ui/button";
import { DrawerDialog } from "../../ui/drawer-dialog";
import { Input } from "../../ui/input";
interface Props {
proId: string;
onClose: () => void;
onCreated: (recipientId: number) => void;
}
export function AddRecipientDialog({ proId, onClose, onCreated }: Props) {
const [label, setLabel] = useState("");
const [number, setNumber] = useState("");
const [makePrimary, setMakePrimary] = useState(false);
const [error, setError] = useState<string | null>(null);
const labelId = useId();
const numberId = useId();
const createMut = useCreateWhatsAppRecipient(proId);
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
setError(null);
const trimmedLabel = label.trim();
if (!trimmedLabel) {
setError("Give this number a label (e.g., Owner, Sales).");
return;
}
if (trimmedLabel.length > 32) {
setError("Label must be 32 characters or fewer.");
return;
}
const parsed = parseIndianPhone(number);
if (!parsed || parsed.type !== "mobile") {
setError("Enter a valid 10-digit Indian mobile number.");
return;
}
try {
const r = await createMut.mutateAsync({
label: trimmedLabel,
number: parsed.e164,
isPrimary: makePrimary,
});
onCreated(r.id);
} catch (err) {
if (err instanceof ApiError) setError(err.message);
else setError("Could not add recipient.");
}
};
return (
<DrawerDialog
open
onClose={onClose}
title="Add WhatsApp recipient"
footer={
<div className="flex justify-end gap-2">
<Button variant="outline" onClick={onClose}>
Cancel
</Button>
<Button
type="submit"
form="add-recipient-form"
disabled={createMut.isPending}
>
{createMut.isPending ? "Sending OTP…" : "Send OTP"}
</Button>
</div>
}
>
<form id="add-recipient-form" onSubmit={handleSubmit} className="flex flex-col gap-4">
<div className="flex flex-col gap-1 text-sm">
<label htmlFor={labelId} className="font-medium text-foreground-default">
Label
</label>
<Input
id={labelId}
value={label}
onChange={(e) => setLabel(e.target.value)}
placeholder="Owner, Sales, Operations…"
maxLength={32}
autoFocus
/>
</div>
<div className="flex flex-col gap-1 text-sm">
<label htmlFor={numberId} className="font-medium text-foreground-default">
WhatsApp number
</label>
<div className="flex items-center gap-2">
<span className="text-sm text-foreground-muted">+91</span>
<Input
id={numberId}
type="tel"
inputMode="numeric"
pattern="[0-9]*"
maxLength={10}
value={number}
onChange={(e) =>
setNumber(e.target.value.replace(/\D/g, "").slice(0, 10))
}
placeholder="10-digit mobile"
/>
</div>
</div>
<label className="flex items-center gap-2 text-sm">
<input
type="checkbox"
checked={makePrimary}
onChange={(e) => setMakePrimary(e.target.checked)}
/>
<span>Make this the primary recipient</span>
</label>
{error && <p className="text-sm text-error" role="alert">{error}</p>}
<p className="text-xs text-foreground-muted">
We'll send a 6-digit code via WhatsApp. Enter it on the next screen
to verify.
</p>
</form>
</DrawerDialog>
);
}
|