import { useEffect, useMemo, useState } from 'react'; import apiClient from '../api/client'; import { buildTemplateSampleRender, getTemplateSamplePayload, getTemplateWorkspaceDescription, } from '../utils/templateWorkspace'; const STATUS_LABELS = { pending_whitelisting: 'Pending Whitelisting', whitelisted: 'Published', generated: 'Generated', }; function getStatusLabel(status) { return STATUS_LABELS[String(status || '').trim()] || 'Draft'; } function buildProfileMap(profiles = []) { return Object.fromEntries((profiles || []).map((profile) => [profile.id, profile])); } export default function TemplateDetailWorkspaceModal({ businessId, templateSlug, initialTemplate = null, initialProfile = null, onClose, onRequestPublish, onRequestTest, }) { const [template, setTemplate] = useState(initialTemplate); const [profilesById, setProfilesById] = useState(initialProfile?.id ? { [initialProfile.id]: initialProfile } : {}); const [loading, setLoading] = useState(!initialTemplate); const [error, setError] = useState(''); useEffect(() => { setTemplate(initialTemplate); }, [initialTemplate]); useEffect(() => { if (!initialProfile?.id) return; setProfilesById((currentProfiles) => ({ ...currentProfiles, [initialProfile.id]: initialProfile, })); }, [initialProfile]); useEffect(() => { if (!templateSlug) return undefined; const previousBodyOverflow = document.body.style.overflow; const previousBodyOverscroll = document.body.style.overscrollBehavior; const previousHtmlOverflow = document.documentElement.style.overflow; const previousHtmlOverscroll = document.documentElement.style.overscrollBehavior; document.body.style.overflow = 'hidden'; document.body.style.overscrollBehavior = 'none'; document.documentElement.style.overflow = 'hidden'; document.documentElement.style.overscrollBehavior = 'none'; return () => { document.body.style.overflow = previousBodyOverflow; document.body.style.overscrollBehavior = previousBodyOverscroll; document.documentElement.style.overflow = previousHtmlOverflow; document.documentElement.style.overscrollBehavior = previousHtmlOverscroll; }; }, [templateSlug]); useEffect(() => { if (!templateSlug) return undefined; let cancelled = false; async function loadWorkspace() { setLoading(true); setError(''); try { const [templateRes, profilesRes] = await Promise.all([ apiClient.get(`/api/businesses/${businessId}/templates/${templateSlug}`), apiClient.get(`/api/businesses/${businessId}/global-sms/profiles`).catch(() => ({ data: { profiles: [] } })), ]); if (cancelled) return; setTemplate(templateRes.data || null); setProfilesById((currentProfiles) => ({ ...currentProfiles, ...buildProfileMap(profilesRes.data?.profiles || []), })); } catch (err) { if (cancelled) return; setError(err.response?.data?.error || 'Failed to load template details'); } finally { if (!cancelled) setLoading(false); } } loadWorkspace(); return () => { cancelled = true; }; }, [businessId, templateSlug]); const boundProfile = useMemo(() => { const profileId = String(template?.curlProfileId || '').trim(); if (!profileId) return initialProfile || null; return profilesById[profileId] || initialProfile || null; }, [initialProfile, profilesById, template?.curlProfileId]); const samplePayload = useMemo(() => getTemplateSamplePayload(template || {}), [template]); const previewState = useMemo( () => buildTemplateSampleRender(template?.selectedTemplate, template?.variableMap, samplePayload), [samplePayload, template?.selectedTemplate, template?.variableMap], ); const renderedPreview = previewState.text; const description = useMemo(() => getTemplateWorkspaceDescription(template || {}), [template]); const isPublished = template?.status === 'whitelisted'; const isPending = template?.status === 'pending_whitelisting'; const hasBoundProfile = !!boundProfile; const canPublish = typeof onRequestPublish === 'function' && isPending && hasBoundProfile; const canTest = typeof onRequestTest === 'function' && isPublished && hasBoundProfile; const runtimeStateLabel = isPublished ? (template?.isRuntimeEnabled === false ? 'Paused' : 'Active') : 'Not live yet'; const provider = boundProfile?.provider || {}; const samplePayloadText = JSON.stringify(samplePayload, null, 2); return (
Template Workspace
Sample Payload
Hardcoded event payload for previewing this template
{samplePayloadText}
Message
{String(template?.selectedTemplate || '').length} characters{template?.selectedTemplate || 'No selected template yet.'}
Preview
Sample render{renderedPreview || template?.selectedTemplate || 'Preview unavailable.'}