This commit is contained in:
debu-2 2026-10-14 06:32:25 +05:30
parent a109df2deb
commit 8901d99dd2
11 changed files with 380 additions and 13 deletions

View file

@ -1,7 +1,7 @@
import { Loader2 } from 'lucide-react'
import { useEffect, useState, type FormEvent } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import { whatsappApi, type WhatsAppAccount, type WhatsAppTemplateRow } from '../../lib/api'
import { waTemplateApi, whatsappApi, type WaManagedTemplate, type WhatsAppAccount, type WhatsAppTemplateRow } from '../../lib/api'
const TEAM_TEMPLATE_NAME = 'urmi_team_aircheck'
const TEAM_TEMPLATE_BODY = "Team, the broadcast desk is on air. This is the first note Urmi is sending through Meta's marketing line, and it is written for the people building it. Read it on your phone, then bring it to standup so we can close the test."
@ -23,7 +23,9 @@ export function WhatsAppBroadcastPage() {
const [accounts, setAccounts] = useState<WhatsAppAccount[]>([])
const [accountId, setAccountId] = useState('')
const [templates, setTemplates] = useState<WhatsAppTemplateRow[]>([])
const [managed, setManaged] = useState<WaManagedTemplate[]>([])
const [templatesReady, setTemplatesReady] = useState(false)
const [useSample, setUseSample] = useState(true)
const [templateName, setTemplateName] = useState(TEAM_TEMPLATE_NAME)
const [templateLanguage, setTemplateLanguage] = useState('en')
const [draftName, setDraftName] = useState(TEAM_TEMPLATE_NAME)
@ -72,6 +74,9 @@ export function WhatsAppBroadcastPage() {
setTemplates([])
setTemplatesReady(false)
})
waTemplateApi.list(accountId)
.then((payload) => setManaged(payload.templates))
.catch(() => setManaged([]))
}, [accountId, templateTick])
async function createTemplate(event: FormEvent) {
@ -103,6 +108,16 @@ export function WhatsAppBroadcastPage() {
setResult(null)
const numbers = recipients.split(/[\n,]/).map((item) => item.trim()).filter(Boolean)
const parameters = bodyValues.split('\n').map((item) => item.trim()).filter(Boolean)
if (mediaHeader && !savedSample) {
setError(`Add the sample ${headerLabel} on the template page. Meta rejects this send without it.`)
setBusy(false)
return
}
if (mediaHeader && !useSample) {
setError(`Turn on the saved sample ${headerLabel}. This template’s header is a ${headerLabel}, and Meta rejects the send without it.`)
setBusy(false)
return
}
try {
const payload = await whatsappApi.sendBroadcast(accountId, {
template_name: templateName.trim(),
@ -110,6 +125,7 @@ export function WhatsAppBroadcastPage() {
recipients: numbers,
body_parameters: parameters,
product_policy: strict ? 'STRICT' : 'CLOUD_API_FALLBACK',
use_sample_header: Boolean(mediaHeader && useSample && savedSample),
})
setResult(payload)
} catch (reason) {
@ -121,6 +137,11 @@ export function WhatsAppBroadcastPage() {
const approved = templates.filter((item) => (item.status || '').toUpperCase() === 'APPROVED' && item.name)
const pending = templates.filter((item) => (item.status || '').toUpperCase() !== 'APPROVED' && item.name)
const selectedTemplate = managed.find((item) => item.name === templateName && item.language === templateLanguage)
|| managed.find((item) => item.name === templateName)
const mediaHeader = ['IMAGE', 'VIDEO', 'DOCUMENT'].includes(selectedTemplate?.header_format || '')
const savedSample = Boolean(selectedTemplate?.sample_stored)
const headerLabel = selectedTemplate?.header_format === 'VIDEO' ? 'video' : selectedTemplate?.header_format === 'DOCUMENT' ? 'document' : 'image'
return (
<div className="wa-biz wa-token-page">
@ -198,6 +219,7 @@ export function WhatsAppBroadcastPage() {
const next = approved.find((item) => item.name === event.target.value)
setTemplateName(event.target.value)
if (next?.language) setTemplateLanguage(next.language)
setUseSample(true)
}}
>
{approved.map((item) => (
@ -220,6 +242,23 @@ export function WhatsAppBroadcastPage() {
<span>One WhatsApp number per line, up to 20. Include the country code.</span>
<textarea value={recipients} onChange={(event) => setRecipients(event.target.value)} rows={4} required placeholder="9198XXXXXXXX" />
</label>
{mediaHeader && (
<label className="explorer-input">
<strong>Header {headerLabel}</strong>
<span>
{savedSample
? `Use the ${headerLabel} saved on this template (${selectedTemplate?.sample_name || 'sample file'}). Meta does not keep the approval file, so each send has to attach it.`
: `This template needs a ${headerLabel} on every send, and none is saved yet.`}
</span>
{savedSample ? (
<input type="checkbox" checked={useSample} onChange={(event) => setUseSample(event.target.checked)} />
) : selectedTemplate ? (
<Link to={`/console/whatsapp/templates/${selectedTemplate.id}`}>Add the sample on the template</Link>
) : (
<span>Open the template and add the sample file first.</span>
)}
</label>
)}
<label className="explorer-input">
<strong>Body values</strong>
<span>Leave this empty for the team aircheck. If a template has {'{{1}}'}, {'{{2}}'}, put one value per line in that order.</span>