+ {step === 0 && (
+ <>
+ Select WhatsApp number
+ The template is created on the WhatsApp Business account that owns this number. Other numbers on the same account can use it after Meta approves it.
+
+ {numbers.map(({ account, phone }) => {
+ const phoneId = phone?.phone_number_id || ''
+ const checked = draft.account_id === account.id && draft.phone_number_id === phoneId
+ return (
+
+ )
+ })}
+
+ {numbers.length === 0 && Connect a WhatsApp number first. Open WhatsApp
}
+ {sharedCount > 1 && This account has {sharedCount} numbers. The template is shared across them.
}
+ >
+ )}
+ {step === 1 && (
+ <>
+ Template details
+
+
+ Selected account: {selected ? `${selected.phone?.verified_name || selected.account.name} · ${selected.phone?.display_phone || selected.account.name}` : 'None selected'}
+ >
+ )}
+ {step === 2 && (
+ <>
+ Choose template category
+
+ {CATEGORIES.map((item) => {
+ const Icon = item.id === 'MARKETING' ? Megaphone : item.id === 'UTILITY' ? Bell : KeyRound
+ return (
+
+ )
+ })}
+
+ {category && (
+
+ )}
+ >
+ )}
+ {step === 3 && draft.category === 'AUTHENTICATION' && (
+ <>
+ One-time passcode
+ Meta writes the code message. You choose the security line, expiry, and copy button.
+
+
+
+ >
+ )}
+ {step === 3 && draft.category !== 'AUTHENTICATION' && (
+ <>
+ Design your message
+
+
+ {draft.header.type === 'TEXT' && (
+
+ )}
+ {['IMAGE', 'VIDEO', 'DOCUMENT'].includes(draft.header.type) && (
+
+ )}
+
+ {variableNames(draft.body).length > 0 && (
+
+ {variableNames(draft.body).map((name, index) => (
+
+ ))}
+
+ )}
+ {draft.header.type === 'TEXT' && variableNames(draft.header.text).length > 0 && (
+
+ {variableNames(draft.header.text).map((name, index) => (
+
+ ))}
+
+ )}
+
+ >
+ )}
+ {step === 4 && (
+ <>
+ Add message actions
+ {draft.category === 'AUTHENTICATION' ? The copy-code button from the previous step is the only action for this authentication template.
: (
+ <>
+ {draft.buttons.map((button, index) => (
+
+ Button {index + 1}
+
+ {button.type !== 'COPY_CODE' && {
+ const buttons = [...draft.buttons]
+ buttons[index] = { ...button, text: event.target.value }
+ patch({ buttons })
+ }} />}
+ {button.type === 'URL' && {
+ const buttons = [...draft.buttons]
+ buttons[index] = { ...button, url: event.target.value }
+ patch({ buttons })
+ }} />}
+ {button.type === 'URL' && variableNames(button.url).length > 0 && {
+ const buttons = [...draft.buttons]
+ buttons[index] = { ...button, example: event.target.value }
+ patch({ buttons })
+ }} />}
+ {button.type === 'PHONE_NUMBER' && {
+ const buttons = [...draft.buttons]
+ buttons[index] = { ...button, phone: event.target.value }
+ patch({ buttons })
+ }} />}
+ {button.type === 'COPY_CODE' && {
+ const buttons = [...draft.buttons]
+ buttons[index] = { ...button, example: event.target.value }
+ patch({ buttons })
+ }} />}
+ {button.type === 'FLOW' && {
+ const buttons = [...draft.buttons]
+ buttons[index] = { ...button, flow_id: event.target.value }
+ patch({ buttons })
+ }} />}
+
+
+
+
+
+
+ ))}
+
+ >
+ )}
+ >
+ )}
+ {step === 5 && (
+ <>
+ Review your template
+
+ - Template name
- {draft.name}
+ - WhatsApp account
- {selected?.account.name || '—'}
+ - Phone number
- {selected?.phone?.display_phone || '—'}
+ - Category
- {draft.category.toLowerCase()}
+ - Type
- {draft.subtype.replaceAll('_', ' ')}
+ - Language
- {draft.language}
+ - Header
- {draft.category === 'AUTHENTICATION' ? 'None' : draft.header.type.toLowerCase()}
+ - Body
- {draft.category === 'AUTHENTICATION' ? 'Meta one-time code message' : draft.body}
+ - Footer
- {draft.footer || 'None'}
+ - Buttons
- {draft.category === 'AUTHENTICATION' ? draft.auth.copy_label : draft.buttons.map((button) => button.text || button.type).join(', ') || 'None'}
+
+
+ {[
+ [!nameError(draft.name), nameError(draft.name) || 'Template name valid', 1],
+ [Boolean(draft.category), draft.category ? 'Category selected' : 'Category missing', 2],
+ [Boolean(draft.language), draft.language ? 'Language selected' : 'Language missing', 1],
+ [!contentError(draft), contentError(draft) || 'Message content is ready', 3],
+ [!buttonError(draft), buttonError(draft) || 'Buttons are ready', 4],
+ ].map(([ok, label, target]) => (
+ -
+ {ok ? '✓ ' : ''}{label}
+ {!ok && }
+
+ ))}
+
+ Meta decides the final category and whether the template is approved.
+ >
+ )}
+ {step >= 2 && category && step < 5 && (
+
+
What this template is good for
+
{category.goodFor}
+
Supported options
+
{category.options}
+
+ )}
+
+
+ {step < 5 ? (
+
+ ) : (
+
+ )}
+
+ {stepError && step < 5 && {stepError}
}
+