import { useState, useEffect } from 'react' import { Save, Eye, Smartphone, Loader2, CheckCircle, ChevronDown, CircleHelp, X } from 'lucide-react' import api from '../services/api' import { useToast } from '../components/ToastProvider' const DEFAULT_TEMPLATE = `{greeting} Your {sender_name} verification code is: *{otp}* This code expires in {expiry_seconds} seconds. Do not share it.` function renderTemplate(template, values) { return String(template || DEFAULT_TEMPLATE) .replaceAll('{greeting}', String(values.greeting || '')) .replaceAll('{sender_name}', String(values.sender_name || '')) .replaceAll('{otp}', String(values.otp || '')) .replaceAll('{expiry_seconds}', String(values.expiry_seconds || '')) } function formatDisplayPhone(phone) { const digits = String(phone || '').replace(/\D/g, '') if (!digits) return 'Not available' if (digits.length <= 4) return `+${digits}` if (digits.length <= 10) return `+${digits}` const countryCode = digits.slice(0, digits.length - 10) const local = digits.slice(-10) return `+${countryCode} ${local.slice(0, 5)} ${local.slice(5)}` } export default function MessageConfig() { const toast = useToast() const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [saved, setSaved] = useState(false) const [error, setError] = useState('') const [registeredPhone, setRegisteredPhone] = useState('') const [testingWebhook, setTestingWebhook] = useState(false) const [webhookNotice, setWebhookNotice] = useState('') const [messageTemplateLimit, setMessageTemplateLimit] = useState(320) const [sandboxMonthlyLimit, setSandboxMonthlyLimit] = useState(0) const [sandboxUsedThisMonth, setSandboxUsedThisMonth] = useState(0) const [liveMonthlyLimit, setLiveMonthlyLimit] = useState(0) const [liveUsedThisMonth, setLiveUsedThisMonth] = useState(0) const [openSections, setOpenSections] = useState({ environment: true, sender: true, webhook: false, }) const [showSandboxHelp, setShowSandboxHelp] = useState(false) const [settings, setSettings] = useState({ sender_name: 'Acme Corp', greeting: 'Hello!', message_template: DEFAULT_TEMPLATE, otp_length: '6', expiry_seconds: '60', environment_mode: 'sandbox', webhook_url: '', return_otp_in_response: 0 }) useEffect(() => { fetchSettings() }, []) const fetchSettings = async () => { try { const res = await api.get('/api/user/profile') setRegisteredPhone(res.data.user?.phone || '') setMessageTemplateLimit(res.data.limits?.message_template_max_chars || 320) setSandboxMonthlyLimit(res.data.limits?.sandbox_monthly_message_limit || 0) setSandboxUsedThisMonth(res.data.stats?.sandbox_used_this_month || 0) setLiveMonthlyLimit(res.data.limits?.live_monthly_message_limit || 0) setLiveUsedThisMonth(res.data.stats?.live_used_this_month || 0) if (res.data.settings) { setSettings({ ...res.data.settings, message_template: res.data.settings.message_template || DEFAULT_TEMPLATE, otp_length: String(res.data.settings.otp_length), expiry_seconds: String(res.data.settings.expiry_seconds), environment_mode: res.data.settings.environment_mode || 'sandbox' }) } } catch (err) { console.error("Failed to fetch settings", err) setError('Failed to load settings') } finally { setLoading(false) } } const handleSave = async () => { setSaving(true) setError('') setSaved(false) try { const res = await api.put('/api/user/settings', { ...settings, otp_length: Number(settings.otp_length), expiry_seconds: Number(settings.expiry_seconds) }) window.dispatchEvent(new CustomEvent('veriflo-settings-updated', { detail: { environment_mode: res.data.settings?.environment_mode || settings.environment_mode } })) setSaved(true) toast.success('Configuration saved') setTimeout(() => setSaved(false), 3000) } catch (err) { const message = err.response?.data?.error || 'Failed to save settings' setError(message) toast.error(message) } finally { setSaving(false) } } const handleChange = (field, value) => { setSettings(prev => ({ ...prev, [field]: value })) } const toggleSection = (section) => { setOpenSections((prev) => ({ ...prev, [section]: !prev[section] })) } const handleTestWebhook = async () => { setTestingWebhook(true) setError('') setWebhookNotice('') try { const res = await api.post('/api/user/test-webhook') setWebhookNotice(res.data.message || 'Test webhook sent successfully') toast.success(res.data.message || 'Test webhook sent successfully') } catch (err) { const message = err.response?.data?.error || 'Failed to send test webhook' setError(message) toast.error(message) } finally { setTestingWebhook(false) } } if (loading) return
Design your WhatsApp OTP template and configure delivery webhooks.
We will POST a JSON payload when delivery succeeds or fails.
{renderedMessage}
{/* Timestamp */}Registered Number: {formatDisplayPhone(registeredPhone)}
{settings.environment_mode === 'sandbox' ? 'Sandbox mode is locked to this number only. Any other recipient will be rejected by the backend.' : 'Live mode removes the sandbox restriction and allows delivery to other valid WhatsApp numbers.'}
{settings.environment_mode === 'live' ? <>Live monthly usage: {liveUsedThisMonth} / {liveMonthlyLimit}> : <>Sandbox monthly usage: {sandboxUsedThisMonth} / {sandboxMonthlyLimit}>}
Mode changes apply only after clicking Save Configuration.