sms-extension-1777538290/client/src/components/WhitelistModal.jsx
2026-03-26 14:19:26 +05:30

183 lines
8.0 KiB
JavaScript

import { useState, useEffect } from 'react';
import apiClient from '../api/client';
export default function WhitelistModal({ businessId, template, onClose, onSuccess }) {
const [templateId, setTemplateId] = useState('');
const [toNumber, setToNumber] = useState('');
const [saving, setSaving] = useState(false);
const [error, setError] = useState('');
const [providers, setProviders] = useState(null);
const [form, setForm] = useState({ providerName: '', senderId: '', dltEntityId: '' });
const [loadingProviders, setLoadingProviders] = useState(true);
useEffect(() => {
async function fetchProviders() {
try {
const res = await apiClient.get(`/api/businesses/${businessId}/providers`);
setProviders(res.data || {});
setForm({
providerName: res.data?.providerName || '',
senderId: res.data?.senderId || '',
dltEntityId: res.data?.dltEntityId || ''
});
} catch {
setProviders({});
} finally {
setLoadingProviders(false);
}
}
fetchProviders();
}, [businessId]);
async function handleSubmit(e) {
e.preventDefault();
if (!templateId.trim() || !toNumber.trim()) return;
setSaving(true);
setError('');
try {
await apiClient.post(`/api/businesses/${businessId}/templates/${template.eventSlug}/publish`, {
templateId: templateId.trim(),
toNumber: toNumber.trim(),
providerName: form.providerName,
senderId: form.senderId.toUpperCase(),
dltEntityId: form.dltEntityId
});
onSuccess(template.eventSlug, templateId.trim());
} catch (err) {
if (err.response?.data?.missingFields) {
setError(`Missing provider fields: ${err.response.data.missingFields.join(', ')}`);
} else {
setError(err.response?.data?.error || 'Failed to publish template');
}
} finally {
setSaving(false);
}
}
const missingName = !providers?.providerName;
const missingSender = !providers?.senderId;
const missingDlt = !providers?.dltEntityId;
const hasMissingProviders = missingName || missingSender || missingDlt;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-gray-900/50 backdrop-blur-sm overflow-y-auto pt-10 pb-10">
<div className="bg-surface-white border border-border-main rounded-xl p-8 w-full max-w-md shadow-xl my-auto">
<div className="w-12 h-12 rounded-full bg-orange-bg flex items-center justify-center mx-auto mb-4">
<span className="text-xl"></span>
</div>
<h3 className="text-lg font-bold text-text-primary text-center mb-1">Publish Template</h3>
<p className="text-sm text-text-muted text-center mb-1">
Provide your DLT details and a test number to publish:
</p>
<p className="text-sm font-semibold text-text-primary text-center mb-6 capitalize">
{template.eventLabel || template.eventSlug.replace(/_/g, ' ')}
</p>
{error && (
<div className="mb-4 px-4 py-2.5 rounded-md text-error-text bg-delayed-bg border border-delayed-border text-sm font-medium">
{error}
</div>
)}
{loadingProviders ? (
<div className="flex justify-center p-4">
<span className="w-6 h-6 border-2 border-spinner-track border-t-primary-blue rounded-full animate-spin" />
</div>
) : (
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-sm font-semibold text-text-primary mb-1.5">DLT Template ID</label>
<input
type="text"
value={templateId}
onChange={e => setTemplateId(e.target.value)}
placeholder="e.g. 1234567890987654321"
className="w-full px-4 py-2.5 rounded-lg bg-page-bg border border-border-main font-mono text-text-primary placeholder-placeholder-bg focus:outline-none focus:ring-2 focus:ring-primary-blue text-sm"
autoFocus
required
/>
</div>
<div>
<label className="block text-sm font-semibold text-text-primary mb-1.5">Destination Phone Number</label>
<input
type="text"
value={toNumber}
onChange={e => setToNumber(e.target.value)}
placeholder="e.g. 919876543210"
className="w-full px-4 py-2.5 rounded-lg bg-page-bg border border-border-main font-mono text-text-primary placeholder-placeholder-bg focus:outline-none focus:ring-2 focus:ring-primary-blue text-sm"
required
/>
<p className="text-xs text-text-muted mt-1">Number to send the initial request on publish</p>
</div>
{hasMissingProviders && (
<div className="pt-2 pb-2">
<p className="text-xs text-error-text font-bold mb-3">You MUST provide missing provider details before publishing.</p>
<div className="space-y-3 p-4 bg-delayed-bg border border-delayed-border rounded-lg">
{missingName && (
<div>
<label className="block text-xs font-semibold text-text-primary mb-1">Provider Name</label>
<input
type="text"
value={form.providerName}
onChange={e => setForm({ ...form, providerName: e.target.value })}
className="w-full px-3 py-2 rounded border border-border-main bg-surface-white text-sm"
required
/>
</div>
)}
{missingSender && (
<div>
<label className="block text-xs font-semibold text-text-primary mb-1">Sender ID (6 Chars)</label>
<input
type="text"
value={form.senderId}
onChange={e => setForm({ ...form, senderId: e.target.value.toUpperCase() })}
maxLength={6}
className="w-full px-3 py-2 rounded border border-border-main bg-surface-white text-sm font-mono uppercase"
required
/>
</div>
)}
{missingDlt && (
<div>
<label className="block text-xs font-semibold text-text-primary mb-1">DLT Entity ID</label>
<input
type="text"
value={form.dltEntityId}
onChange={e => setForm({ ...form, dltEntityId: e.target.value })}
className="w-full px-3 py-2 rounded border border-border-main bg-surface-white text-sm font-mono"
required
/>
</div>
)}
</div>
</div>
)}
<div className="flex gap-3 pt-4">
<button
type="button"
onClick={onClose}
disabled={saving}
className="flex-1 py-2.5 rounded-lg border border-border-main text-text-primary hover:bg-page-bg text-sm font-medium transition disabled:opacity-50"
>
Cancel
</button>
<button
type="submit"
disabled={saving || !templateId.trim() || !toNumber.trim() || (hasMissingProviders && (!form.providerName || !form.senderId || !form.dltEntityId))}
className="flex-1 py-2.5 rounded-lg bg-primary-blue hover:bg-primary-dark text-white text-sm font-semibold transition shadow-sm disabled:opacity-50 flex items-center justify-center gap-2"
>
{saving ? <><span className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" /> Publishing</> : 'Publish'}
</button>
</div>
</form>
)}
</div>
</div>
);
}