import { useState, useEffect, useCallback, useRef } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import apiClient from '../api/client'; import { useBusiness } from '../context/BusinessContext'; function getMissingProviderFields(profile) { const provider = profile?.provider || {}; const missing = []; if (!provider.providerName) missing.push('Provider Name'); if (!provider.senderId) missing.push('Sender ID'); if (!provider.dltEntityId) missing.push('DLT Entity ID'); return missing; } function isProviderSetupComplete(profile) { return getMissingProviderFields(profile).length === 0; } function formatUpdatedAt(value) { if (!value) return 'Not updated yet'; try { return new Date(value).toLocaleString(); } catch { return 'Not updated yet'; } } function buildProviderSummary(profile) { const provider = profile?.provider || {}; const parts = []; if (provider.providerName) parts.push(provider.providerName); if (provider.senderId) parts.push(`Sender ${provider.senderId}`); if (provider.dltEntityId) parts.push('DLT added'); return parts.length > 0 ? parts.join(' • ') : 'Provider details not completed yet'; } function ProfileStatusPill({ complete }) { return ( {complete ? 'Complete' : 'Missing Fields'} ); } export default function Providers() { const { businessId } = useParams(); const navigate = useNavigate(); const { refreshOnboardingState } = useBusiness(); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [profiles, setProfiles] = useState([]); const [activeProfileId, setActiveProfileId] = useState(''); const [selectedProfileId, setSelectedProfileId] = useState(''); const [form, setForm] = useState({ providerName: '', senderId: '', dltEntityId: '', authKey: '', }); const [error, setError] = useState(''); const [success, setSuccess] = useState(''); const [copiedProfileId, setCopiedProfileId] = useState(''); const copyTimeoutRef = useRef(null); const globalSmsPath = `/${businessId}/global-sms`; const loadProfiles = useCallback(async () => { try { setLoading(true); const res = await apiClient.get(`/api/businesses/${businessId}/global-sms/profiles`); const fetchedProfiles = res.data?.profiles || []; const nextActiveProfileId = String(res.data?.activeProfileId || ''); setProfiles(fetchedProfiles); setActiveProfileId(nextActiveProfileId); setSelectedProfileId((currentSelectedProfileId) => ( fetchedProfiles.some((profile) => profile.id === currentSelectedProfileId) ? currentSelectedProfileId : '' )); } catch (err) { setError(err.response?.data?.error || 'Failed to load provider profiles'); } finally { setLoading(false); } }, [businessId]); useEffect(() => { loadProfiles(); }, [loadProfiles]); useEffect(() => () => { if (copyTimeoutRef.current) { clearTimeout(copyTimeoutRef.current); } }, []); const selectedProfile = profiles.find((profile) => profile.id === selectedProfileId) || null; useEffect(() => { if (!selectedProfile) { setForm({ providerName: '', senderId: '', dltEntityId: '', authKey: '', }); return; } const provider = selectedProfile.provider || {}; setForm({ providerName: provider.providerName || '', senderId: provider.senderId || '', dltEntityId: provider.dltEntityId || '', authKey: provider.authKey || '', }); }, [selectedProfile]); function handleChange(field, value) { setForm((prev) => ({ ...prev, [field]: value })); } function handleSelectProfile(profileId) { setSelectedProfileId(profileId); setError(''); setSuccess(''); } function handleReturnToList() { setSelectedProfileId(''); setError(''); setSuccess(''); } async function handleActivate(profile) { if (!profile?.id) return; try { setError(''); setSuccess(''); await apiClient.post(`/api/businesses/${businessId}/global-sms/profiles/${profile.id}/activate`); setSelectedProfileId(profile.id); await loadProfiles(); await refreshOnboardingState(businessId).catch(() => null); setSuccess(`${profile.name} is now the active profile.`); } catch (err) { setError(err.response?.data?.error || 'Failed to activate profile'); } } async function handleCopyCurl(profile) { if (!profile?.rawCurl) return; try { if (!navigator?.clipboard?.writeText) { throw new Error('Clipboard API unavailable'); } await navigator.clipboard.writeText(profile.rawCurl); setCopiedProfileId(profile.id); if (copyTimeoutRef.current) { clearTimeout(copyTimeoutRef.current); } copyTimeoutRef.current = window.setTimeout(() => { setCopiedProfileId(''); }, 1800); } catch { setError('Failed to copy the cURL command.'); } } async function handleSave(event) { event.preventDefault(); if (!selectedProfile?.id) return; setSaving(true); setError(''); setSuccess(''); if (form.senderId && !/^[A-Za-z]{6}$/.test(form.senderId)) { setError('DLT Sender ID must be exactly 6 alphabet characters'); setSaving(false); return; } try { await apiClient.patch(`/api/businesses/${businessId}/global-sms/profiles/${selectedProfile.id}`, { provider: { providerName: form.providerName, senderId: form.senderId.toUpperCase(), dltEntityId: form.dltEntityId, authKey: form.authKey, }, }); await loadProfiles(); await refreshOnboardingState(businessId).catch(() => null); setSuccess(`Provider configuration saved for ${selectedProfile.name}.`); } catch (err) { setError(err.response?.data?.error || 'Failed to save configuration'); } finally { setSaving(false); } } if (loading) { return (
); } return (

Provider Configuration

Review the provider details stored against each saved cURL profile.

{error && (
{error}
)} {success && (
{success}
)} {!selectedProfile ? (

Saved Profiles

{profiles.length} total
{profiles.length === 0 ? (

No saved profiles yet

Add and validate a cURL profile from Omni-channel SMS before configuring provider details here.

) : (
{profiles.map((profile) => { const isActive = profile.id === activeProfileId; const complete = isProviderSetupComplete(profile); return ( ); })}
)}
) : (

{selectedProfile.name}

{selectedProfile.id === activeProfileId && ( Active profile )}

Review the exact saved request, then update the provider fields tied to this profile.

{selectedProfile.id !== activeProfileId && ( )}

Preview

Updated {formatUpdatedAt(selectedProfile.updatedAt)}
                {selectedProfile.rawCurl}
              

Provider Details

These fields are stored against this profile and are used during template publishing.

handleChange('providerName', event.target.value)} className={`w-full rounded-lg border px-4 py-2 text-sm font-medium text-text-primary placeholder-placeholder-bg transition focus:border-transparent focus:outline-none focus:ring-2 ${!form.providerName ? 'border-error-text focus:ring-error-text' : 'border-border-main focus:ring-primary-blue'} bg-surface-white`} placeholder="e.g. MSG91, Gupshup" />
handleChange('senderId', event.target.value.toUpperCase())} maxLength={6} className={`w-full rounded-lg border px-4 py-2 font-mono text-sm uppercase tracking-widest text-text-primary placeholder-placeholder-bg transition focus:border-transparent focus:outline-none focus:ring-2 ${!form.senderId ? 'border-error-text focus:ring-error-text' : 'border-border-main focus:ring-primary-blue'} bg-surface-white`} placeholder="6 CHARS" />

Exactly 6 alphabetic characters.

handleChange('dltEntityId', event.target.value)} className={`w-full rounded-lg border px-4 py-2 font-mono text-sm text-text-primary placeholder-placeholder-bg transition focus:border-transparent focus:outline-none focus:ring-2 ${!form.dltEntityId ? 'border-error-text focus:ring-error-text' : 'border-border-main focus:ring-primary-blue'} bg-surface-white`} placeholder="19-digit DLT PE ID" />
handleChange('authKey', event.target.value)} className="w-full rounded-lg border border-border-main bg-surface-white px-4 py-2 font-mono text-sm text-text-primary placeholder-placeholder-bg transition focus:border-transparent focus:outline-none focus:ring-2 focus:ring-primary-blue" placeholder="Authorization key for your SMS provider" />

Used as the Authorization header in your SMS requests.

)}
); }