import { useState, useEffect, useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import apiClient from '../api/client'; import { useBusiness } from '../context/BusinessContext'; import RegisterBusinessModal from '../components/RegisterBusinessModal'; import { fetchActiveSalesChannels } from '../utils/fyndSalesChannels'; import { getBusinessDomain, getBusinessImage, getBusinessName, getBusinessTagline, getChannelId, } from '../utils/businessProfile'; function DeleteConfirmModal({ businessName, onCancel, onConfirm, deleting }) { return (
đź—‘

Delete Business?

This will permanently delete {businessName} and all its events, templates, and images. This cannot be undone.

); } function BusinessCreatedModal({ business, onClose }) { const name = getBusinessName(business); const domain = getBusinessDomain(business); const tagline = getBusinessTagline(business); const image = getBusinessImage(business); return (
âś“

Business Added!

Your business is ready for onboarding.

{image ? ( {name} ) : ( {name?.[0]?.toUpperCase() || 'B'} )}

{name}

{domain &&

{domain}

} {tagline &&

{tagline}

}
); } function SalesChannelCard({ channel, disabled, onImport }) { const name = getBusinessName(channel); const domain = getBusinessDomain(channel); const image = getBusinessImage(channel); return (
{image ? ( {name} ) : ( {name?.[0]?.toUpperCase() || 'S'} )}

{name}

{domain || 'Domain unavailable'}

{channel.websiteUrl ? 'Ready to scrape' : 'Use manual URL fallback'}
); } export default function Businesses() { const navigate = useNavigate(); const { setActiveBusiness } = useBusiness(); const [businesses, setBusinesses] = useState([]); const [salesChannels, setSalesChannels] = useState([]); const [loading, setLoading] = useState(true); const [salesChannelsStatus, setSalesChannelsStatus] = useState('loading'); const [salesChannelsError, setSalesChannelsError] = useState(''); const [salesChannelQuery, setSalesChannelQuery] = useState(''); const [selectingBusinessId, setSelectingBusinessId] = useState(''); const [creatingSalesChannelId, setCreatingSalesChannelId] = useState(''); const [createdBusiness, setCreatedBusiness] = useState(null); const [showModal, setShowModal] = useState(false); const [deleteTarget, setDeleteTarget] = useState(null); const [deleting, setDeleting] = useState(false); const [error, setError] = useState(''); const configuredApplicationIds = useMemo(() => ( new Set( businesses .map((business) => String(business?.applicationId || '').trim()) .filter(Boolean) ) ), [businesses]); const availableSalesChannels = useMemo(() => ( salesChannels.filter((channel) => !configuredApplicationIds.has(getChannelId(channel))) ), [configuredApplicationIds, salesChannels]); const filteredSalesChannels = useMemo(() => { const query = salesChannelQuery.trim().toLowerCase(); if (!query) return availableSalesChannels; return availableSalesChannels.filter((channel) => { const name = String(getBusinessName(channel) || '').toLowerCase(); const domain = String(getBusinessDomain(channel) || '').toLowerCase(); return name.includes(query) || domain.includes(query); }); }, [availableSalesChannels, salesChannelQuery]); const loadBusinesses = useCallback(async () => { const res = await apiClient.get('/api/businesses'); setBusinesses(res.data.businesses || []); }, []); const loadSalesChannels = useCallback(async () => { setSalesChannelsStatus('loading'); const channels = await fetchActiveSalesChannels(); setSalesChannels(channels); setSalesChannelsStatus('success'); }, []); const load = useCallback(async () => { setLoading(true); setError(''); setSalesChannelsError(''); try { const [businessesRes, salesChannelsRes] = await Promise.allSettled([ loadBusinesses(), loadSalesChannels(), ]); if (businessesRes.status === 'rejected') { setError('Failed to load businesses'); } if (salesChannelsRes.status === 'rejected') { setSalesChannels([]); setSalesChannelsStatus('error'); setSalesChannelsError( salesChannelsRes.reason?.message || 'Active sales channels could not be loaded right now.' ); } } finally { setLoading(false); } }, [loadBusinesses, loadSalesChannels]); useEffect(() => { load(); }, [load]); async function handleSelect(biz) { setSelectingBusinessId(biz.businessId); setError(''); try { const setupComplete = await setActiveBusiness(biz); navigate(`/${biz.businessId}/${setupComplete ? 'events' : 'global-sms'}`); } catch (err) { setError(err.response?.data?.error || 'Failed to open business'); } finally { setSelectingBusinessId(''); } } async function handleCreateFromSalesChannel(channel) { const applicationId = getChannelId(channel); if (!applicationId) return; if (!channel.websiteUrl) { setSalesChannelsError('A website URL could not be derived from this sales channel. Please use Add Business and enter the URL manually.'); return; } setCreatingSalesChannelId(applicationId); setError(''); setSalesChannelsError(''); try { const res = await apiClient.post('/api/businesses', { applicationId, websiteUrl: channel.websiteUrl, }); setCreatedBusiness(res.data); await Promise.all([loadBusinesses(), loadSalesChannels()]); setSalesChannelsStatus('success'); } catch (err) { setError(err.response?.data?.error || 'Failed to add business from sales channel'); } finally { setCreatingSalesChannelId(''); } } 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'); } finally { setDeleting(false); } } if (loading) { return (
); } return (

{businesses.length > 0 ? 'Your Businesses' : 'Set Up Your First Business'}

Import from an active sales channel when available, or use the website URL fallback to scrape manually.

{error && (
{error}
)}

Configured Businesses

Select a business to manage its SMS templates.

{businesses.length > 0 ? (
{businesses.map((biz) => (
Click to manage →
))}
) : (

No configured businesses yet.

Import from an active sales channel below, or use Add Business to enter a storefront URL manually.

)}

Active Sales Channels

These are pulled directly from Commerce and can be scraped into businesses with one click.

{salesChannelsError && (
{salesChannelsError}
)} {salesChannelsStatus === 'loading' ? (

Loading active sales channels…

) : availableSalesChannels.length > 0 ? (
setSalesChannelQuery(e.target.value)} placeholder="Search by channel name or domain" className="w-full rounded-lg border border-gray-300 px-4 py-2.5 text-sm text-gray-900 placeholder-gray-400 shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:border-transparent" />
{filteredSalesChannels.map((channel) => { const channelId = getChannelId(channel); return ( handleCreateFromSalesChannel(channel)} /> ); })}
{filteredSalesChannels.length === 0 && (

No active sales channels matched your search.

Use the website URL fallback if you want to scrape a storefront directly.

)}
) : (

No active sales channels are available right now.

Use Add Business to enter a website URL manually and keep moving.

)}
{showModal && ( { setShowModal(false); loadBusinesses(); }} /> )} {createdBusiness && setCreatedBusiness(null)} />} {deleteTarget && ( setDeleteTarget(null)} onConfirm={handleDelete} deleting={deleting} /> )}
); }