85 lines
3.7 KiB
JavaScript
85 lines
3.7 KiB
JavaScript
import { BrowserRouter, Routes, Route, Navigate, useLocation } from 'react-router-dom';
|
|
import { BusinessProvider, useBusiness } from './context/BusinessContext';
|
|
import Sidebar from './components/Sidebar';
|
|
import Businesses from './pages/Businesses';
|
|
import Providers from './pages/Providers';
|
|
import GlobalSms from './pages/GlobalSms';
|
|
import Events from './pages/Events';
|
|
import Templates from './pages/Templates';
|
|
import { Link } from 'react-router-dom';
|
|
|
|
function SubLayout({ children }) {
|
|
const { activeBusinessId, hasGlobalSms } = useBusiness();
|
|
return (
|
|
<div className="flex min-h-screen bg-page-bg">
|
|
<Sidebar />
|
|
<main className="flex-1 ml-60 flex flex-col">
|
|
<header className="h-16 border-b border-border-main bg-white flex items-center justify-end px-8 z-10 shrink-0">
|
|
{hasGlobalSms && (
|
|
<Link
|
|
to={`/${activeBusinessId}/settings`}
|
|
className="w-10 h-10 rounded-full hover:bg-refresh-hover text-gray-500 hover:text-primary-blue flex items-center justify-center transition-colors shadow-sm border border-border-soft"
|
|
title="Settings"
|
|
>
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" /><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /></svg>
|
|
</Link>
|
|
)}
|
|
</header>
|
|
<div className="flex-1 p-8 overflow-auto">
|
|
{children}
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Guard: redirect to / if no active business in session.
|
|
// Also enforce cURL-first: only the cURL profile route is available until an active profile exists.
|
|
function BusinessGuard({ children, isGlobalSmsRoute }) {
|
|
const { activeBusinessId, loading, isSetupComplete } = useBusiness();
|
|
const location = useLocation();
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-page-bg">
|
|
<div className="w-8 h-8 border-2 border-indigo-200 border-t-primary-blue rounded-full animate-spin" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!activeBusinessId) {
|
|
return <Navigate to="/" state={{ from: location }} replace />;
|
|
}
|
|
|
|
if (!isSetupComplete && !isGlobalSmsRoute) {
|
|
return <Navigate to={`/${activeBusinessId}/global-sms`} replace />;
|
|
}
|
|
|
|
return children;
|
|
}
|
|
|
|
export default function App() {
|
|
return (
|
|
<BusinessProvider>
|
|
<BrowserRouter>
|
|
<Routes>
|
|
<Route path="/" element={<Businesses />} />
|
|
<Route path="/:businessId/settings" element={
|
|
<BusinessGuard><SubLayout><Providers /></SubLayout></BusinessGuard>
|
|
} />
|
|
<Route path="/:businessId/global-sms" element={
|
|
<BusinessGuard isGlobalSmsRoute><SubLayout><GlobalSms /></SubLayout></BusinessGuard>
|
|
} />
|
|
<Route path="/:businessId/events" element={
|
|
<BusinessGuard><SubLayout><Events /></SubLayout></BusinessGuard>
|
|
} />
|
|
<Route path="/:businessId/templates" element={
|
|
<BusinessGuard><SubLayout><Templates /></SubLayout></BusinessGuard>
|
|
} />
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
</BrowserRouter>
|
|
</BusinessProvider>
|
|
);
|
|
}
|