188 lines
8.0 KiB
JavaScript
188 lines
8.0 KiB
JavaScript
import { useState, useEffect } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import apiClient from '../api/client';
|
|
import { useBusiness } from '../context/BusinessContext';
|
|
import RegisterBusinessModal from '../components/RegisterBusinessModal';
|
|
|
|
function DeleteConfirmModal({ businessName, onCancel, onConfirm, deleting }) {
|
|
return (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-gray-900/50 backdrop-blur-sm">
|
|
<div className="bg-white border border-gray-200 rounded-xl p-8 w-full max-w-md shadow-xl">
|
|
<div className="w-12 h-12 rounded-full bg-red-50 flex items-center justify-center mx-auto mb-4">
|
|
<span className="text-xl">🗑</span>
|
|
</div>
|
|
<h3 className="text-lg font-semibold text-gray-900 text-center mb-2">Delete Business?</h3>
|
|
<p className="text-sm text-gray-500 text-center mb-6">
|
|
This will permanently delete <span className="text-gray-900 font-medium">{businessName}</span> and all its events, templates, and images. This cannot be undone.
|
|
</p>
|
|
<div className="flex gap-3">
|
|
<button
|
|
onClick={onCancel}
|
|
disabled={deleting}
|
|
className="flex-1 py-2.5 rounded-lg border border-gray-300 text-gray-700 hover:bg-gray-50 text-sm font-medium transition disabled:opacity-50"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
onClick={onConfirm}
|
|
disabled={deleting}
|
|
className="flex-1 py-2.5 rounded-lg bg-red-600 hover:bg-red-700 text-white text-sm font-medium transition shadow-sm disabled:opacity-50 flex items-center justify-center gap-2"
|
|
>
|
|
{deleting ? <><span className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" /> Deleting…</> : 'Yes, Delete'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default function Businesses() {
|
|
const navigate = useNavigate();
|
|
const { setActiveBusiness } = useBusiness();
|
|
const [businesses, setBusinesses] = useState([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [showModal, setShowModal] = useState(false);
|
|
const [deleteTarget, setDeleteTarget] = useState(null);
|
|
const [deleting, setDeleting] = useState(false);
|
|
const [error, setError] = useState('');
|
|
|
|
async function load() {
|
|
setLoading(true);
|
|
try {
|
|
const res = await apiClient.get('/api/businesses');
|
|
setBusinesses(res.data.businesses || []);
|
|
} catch {
|
|
setError('Failed to load businesses');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
useEffect(() => { load(); }, []);
|
|
|
|
function handleSelect(biz) {
|
|
setActiveBusiness(biz);
|
|
navigate(`/${biz.businessId}/global-sms`);
|
|
}
|
|
|
|
async function handleDelete() {
|
|
if (!deleteTarget) return;
|
|
setDeleting(true);
|
|
try {
|
|
await apiClient.delete(`/api/businesses/${deleteTarget.businessId}`);
|
|
setDeleteTarget(null);
|
|
await load();
|
|
} catch (err) {
|
|
setError(err.response?.data?.error || 'Failed to delete business');
|
|
setDeleting(false);
|
|
}
|
|
}
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
|
<div className="w-8 h-8 border-2 border-indigo-200 border-t-indigo-600 rounded-full animate-spin" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ── NO BUSINESSES YET ──────────────────────────────────────────────────────
|
|
if (businesses.length === 0 && !showModal) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-gray-50">
|
|
<div className="text-center max-w-lg px-8">
|
|
<div className="w-16 h-16 rounded-2xl bg-indigo-600 flex items-center justify-center mx-auto mb-6 text-2xl font-bold text-white shadow-lg shadow-indigo-600/20">
|
|
S
|
|
</div>
|
|
<h1 className="text-3xl font-bold text-gray-900 mb-3 tracking-tight">SMS Template Extension</h1>
|
|
<p className="text-gray-500 text-base mb-8 leading-relaxed">
|
|
Generate TRAI-compliant SMS templates for your Fynd store. Add your first business to get started.
|
|
</p>
|
|
<button
|
|
onClick={() => setShowModal(true)}
|
|
className="px-8 py-3 rounded-lg bg-indigo-600 hover:bg-indigo-700 text-white font-medium shadow-sm transition-all focus:ring-2 focus:ring-offset-2 focus:ring-indigo-600"
|
|
>
|
|
Add Your First Business
|
|
</button>
|
|
</div>
|
|
{showModal && <RegisterBusinessModal onClose={() => { setShowModal(false); load(); }} />}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ── BUSINESS LIST ──────────────────────────────────────────────────────────
|
|
return (
|
|
<div className="min-h-screen bg-gray-50 p-8">
|
|
<div className="max-w-4xl mx-auto">
|
|
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between mb-8">
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-gray-900 tracking-tight">Your Businesses</h1>
|
|
<p className="text-sm text-gray-500 mt-1">Select a business to manage its SMS templates.</p>
|
|
</div>
|
|
<button
|
|
onClick={() => setShowModal(true)}
|
|
className="px-4 py-2.5 rounded-lg bg-indigo-600 hover:bg-indigo-700 text-white text-sm font-semibold shadow-sm transition"
|
|
>
|
|
+ Add Business
|
|
</button>
|
|
</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">×</button>
|
|
</div>
|
|
)}
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
{businesses.map(biz => (
|
|
<div
|
|
key={biz.businessId}
|
|
className="group rounded-xl bg-white border border-gray-200 shadow-sm hover:border-indigo-300 hover:ring-1 hover:ring-indigo-300 transition-all overflow-hidden"
|
|
>
|
|
<button
|
|
className="w-full text-left p-6"
|
|
onClick={() => handleSelect(biz)}
|
|
>
|
|
<div className="flex items-center gap-4 mb-3">
|
|
<div className="w-10 h-10 rounded-lg bg-indigo-600 flex items-center justify-center text-base font-bold text-white shrink-0 shadow-sm">
|
|
{biz.brandName?.[0]?.toUpperCase() || 'B'}
|
|
</div>
|
|
<div className="min-w-0">
|
|
<p className="font-bold text-gray-900 truncate">{biz.brandName}</p>
|
|
<p className="text-xs text-gray-500 font-medium truncate">{biz.domain}</p>
|
|
</div>
|
|
</div>
|
|
<p className="text-xs text-gray-400 font-medium">
|
|
Added {new Date(biz.createdAt).toLocaleDateString('en-IN', { day: 'numeric', month: 'short', year: 'numeric' })}
|
|
</p>
|
|
</button>
|
|
<div className="px-6 py-3 bg-gray-50 border-t border-gray-100 flex justify-between items-center">
|
|
<span className="text-xs text-indigo-600 font-semibold group-hover:underline">Click to manage →</span>
|
|
<button
|
|
onClick={(e) => { e.stopPropagation(); setDeleteTarget(biz); }}
|
|
className="text-xs text-red-500 hover:text-red-700 font-medium transition"
|
|
>
|
|
Delete
|
|
</button>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{showModal && <RegisterBusinessModal onClose={() => { setShowModal(false); load(); }} />}
|
|
{deleteTarget && (
|
|
<DeleteConfirmModal
|
|
businessName={deleteTarget.brandName}
|
|
onCancel={() => setDeleteTarget(null)}
|
|
onConfirm={handleDelete}
|
|
deleting={deleting}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|