import { useState, useEffect, useCallback, useRef } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import apiClient from '../api/client'; import { useBusiness } from '../context/BusinessContext'; const DESKTOP_SPLIT_QUERY = '(min-width: 1100px)'; const DEFAULT_LIST_PANE_WIDTH = 340; const MIN_LIST_PANE_WIDTH = 280; const MAX_LIST_PANE_WIDTH = 420; const MIN_DETAIL_PANE_WIDTH = 440; function clamp(value, min, max) { return Math.min(Math.max(value, min), max); } 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 [isDesktopSplit, setIsDesktopSplit] = useState(false); const [listPaneWidth, setListPaneWidth] = useState(DEFAULT_LIST_PANE_WIDTH); const layoutRef = useRef(null); 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(() => { const mediaQuery = window.matchMedia(DESKTOP_SPLIT_QUERY); const syncLayoutMode = (event) => setIsDesktopSplit(event.matches); setIsDesktopSplit(mediaQuery.matches); if (typeof mediaQuery.addEventListener === 'function') { mediaQuery.addEventListener('change', syncLayoutMode); return () => mediaQuery.removeEventListener('change', syncLayoutMode); } mediaQuery.addListener(syncLayoutMode); return () => mediaQuery.removeListener(syncLayoutMode); }, []); 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 handleResizeStart(event) { if (!isDesktopSplit) return; event.preventDefault(); const containerBounds = layoutRef.current?.getBoundingClientRect(); if (!containerBounds) return; const maxAllowedWidth = clamp( containerBounds.width - MIN_DETAIL_PANE_WIDTH, MIN_LIST_PANE_WIDTH, MAX_LIST_PANE_WIDTH, ); function handlePointerMove(moveEvent) { const nextWidth = clamp( moveEvent.clientX - containerBounds.left, MIN_LIST_PANE_WIDTH, maxAllowedWidth, ); setListPaneWidth(nextWidth); } function handlePointerUp() { document.body.style.userSelect = ''; window.removeEventListener('mousemove', handlePointerMove); window.removeEventListener('mouseup', handlePointerUp); } document.body.style.userSelect = 'none'; window.addEventListener('mousemove', handlePointerMove); window.addEventListener('mouseup', handlePointerUp); } 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 (
Pick a saved profile to review its complete request and manage the provider details stored against it.
Saved Profiles
No saved profiles yet
Add and validate a cURL profile from Omni-channel SMS before configuring provider details here.
Select a profile
The selected profile will open here with a complete cURL preview, provider details, and activation controls.
Review the exact saved request, then update the provider fields tied to this profile.
Preview
{selectedProfile.rawCurl}