UNPKG

@benny_gebeya/gebeya-whatsapp-otp

Version:

React WhatsApp OTP verification component library with Supabase integration for phone number authentication

456 lines (441 loc) 31.3 kB
import { jsx, jsxs, Fragment } from 'react/jsx-runtime'; import React, { useState, useCallback, createContext, useContext } from 'react'; import { Phone, X, CheckCircle, ChevronDown } from 'lucide-react'; /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; var useWhatsAppOTP = function (config, callbacks) { var _a = useState("phone"), step = _a[0], setStep = _a[1]; var _b = useState(config.defaultCountry || "+251"), countryCode = _b[0], setCountryCode = _b[1]; var _c = useState(""), phoneNumber = _c[0], setPhoneNumber = _c[1]; var _d = useState(""), otpCode = _d[0], setOtpCode = _d[1]; var _e = useState(false), isLoading = _e[0], setIsLoading = _e[1]; var _f = useState(3), attemptsLeft = _f[0], setAttemptsLeft = _f[1]; var _g = useState(false), maxAttemptsReached = _g[0], setMaxAttemptsReached = _g[1]; var _h = useState(false), isSuspended = _h[0], setIsSuspended = _h[1]; var _j = useState(""), suspensionMessage = _j[0], setSuspensionMessage = _j[1]; var _k = useState(false), isModalOpen = _k[0], setIsModalOpen = _k[1]; var sendOTP = useCallback(function () { return __awaiter(void 0, void 0, void 0, function () { var fullNumber, response, data, error_1, errorMessage; var _a, _b, _c; return __generator(this, function (_d) { switch (_d.label) { case 0: if (!phoneNumber) return [2 /*return*/]; setIsLoading(true); fullNumber = countryCode + phoneNumber; _d.label = 1; case 1: _d.trys.push([1, 4, 5, 6]); return [4 /*yield*/, fetch("".concat(config.supabaseUrl, "/functions/v1/otp_whatsapp"), { method: "POST", headers: { Authorization: "Bearer ".concat(config.supabaseKey), "Content-Type": "application/json", apikey: config.supabaseKey, }, body: JSON.stringify({ action: "send_otp", phone_number: fullNumber, }), })]; case 2: response = _d.sent(); return [4 /*yield*/, response.json()]; case 3: data = _d.sent(); if (response.ok && data.success) { setStep("verify"); setAttemptsLeft(3); setMaxAttemptsReached(false); setIsSuspended(false); setSuspensionMessage(""); (_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onStepChange) === null || _a === void 0 ? void 0 : _a.call(callbacks, "verify"); } else { throw new Error(data.error || "Failed to send OTP"); } return [3 /*break*/, 6]; case 4: error_1 = _d.sent(); errorMessage = error_1 instanceof Error ? error_1.message : "Failed to send OTP"; if (errorMessage.includes("temporarily suspended")) { setIsSuspended(true); setSuspensionMessage(errorMessage); (_b = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onSuspension) === null || _b === void 0 ? void 0 : _b.call(callbacks, errorMessage); } (_c = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onError) === null || _c === void 0 ? void 0 : _c.call(callbacks, errorMessage); return [3 /*break*/, 6]; case 5: setIsLoading(false); return [7 /*endfinally*/]; case 6: return [2 /*return*/]; } }); }); }, [phoneNumber, countryCode, config, callbacks]); var verifyOTP = useCallback(function () { return __awaiter(void 0, void 0, void 0, function () { var fullNumber, response, data, errorMessage, match, remaining, error_2, errorMessage; var _a, _b, _c, _d, _e, _f; return __generator(this, function (_g) { switch (_g.label) { case 0: if (!otpCode) return [2 /*return*/]; setIsLoading(true); fullNumber = countryCode + phoneNumber; _g.label = 1; case 1: _g.trys.push([1, 4, 5, 6]); return [4 /*yield*/, fetch("".concat(config.supabaseUrl, "/functions/v1/otp_whatsapp"), { method: "POST", headers: { Authorization: "Bearer ".concat(config.supabaseKey), "Content-Type": "application/json", apikey: config.supabaseKey, }, body: JSON.stringify({ action: "verify_otp", phone_number: fullNumber, code: otpCode, }), })]; case 2: response = _g.sent(); return [4 /*yield*/, response.json()]; case 3: data = _g.sent(); if (response.ok && (data === null || data === void 0 ? void 0 : data.success)) { setStep("success"); (_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onStepChange) === null || _a === void 0 ? void 0 : _a.call(callbacks, "success"); (_b = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onSuccess) === null || _b === void 0 ? void 0 : _b.call(callbacks, fullNumber); } else { errorMessage = (data === null || data === void 0 ? void 0 : data.error) || "Invalid or expired OTP code"; if (errorMessage.includes("temporarily suspended")) { setIsSuspended(true); setSuspensionMessage(errorMessage); setMaxAttemptsReached(true); setAttemptsLeft(0); (_c = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onSuspension) === null || _c === void 0 ? void 0 : _c.call(callbacks, errorMessage); } else if (errorMessage.includes("Maximum attempts reached")) { setMaxAttemptsReached(true); setAttemptsLeft(0); setIsSuspended(true); setSuspensionMessage(errorMessage); (_d = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onSuspension) === null || _d === void 0 ? void 0 : _d.call(callbacks, errorMessage); } else if (errorMessage.includes("attempts remaining")) { match = errorMessage.match(/(\d+)\s+attempts?\s+remaining/); if (match) { remaining = parseInt(match[1]); setAttemptsLeft(remaining); } } (_e = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onError) === null || _e === void 0 ? void 0 : _e.call(callbacks, errorMessage); setOtpCode(""); } return [3 /*break*/, 6]; case 4: error_2 = _g.sent(); errorMessage = error_2 instanceof Error ? error_2.message : "Something went wrong"; (_f = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onError) === null || _f === void 0 ? void 0 : _f.call(callbacks, errorMessage); setOtpCode(""); return [3 /*break*/, 6]; case 5: setIsLoading(false); return [7 /*endfinally*/]; case 6: return [2 /*return*/]; } }); }); }, [otpCode, phoneNumber, countryCode, config, callbacks]); var resetFlow = useCallback(function () { var _a; setStep("phone"); setPhoneNumber(""); setOtpCode(""); setAttemptsLeft(3); setMaxAttemptsReached(false); setIsSuspended(false); setSuspensionMessage(""); (_a = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onStepChange) === null || _a === void 0 ? void 0 : _a.call(callbacks, "phone"); }, [callbacks]); var openModal = useCallback(function () { setIsModalOpen(true); }, []); var closeModal = useCallback(function () { setIsModalOpen(false); resetFlow(); }, [resetFlow]); return { // State step: step, countryCode: countryCode, phoneNumber: phoneNumber, otpCode: otpCode, isLoading: isLoading, attemptsLeft: attemptsLeft, maxAttemptsReached: maxAttemptsReached, isSuspended: isSuspended, suspensionMessage: suspensionMessage, isModalOpen: isModalOpen, // Actions setCountryCode: setCountryCode, setPhoneNumber: setPhoneNumber, setOtpCode: setOtpCode, sendOTP: sendOTP, verifyOTP: verifyOTP, resetFlow: resetFlow, openModal: openModal, closeModal: closeModal, }; }; var WhatsAppOTPContext = createContext(undefined); var WhatsAppOTPProvider = function (_a) { var children = _a.children, config = _a.config, callbacks = _a.callbacks; var otpState = useWhatsAppOTP(config, callbacks); return (jsx(WhatsAppOTPContext.Provider, { value: otpState, children: children })); }; var useWhatsAppOTPContext = function () { var context = useContext(WhatsAppOTPContext); if (context === undefined) { throw new Error("useWhatsAppOTPContext must be used within a WhatsAppOTPProvider"); } return context; }; var Button$1 = React.forwardRef(function (_a, ref) { var _b = _a.className, className = _b === void 0 ? "" : _b, _c = _a.variant, variant = _c === void 0 ? "default" : _c, _d = _a.size, size = _d === void 0 ? "default" : _d, props = __rest(_a, ["className", "variant", "size"]); var baseClasses = "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"; var variantClasses = { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", }; var sizeClasses = { default: "h-10 px-4 py-2", sm: "h-9 rounded-md px-3", lg: "h-11 rounded-md px-8", icon: "h-10 w-10", }; var classes = "".concat(baseClasses, " ").concat(variantClasses[variant], " ").concat(sizeClasses[size], " ").concat(className); return jsx("button", __assign({ className: classes, ref: ref }, props)); }); Button$1.displayName = "Button"; var VerifyWithWhatsAppButton = function (_a) { var children = _a.children, className = _a.className, _b = _a.variant, variant = _b === void 0 ? "default" : _b, _c = _a.size, size = _c === void 0 ? "default" : _c, disabled = _a.disabled; var openModal = useWhatsAppOTPContext().openModal; return (jsxs(Button$1, { onClick: openModal, variant: variant, size: size, className: className, disabled: disabled, children: [jsx(Phone, { className: "h-4 w-4 mr-2" }), children || "Verify with WhatsApp"] })); }; var Dialog = function (_a) { var open = _a.open, onOpenChange = _a.onOpenChange, children = _a.children; if (!open) return null; return (jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [jsx("div", { className: "fixed inset-0 bg-black/50", onClick: function () { return onOpenChange(false); } }), jsx("div", { className: "relative z-50", children: children })] })); }; var DialogContent = function (_a) { var _b = _a.className, className = _b === void 0 ? "" : _b, children = _a.children; return (jsx("div", { className: "bg-white dark:bg-gray-900 rounded-lg shadow-lg p-6 w-full max-w-md mx-4 ".concat(className), children: children })); }; var DialogHeader = function (_a) { var children = _a.children; return (jsx("div", { className: "mb-4", children: children })); }; var DialogTitle = function (_a) { var _b = _a.className, className = _b === void 0 ? "" : _b, children = _a.children; return jsx("h2", { className: "text-lg font-semibold ".concat(className), children: children }); }; var Button = React.forwardRef(function (_a, ref) { var _b = _a.className, className = _b === void 0 ? "" : _b, _c = _a.variant, variant = _c === void 0 ? "default" : _c, _d = _a.size, size = _d === void 0 ? "default" : _d, props = __rest(_a, ["className", "variant", "size"]); var baseClasses = "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"; var variantClasses = { default: "bg-primary text-primary-foreground hover:bg-primary/90 bg-gray-900 text-white hover:bg-gray-800", destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90 bg-red-600 text-white hover:bg-red-700", outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground border-gray-300 hover:bg-gray-50", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 bg-gray-100 text-gray-900 hover:bg-gray-200", ghost: "hover:bg-accent hover:text-accent-foreground hover:bg-gray-100", link: "text-primary underline-offset-4 hover:underline text-blue-600", }; var sizeClasses = { default: "h-10 px-4 py-2", sm: "h-9 rounded-md px-3", lg: "h-11 rounded-md px-8", icon: "h-10 w-10", }; var classes = "".concat(baseClasses, " ").concat(variantClasses[variant], " ").concat(sizeClasses[size], " ").concat(className); return jsx("button", __assign({ className: classes, ref: ref }, props)); }); Button.displayName = "Button"; var Input = React.forwardRef(function (_a, ref) { var _b = _a.className, className = _b === void 0 ? "" : _b, props = __rest(_a, ["className"]); var classes = "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 border-gray-300 focus:border-blue-500 focus:ring-blue-500 ".concat(className); return jsx("input", __assign({ className: classes, ref: ref }, props)); }); Input.displayName = "Input"; var Label = React.forwardRef(function (_a, ref) { var _b = _a.className, className = _b === void 0 ? "" : _b, props = __rest(_a, ["className"]); var classes = "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 ".concat(className); return jsx("label", __assign({ className: classes, ref: ref }, props)); }); Label.displayName = "Label"; var Select = function (_a) { var value = _a.value, onValueChange = _a.onValueChange, children = _a.children; var _b = useState(false), isOpen = _b[0], setIsOpen = _b[1]; return (jsx("div", { className: "relative", children: React.Children.map(children, function (child) { if (React.isValidElement(child)) { return React.cloneElement(child, { value: value, onValueChange: onValueChange, isOpen: isOpen, setIsOpen: setIsOpen, }); } return child; }) })); }; var SelectTrigger = function (_a) { var children = _a.children, isOpen = _a.isOpen, setIsOpen = _a.setIsOpen; return (jsxs("button", { type: "button", className: "flex h-10 w-full items-center justify-between rounded-md border border-gray-300 bg-white px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", onClick: function () { return setIsOpen === null || setIsOpen === void 0 ? void 0 : setIsOpen(!isOpen); }, children: [children, jsx(ChevronDown, { className: "h-4 w-4 opacity-50" })] })); }; var SelectValue = function (_a) { var value = _a.value; var selectedCountry = defaultCountries.find(function (country) { return country.code === value; }); return (jsx("span", { className: "flex items-center gap-2", children: selectedCountry ? (jsxs(Fragment, { children: [jsx("span", { children: selectedCountry.flag }), jsxs("span", { children: [selectedCountry.country, " (", selectedCountry.code, ")"] })] })) : (jsx("span", { className: "text-muted-foreground", children: "Select country..." })) })); }; var SelectContent = function (_a) { var children = _a.children, value = _a.value, onValueChange = _a.onValueChange, isOpen = _a.isOpen, setIsOpen = _a.setIsOpen; if (!isOpen) return null; return (jsx("div", { className: "absolute top-full left-0 right-0 z-50 mt-1 max-h-60 overflow-auto rounded-md border border-gray-300 bg-white shadow-lg", children: React.Children.map(children, function (child) { if (React.isValidElement(child)) { return React.cloneElement(child, { value: value, onValueChange: onValueChange, setIsOpen: setIsOpen, }); } return child; }) })); }; var SelectItem = function (_a) { var itemValue = _a.value, children = _a.children, onValueChange = _a.onValueChange, setIsOpen = _a.setIsOpen; return (jsx("div", { className: "relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-gray-100 focus:bg-gray-100", onClick: function () { onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(itemValue); setIsOpen === null || setIsOpen === void 0 ? void 0 : setIsOpen(false); }, children: children })); }; // Default countries list var defaultCountries = [ { code: "+251", country: "Ethiopia", flag: "🇪🇹" }, { code: "+254", country: "Kenya", flag: "🇰🇪" }, { code: "+256", country: "Uganda", flag: "🇺🇬" }, { code: "+255", country: "Tanzania", flag: "🇹🇿" }, { code: "+250", country: "Rwanda", flag: "🇷🇼" }, { code: "+257", country: "Burundi", flag: "🇧🇮" }, { code: "+252", country: "Somalia", flag: "🇸🇴" }, { code: "+253", country: "Djibouti", flag: "🇩🇯" }, { code: "+211", country: "South Sudan", flag: "🇸🇸" }, ]; var WhatsAppOTPModal = function (_a) { var _b = _a.countries, countries = _b === void 0 ? defaultCountries : _b; var _c = useWhatsAppOTPContext(), isModalOpen = _c.isModalOpen, closeModal = _c.closeModal, step = _c.step, countryCode = _c.countryCode, phoneNumber = _c.phoneNumber, otpCode = _c.otpCode, isLoading = _c.isLoading, attemptsLeft = _c.attemptsLeft, maxAttemptsReached = _c.maxAttemptsReached, isSuspended = _c.isSuspended, suspensionMessage = _c.suspensionMessage, setCountryCode = _c.setCountryCode, setPhoneNumber = _c.setPhoneNumber, setOtpCode = _c.setOtpCode, sendOTP = _c.sendOTP, verifyOTP = _c.verifyOTP, resetFlow = _c.resetFlow; var handleBackToPhone = function () { resetFlow(); }; return (jsx(Dialog, { open: isModalOpen, onOpenChange: closeModal, children: jsxs(DialogContent, { className: "sm:max-w-md", children: [jsx(DialogHeader, { children: jsxs(DialogTitle, { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Phone, { className: "h-5 w-5 text-green-600" }), step === "phone" && "WhatsApp OTP", step === "verify" && "Enter Verification Code", step === "success" && "Phone Verified!"] }), jsx(Button, { variant: "ghost", size: "icon", onClick: closeModal, children: jsx(X, { className: "h-4 w-4" }) })] }) }), jsxs("div", { className: "space-y-4", children: [step === "phone" && (jsxs(Fragment, { children: [jsx("p", { className: "text-sm text-muted-foreground", children: "Enter your phone number to receive a verification code via WhatsApp" }), jsxs("div", { className: "space-y-2", children: [jsx(Label, { htmlFor: "country", children: "Country" }), jsxs(Select, { value: countryCode, onValueChange: setCountryCode, children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsx(SelectContent, { children: countries.map(function (country) { return (jsx(SelectItem, { value: country.code, children: jsxs("span", { className: "flex items-center gap-2", children: [jsx("span", { children: country.flag }), jsxs("span", { children: [country.country, " (", country.code, ")"] })] }) }, country.code)); }) })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label, { htmlFor: "phone", children: "Phone Number" }), jsxs("div", { className: "flex gap-2", children: [jsx("div", { className: "flex items-center px-3 py-2 border rounded-md bg-muted text-muted-foreground", children: countryCode }), jsx(Input, { id: "phone", type: "tel", placeholder: "985101186", value: phoneNumber, onChange: function (e) { return setPhoneNumber(e.target.value.replace(/\D/g, "")); }, className: "flex-1" })] })] }), jsx(Button, { onClick: sendOTP, className: "w-full", disabled: !phoneNumber || isLoading || isSuspended, children: isLoading ? "Sending..." : isSuspended ? "Phone Suspended" : "Send OTP via WhatsApp" })] })), step === "verify" && (jsxs(Fragment, { children: [jsx("p", { className: "text-sm text-muted-foreground", children: "Enter the 6-digit code sent to your WhatsApp" }), jsxs("div", { className: "space-y-2", children: [jsx(Label, { htmlFor: "otp", children: "Verification Code" }), jsx(Input, { id: "otp", type: "text", placeholder: "123456", value: otpCode, onChange: function (e) { return setOtpCode(e.target.value.replace(/\D/g, "").slice(0, 6)); }, maxLength: 6, className: "text-center text-lg tracking-widest", disabled: maxAttemptsReached || isSuspended })] }), jsx("div", { className: "text-center", children: isSuspended ? (jsxs("div", { className: "p-3 bg-destructive/10 border border-destructive/20 rounded-md", children: [jsx("p", { className: "text-destructive font-medium mb-1", children: "Phone Number Suspended" }), jsx("p", { className: "text-sm text-muted-foreground", children: suspensionMessage })] })) : maxAttemptsReached ? (jsxs("div", { className: "p-3 bg-destructive/10 border border-destructive/20 rounded-md", children: [jsx("p", { className: "text-destructive font-medium", children: "Maximum attempts reached" }), jsx("p", { className: "text-sm text-muted-foreground", children: "Please request a new OTP code" })] })) : (jsx("div", { className: "p-2 rounded-md ".concat(attemptsLeft === 1 ? "bg-destructive/10 border border-destructive/20" : attemptsLeft === 2 ? "bg-yellow-50 border border-yellow-200 dark:bg-yellow-900/20 dark:border-yellow-800" : "bg-muted/50"), children: jsxs("p", { className: "text-sm font-medium ".concat(attemptsLeft === 1 ? "text-destructive" : attemptsLeft === 2 ? "text-yellow-700 dark:text-yellow-300" : "text-muted-foreground"), children: [attemptsLeft, " ", attemptsLeft === 1 ? "attempt" : "attempts", " remaining"] }) })) }), jsxs("div", { className: "flex gap-2", children: [jsx(Button, { variant: "outline", onClick: handleBackToPhone, className: "flex-1", children: isSuspended || maxAttemptsReached ? "Get New Code" : "Back" }), jsx(Button, { onClick: verifyOTP, className: "flex-1", disabled: otpCode.length !== 6 || isLoading || maxAttemptsReached || isSuspended, children: isLoading ? "Verifying..." : "Verify Code" })] })] })), step === "success" && (jsxs("div", { className: "text-center space-y-4", children: [jsx(CheckCircle, { className: "h-16 w-16 text-green-600 mx-auto" }), jsx("p", { className: "text-lg font-semibold", children: "Phone number verified!" }), jsxs("p", { className: "text-muted-foreground", children: [countryCode, phoneNumber, " has been successfully verified"] }), jsxs("div", { className: "flex gap-2", children: [jsx(Button, { variant: "outline", onClick: closeModal, className: "flex-1", children: "Close" }), jsx(Button, { onClick: handleBackToPhone, className: "flex-1", children: "Verify Another" })] })] }))] })] }) })); }; export { VerifyWithWhatsAppButton, WhatsAppOTPModal, WhatsAppOTPProvider, useWhatsAppOTP }; //# sourceMappingURL=index.esm.js.map