import { useState, useEffect, useCallback } from 'react';
import { useParams } from 'react-router-dom';
import apiClient from '../api/client';
import WhitelistModal from '../components/WhitelistModal';
import TestSmsModal from '../components/TestSmsModal';
const STATUS_CONFIG = {
generated: { label: 'Generated', bg: 'bg-page-bg', text: 'text-text-muted', border: 'border-border-main' },
pending_whitelisting: { label: 'Pending Whitelisting', bg: 'bg-tags-bg', text: 'text-tags-text', border: 'border-tags-border' },
whitelisted: { label: 'Published', bg: 'bg-badge-bg', text: 'text-badge-text', border: 'border-badge-border' },
};
export default function Templates() {
const { businessId } = useParams();
const [templates, setTemplates] = useState([]);
const [profilesById, setProfilesById] = useState({});
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
const [whitelistTarget, setWhitelistTarget] = useState(null);
const [testTarget, setTestTarget] = useState(null);
const [activeTab, setActiveTab] = useState('published'); // 'published' | 'pending'
const loadTemplates = useCallback(async () => {
setLoading(true);
setError('');
try {
const [templatesRes, profilesRes] = await Promise.all([
apiClient.get(`/api/businesses/${businessId}/templates`),
apiClient.get(`/api/businesses/${businessId}/global-sms/profiles`).catch(() => ({ data: { profiles: [] } })),
]);
const all = (templatesRes.data.templates || []).filter(t => t.selectedTemplate);
const profileMap = Object.fromEntries((profilesRes.data.profiles || []).map(profile => [profile.id, profile]));
setTemplates(all);
setProfilesById(profileMap);
} catch {
setError('Failed to load templates');
} finally {
setLoading(false);
}
}, [businessId]);
useEffect(() => {
loadTemplates();
}, [loadTemplates]);
async function handleWhitelistSuccess() {
setWhitelistTarget(null);
await loadTemplates();
}
if (loading) {
return (
);
}
return (
Templates
Track whitelisting status and test your SMS templates.
{error && (
{error}
setError('')} className="text-error-text hover:text-red-900 font-bold">×
)}
setActiveTab('published')}
className={`py-2 px-1 border-b-2 font-medium text-sm transition-colors ${
activeTab === 'published'
? 'border-primary-blue text-primary-dark'
: 'border-transparent text-text-muted hover:text-text-primary hover:border-border-main'
}`}
>
Published
setActiveTab('pending')}
className={`py-2 px-1 border-b-2 font-medium text-sm transition-colors ${
activeTab === 'pending'
? 'border-primary-blue text-primary-dark'
: 'border-transparent text-text-muted hover:text-text-primary hover:border-border-main'
}`}
>
Pending Whitelisting
{templates.length === 0 ? (
No Templates Yet
Generate and select templates in the Events section first.
) : (() => {
const publishedTabs = templates.filter(t => t.status === 'whitelisted');
const pendingTabs = templates.filter(t => t.status === 'pending_whitelisting');
const visibleTemplates = activeTab === 'published' ? publishedTabs : pendingTabs;
if (visibleTemplates.length === 0) {
return (
No templates in {activeTab === 'published' ? 'Published' : 'Pending'}.
);
}
return (
{visibleTemplates.map(tmpl => {
const statusCfg = STATUS_CONFIG[tmpl.status] || STATUS_CONFIG.generated;
const boundProfile = tmpl.curlProfileId ? profilesById[tmpl.curlProfileId] || null : null;
const isBoundProfileMissing = !boundProfile;
const boundProfileMessage = tmpl.curlProfileId
? 'The cURL profile used for this template no longer exists. Re-select this template from Events to continue.'
: 'This template is not bound to a cURL profile. Re-select it from Events to continue.';
return (
{tmpl.eventLabel || tmpl.eventSlug.replace(/_/g, ' ')}
{tmpl.eventSlug}
{statusCfg.label}
Bound cURL Profile
{boundProfile ? (
{boundProfile.name}
{boundProfile.id}
) : (
{boundProfileMessage}
)}
Selected Template
{tmpl.selectedTemplate}
{tmpl.templateId && (
DLT Template ID
{tmpl.templateId}
)}
{tmpl.variableMap && Object.keys(tmpl.variableMap).length > 0 && (
Variable Mappings
{Object.entries(tmpl.variableMap).map(([key, val]) => (
{key}
→
{val}
))}
)}
{!isBoundProfileMissing && tmpl.status === 'pending_whitelisting' && (
setWhitelistTarget(tmpl)}
className="px-4 py-2 rounded-lg bg-orange-text hover:bg-[#c97b45] text-white text-sm font-semibold transition shadow-sm"
>
Publish
)}
{!isBoundProfileMissing && tmpl.status === 'whitelisted' && (
setTestTarget(tmpl)}
className="px-4 py-2 rounded-lg bg-primary-blue hover:bg-primary-dark text-white text-sm font-semibold transition shadow-sm flex items-center gap-2"
>
Test SMS
)}
{tmpl.status === 'pending_whitelisting' && !isBoundProfileMissing && (
Submit to the DLT portal, then complete publish from here.
)}
);
})}
);
})()}
{whitelistTarget && (
setWhitelistTarget(null)}
onSuccess={handleWhitelistSuccess}
/>
)}
{testTarget && (
setTestTarget(null)}
/>
)}
);
}