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 (
Review the provider details stored against each saved cURL profile.
Saved Profiles
No saved profiles yet
Add and validate a cURL profile from Omni-channel SMS before configuring provider details here.
Review the exact saved request, then update the provider fields tied to this profile.
Preview
{selectedProfile.rawCurl}