bolt-templates-sms-extensio.../client/src/pages/Providers.jsx
2026-03-26 14:19:26 +05:30

162 lines
7.4 KiB
JavaScript

import { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import apiClient from '../api/client';
export default function Providers() {
const { businessId } = useParams();
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
const [form, setForm] = useState({
providerName: 'MSG91',
senderId: '',
dltEntityId: '',
authKey: '',
});
const [error, setError] = useState('');
const [success, setSuccess] = useState('');
useEffect(() => {
async function load() {
try {
const res = await apiClient.get(`/api/businesses/${businessId}/providers`);
if (res.data && res.data.providerName) {
setForm({
providerName: res.data.providerName || 'MSG91',
senderId: res.data.senderId || '',
dltEntityId: res.data.dltEntityId || '',
authKey: res.data.authKey || '',
});
}
} catch {
// no providers yet — keep defaults
} finally {
setLoading(false);
}
}
load();
}, [businessId]);
function handleChange(field, value) {
setForm(prev => ({ ...prev, [field]: value }));
}
async function handleSave(e) {
e.preventDefault();
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.post(`/api/businesses/${businessId}/providers`, form);
setSuccess('Provider configuration saved successfully.');
} catch (err) {
setError(err.response?.data?.error || 'Failed to save configuration');
} finally {
setSaving(false);
}
}
if (loading) {
return (
<div className="flex items-center justify-center h-64">
<div className="w-8 h-8 border-2 border-indigo-200 border-t-indigo-600 rounded-full animate-spin" />
</div>
);
}
return (
<div className="max-w-2xl mx-auto">
<div className="pb-5 mb-6 border-b border-gray-200">
<h1 className="text-2xl font-bold text-gray-900 tracking-tight">Provider Configuration</h1>
<p className="text-sm text-gray-500 mt-1 font-medium">Save your DLT-approved sender details so the extension can dispatch SMS via your vendor.</p>
</div>
{error && (
<div className="mb-6 px-4 py-3 rounded-md bg-red-50 border border-red-200 text-red-700 font-medium text-sm flex items-center justify-between">
{error}
<button onClick={() => setError('')} className="text-red-500 hover:text-red-700 font-bold">&times;</button>
</div>
)}
{success && (
<div className="mb-6 px-4 py-3 rounded-md bg-green-50 border border-green-200 text-green-700 font-medium text-sm flex items-center justify-between shadow-sm">
{success}
<button onClick={() => setSuccess('')} className="text-green-500 hover:text-green-700 font-bold">&times;</button>
</div>
)}
<form onSubmit={handleSave} className="bg-white border border-gray-200 rounded-xl shadow-sm overflow-hidden">
<div className="p-6 space-y-6">
<div>
<label className={`block text-sm font-semibold mb-1.5 tracking-wide ${!form.providerName ? 'text-error-text' : 'text-text-primary'}`}>
Provider Name {(!form.providerName) && <span className="text-error-text">*</span>}
</label>
<input
type="text"
value={form.providerName}
onChange={e => handleChange('providerName', e.target.value)}
className={`w-full px-4 py-2.5 rounded-lg bg-surface-white border ${!form.providerName ? 'border-error-text focus:ring-error-text' : 'border-border-main focus:ring-primary-blue'} text-text-primary placeholder-placeholder-bg font-medium focus:outline-none focus:ring-2 focus:border-transparent transition text-sm shadow-sm`}
placeholder="e.g. MSG91, Gupshup"
/>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
<div>
<label className={`block text-sm font-semibold mb-1.5 tracking-wide ${!form.senderId ? 'text-error-text' : 'text-text-primary'}`}>
DLT Sender ID {(!form.senderId) && <span className="text-error-text">*</span>}
</label>
<input
type="text"
value={form.senderId}
onChange={e => handleChange('senderId', e.target.value.toUpperCase())}
maxLength={6}
className={`w-full px-4 py-2.5 rounded-lg bg-surface-white border ${!form.senderId ? 'border-error-text focus:ring-error-text' : 'border-border-main focus:ring-primary-blue'} text-text-primary font-mono tracking-widest placeholder-placeholder-bg focus:outline-none focus:ring-2 focus:border-transparent transition text-sm shadow-sm uppercase`}
placeholder="6 CHARS"
/>
<p className="text-xs text-gray-500 mt-2 font-medium">Exactly 6 alphabetic characters (e.g. MOKOBA).</p>
</div>
<div>
<label className={`block text-sm font-semibold mb-1.5 tracking-wide ${!form.dltEntityId ? 'text-error-text' : 'text-text-primary'}`}>
DLT Entity ID {(!form.dltEntityId) && <span className="text-error-text">*</span>}
</label>
<input
type="text"
value={form.dltEntityId}
onChange={e => handleChange('dltEntityId', e.target.value)}
className={`w-full px-4 py-2.5 rounded-lg bg-surface-white border ${!form.dltEntityId ? 'border-error-text focus:ring-error-text' : 'border-border-main focus:ring-primary-blue'} text-text-primary font-mono placeholder-placeholder-bg focus:outline-none focus:ring-2 focus:border-transparent transition text-sm shadow-sm`}
placeholder="19-digit DLT PE ID"
/>
</div>
</div>
<div>
<label className="block text-sm font-semibold text-text-primary mb-1.5 tracking-wide">API Auth Key <span className="text-text-muted font-normal text-xs">(Optional)</span></label>
<input
type="password"
value={form.authKey}
onChange={e => handleChange('authKey', e.target.value)}
className="w-full px-4 py-2.5 rounded-lg bg-surface-white border border-border-main text-text-primary font-mono placeholder-placeholder-bg focus:outline-none focus:ring-2 focus:ring-primary-blue focus:border-transparent transition text-sm shadow-sm"
placeholder="Authorization key for your SMS provider"
/>
<p className="text-xs text-gray-500 mt-2 font-medium">Used as the Authorization header in your SMS requests.</p>
</div>
</div>
<div className="px-6 py-4 bg-gray-50 border-t border-gray-200 flex justify-end">
<button
type="submit"
disabled={saving}
className="px-6 py-2.5 rounded-lg bg-primary-blue hover:bg-primary-dark text-white font-semibold text-sm shadow-sm transition 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" /> Saving</> : 'Save Configuration'}
</button>
</div>
</form>
</div>
);
}