function MobileCreateBranch({ salesUrl, token, planId, branchLimit: propBranchLimit = 0 }) { const [form, setForm] = React.useState({ name: '', address: '', gstNo: '', phoneNumber: '', email: '', password: '', confirmPassword: '' }); const [rows, setRows] = React.useState([]); const [branchLimit, setBranchLimit] = React.useState(propBranchLimit); const [saving, setSaving] = React.useState(false); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(''); const [page, setPage] = React.useState(1); const [pageSize] = React.useState(10); const formTopRef = React.useRef(null); const nameInputRef = React.useRef(null); const decodeJwt = (tk) => { try { const base64 = tk.split('.')[1] || ''; const json = atob(base64.replace(/-/g, '+').replace(/_/g, '/')); return JSON.parse(json); } catch (_e) { return null; } }; const storedBranchToken = typeof window !== 'undefined' ? (localStorage.getItem('branch_token') || '') : ''; const effectiveToken = token || storedBranchToken || ''; const decodedEffective = effectiveToken ? decodeJwt(effectiveToken) : null; const branchUserDecoded = decodedEffective && decodedEffective.branch_id ? decodedEffective : null; const onChange = (e) => { const { name, value } = e.target; setForm((f) => ({ ...f, [name]: value })); }; const loadPlanLimits = React.useCallback(async () => { try { const res = await fetch(salesUrl + '/api/plan-limits'); const data = await res.json(); if (res.ok && data.limits?.branches) { setBranchLimit(data.limits.branches); } } catch (e) { console.error('Failed to fetch plan limits:', e); } }, [salesUrl]); const loadBranches = React.useCallback(async () => { setLoading(true); try { setError(''); let res = await fetch(salesUrl + '/api/branches', { headers: { Authorization: 'Bearer ' + effectiveToken } }); if (res.status === 401 && storedBranchToken && storedBranchToken !== effectiveToken) { res = await fetch(salesUrl + '/api/branches', { headers: { Authorization: 'Bearer ' + storedBranchToken } }); } const data = await res.json(); if (!res.ok) throw new Error(data.message || 'Failed to load branches'); setRows(Array.isArray(data.branches) ? data.branches : []); setPage(1); } catch (e) { if (!branchUserDecoded) setError(e.message); } finally { setLoading(false); } }, [salesUrl, effectiveToken, storedBranchToken, branchUserDecoded]); React.useEffect(() => { loadBranches(); loadPlanLimits(); }, [loadBranches, loadPlanLimits]); const submit = async (e) => { e.preventDefault(); setError(''); if (form.password !== form.confirmPassword) { return setError('Passwords do not match'); } const limit = Number.isFinite(Number(branchLimit)) ? Number(branchLimit) : 0; if (limit > 0 && rows.length >= limit) { return setError('Branch limit reached for your plan'); } const normalizedEmail = (form.email || '').toLowerCase().trim(); const emailExists = rows.some((branch) => (branch.email || '').toLowerCase().trim() === normalizedEmail); if (emailExists) { return setError('A branch with this email already exists. Please use a different email address.'); } setSaving(true); try { let res = await fetch(salesUrl + '/api/branches', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + effectiveToken }, body: JSON.stringify({ name: form.name, address: form.address, gstNo: form.gstNo, phoneNumber: form.phoneNumber, email: form.email, password: form.password }) }); if (res.status === 401 && storedBranchToken && storedBranchToken !== effectiveToken) { res = await fetch(salesUrl + '/api/branches', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + storedBranchToken }, body: JSON.stringify({ name: form.name, address: form.address, gstNo: form.gstNo, phoneNumber: form.phoneNumber, email: form.email, password: form.password }) }); } const data = await res.json(); if (!res.ok || !data.success) throw new Error(data.message || 'Create failed'); setForm({ name: '', address: '', gstNo: '', phoneNumber: '', email: '', password: '', confirmPassword: '' }); await loadBranches(); try { if (nameInputRef.current) nameInputRef.current.focus(); } catch (_e) {} } catch (e) { if (!branchUserDecoded) setError(e.message); } finally { setSaving(false); } }; const total = rows.length; const totalPages = Math.max(1, Math.ceil(total / pageSize)); const clampedPage = Math.min(totalPages, Math.max(1, page)); const startIndex = total === 0 ? 0 : (clampedPage - 1) * pageSize + 1; const endIndex = Math.min(clampedPage * pageSize, total); const visible = rows.slice((clampedPage - 1) * pageSize, (clampedPage - 1) * pageSize + pageSize); const scrollToCreate = () => { try { if (formTopRef.current) formTopRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' }); setTimeout(() => { try { if (nameInputRef.current) nameInputRef.current.focus(); } catch (_e) {} }, 250); } catch (_e) {} }; const limit = Number.isFinite(Number(branchLimit)) ? Number(branchLimit) : 0; const usedCount = rows.length; const remaining = limit > 0 ? Math.max(0, limit - usedCount) : 0; const limitReached = limit > 0 ? usedCount >= limit : true; const badgeStyle = { display: 'inline-flex', alignItems: 'center', gap: 6, padding: '6px 10px', borderRadius: 999, border: '1px solid var(--border)', background: 'var(--bg)', fontSize: 12, fontWeight: 800, color: 'var(--text)' }; const subStyle = { fontSize: 12, color: 'var(--text-muted)', marginTop: 2 }; const kvRow = { display: 'grid', gridTemplateColumns: '110px 1fr', gap: 8, padding: '8px 0', borderTop: '1px solid var(--border)' }; const kvKey = { fontSize: 12, fontWeight: 800, color: 'var(--text-muted)' }; const kvVal = { fontSize: 13, fontWeight: 700, color: 'var(--text)', wordBreak: 'break-word' }; return (
🏪 Branch Management
Create and manage branch locations
{limit > 0 ? `Limit: ${limit}` : 'Upgrade required'}
{limit > 0 ? `${usedCount}/${limit} used` : `${usedCount} branches`}
Plan
{planId || 'Basic'}
Your current plan
Available Slots
{limit > 0 ? remaining : 0}
{limit > 0 ? (remaining > 0 ? 'Ready to expand' : 'Limit reached') : 'Enable branches to add'}
+ Create New Branch
Fill details to add a new branch
{limit > 0 ? `Using ${usedCount} of ${limit} branches` : 'Upgrade to enable branches'}
{limit > 0 && limitReached ? (
🚫 Branch limit reached ({usedCount}/{limit}).
) : null} {error && (
❌ {error}
)}
Branch Locations
Readable list for mobile
{loading && visible.length === 0 ? (
Loading branches…
) : null} {visible.length === 0 && !loading ? (
No Branches Yet
Create your first branch location to get started
) : null} {visible.length > 0 ? ( <>
{visible.map((r, i) => (
{r.name || '-'}
{r.email || '-'}
#{startIndex + i}
Active
Contact
{r.phoneNumber || '-'}
GST No
{r.gstNo || '-'}
Address
{r.address || '-'}
))}
{total === 0 ? 'No branches found' : `Showing ${startIndex} to ${endIndex} of ${total} branches`}
Page {clampedPage} of {totalPages}
) : null}
); } window.MobileCreateBranch = MobileCreateBranch;