Some checks failed
Client Admin / build-deploy (push) Failing after 8s
Client Client / build-deploy (push) Failing after 3s
Client Registration / build-deploy (push) Failing after 20s
Client Tech / build-deploy (push) Failing after 1s
Client Home / build-deploy (push) Successful in 14s
187 lines
9.1 KiB
JavaScript
187 lines
9.1 KiB
JavaScript
import React, { useRef } from 'react';
|
|
import { useAdmin, CATEGORY_LABELS, TAB_ENDPOINTS } from '../context/AdminContext';
|
|
import { TemplatesProvider } from '../context/TemplatesContext';
|
|
import { ObjectiveMappingsProvider } from '../context/ObjectiveMappingsContext';
|
|
import Sidebar from './Sidebar';
|
|
import ClientUsersPanel from './admin/ClientUsersPanel';
|
|
import SessionsPanel from './admin/SessionsPanel';
|
|
import TemplatesPanel from './admin/TemplatesPanel';
|
|
import ObjectiveMappingPanel from './admin/ObjectiveMappingPanel';
|
|
import CampaignsPanel from './admin/CampaignsPanel';
|
|
import IntelligencePanel from './admin/IntelligencePanel';
|
|
import ModifiersPanel from './admin/ModifiersPanel';
|
|
import ClientManagementPanel from './admin/ClientManagementPanel';
|
|
import ClientActivityPanel from './admin/ClientActivityPanel';
|
|
import ClientDocumentsPanel from './admin/ClientDocumentsPanel';
|
|
import DocumentsPanel from './admin/DocumentsPanel';
|
|
|
|
export default function Dashboard() {
|
|
const {
|
|
user, userRole, isAuthenticated,
|
|
activeCategory, activeTab, tabs, collapsed,
|
|
setActiveCategory, setActiveTab, setCollapsed,
|
|
data, loading, error,
|
|
} = useAdmin();
|
|
const tabBarRef = useRef(null);
|
|
|
|
return (
|
|
<div className="dashboard-layout">
|
|
{/* Sidebar */}
|
|
<Sidebar
|
|
activeCategory={activeCategory}
|
|
onSelectCategory={setActiveCategory}
|
|
collapsed={collapsed}
|
|
onToggleCollapse={() => setCollapsed(c => !c)}
|
|
/>
|
|
|
|
{/* Main area */}
|
|
<div className="dashboard-main">
|
|
{/* Header with category title + tabs */}
|
|
<header className="dashboard-header">
|
|
<div className="dashboard-header-top">
|
|
<h1 className="dashboard-title">
|
|
{CATEGORY_LABELS[activeCategory] || activeCategory}
|
|
</h1>
|
|
<div className="dashboard-header-right">
|
|
<span className="dashboard-meta">
|
|
{user?.displayName && <span>{user.displayName}</span>}
|
|
{userRole && <span><strong>Role:</strong> {userRole}</span>}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Horizontal tabs (within the current category) */}
|
|
{tabs.length > 1 && (
|
|
<div className="dashboard-tabs" ref={tabBarRef}>
|
|
{tabs.map(tab => (
|
|
<button
|
|
key={tab.id}
|
|
className={`tab-btn ${activeTab === tab.id ? 'active' : ''}`}
|
|
onClick={() => setActiveTab(tab.id)}
|
|
>
|
|
{tab.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
</header>
|
|
|
|
{/* Content area */}
|
|
<div className="dashboard-content">
|
|
|
|
{/* Loading state — full spinner only on initial load */}
|
|
{loading && !data && (
|
|
<div className="loading-container">
|
|
<div className="spinner"></div>
|
|
<p>Loading...</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* Refreshing indicator — subtle, panels stay mounted */}
|
|
{loading && data && (
|
|
<div style={{ padding: '4px 12px', fontSize: '12px', color: '#888', textAlign: 'right' }}>
|
|
Refreshing…
|
|
</div>
|
|
)}
|
|
|
|
{/* Error state */}
|
|
{error && !loading && (
|
|
<div className="error-message" style={{ margin: '0 0 16px 0' }}>
|
|
<strong>Error:</strong> {error}
|
|
</div>
|
|
)}
|
|
|
|
{/* Data-driven panels — stay mounted during refresh */}
|
|
{(data || (error && activeTab === 'templates') || activeTab === 'objectives'
|
|
|| activeTab === 'modifiers'
|
|
|| activeTab === 'performance' || activeTab === 'insights' || activeTab === 'analysis'
|
|
|| activeTab === 'pending' || activeTab === 'allClients'
|
|
|| activeTab === 'clientActivity'
|
|
|| activeTab === 'clientDocuments'
|
|
|| activeTab === 'documents') && (
|
|
<div className="data-panel" style={{ opacity: loading ? 0.6 : 1, transition: 'opacity 0.2s' }}>
|
|
{activeTab === 'overview' && data && <OverviewPanel data={data} />}
|
|
{activeTab === 'sessions' && data && <SessionsPanel />}
|
|
{activeTab === 'clientUsers' && data && <ClientUsersPanel />}
|
|
{activeTab === 'templates' && (
|
|
<TemplatesProvider>
|
|
<TemplatesPanel />
|
|
</TemplatesProvider>
|
|
)}
|
|
{activeTab === 'objectives' && (
|
|
<ObjectiveMappingsProvider>
|
|
<ObjectiveMappingPanel />
|
|
</ObjectiveMappingsProvider>
|
|
)}
|
|
{activeTab === 'modifiers' && <ModifiersPanel />}
|
|
{activeTab === 'campaigns' && data && <CampaignsPanel />}
|
|
{(activeTab === 'performance' || activeTab === 'insights' || activeTab === 'analysis') && (
|
|
<IntelligencePanel activeTab={activeTab} />
|
|
)}
|
|
{(activeTab === 'pending' || activeTab === 'allClients') && (
|
|
<ClientManagementPanel activeTab={activeTab} />
|
|
)}
|
|
{activeTab === 'clientActivity' && <ClientActivityPanel />}
|
|
{activeTab === 'clientDocuments' && <ClientDocumentsPanel />}
|
|
{activeTab === 'documents' && <DocumentsPanel />}
|
|
</div>
|
|
)}
|
|
|
|
{/* Placeholder for tabs without API endpoints */}
|
|
{!loading && !error && !data && !TAB_ENDPOINTS[activeTab]
|
|
&& activeTab !== 'pending' && activeTab !== 'allClients'
|
|
&& activeTab !== 'clientActivity'
|
|
&& activeTab !== 'clientDocuments'
|
|
&& activeTab !== 'performance' && activeTab !== 'insights' && activeTab !== 'analysis'
|
|
&& activeTab !== 'documents' && (
|
|
<div className="placeholder-panel">
|
|
<div className="placeholder-icon">🚧</div>
|
|
<h3>{activeTab.charAt(0).toUpperCase() + activeTab.slice(1)}</h3>
|
|
<p>This section is under development.</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* Fallback */}
|
|
{!loading && !error && !data && activeTab !== 'templates'
|
|
&& activeTab !== 'modifiers'
|
|
&& activeTab !== 'pending' && activeTab !== 'allClients'
|
|
&& activeTab !== 'clientActivity'
|
|
&& activeTab !== 'clientDocuments'
|
|
&& activeTab !== 'performance' && activeTab !== 'insights' && activeTab !== 'analysis'
|
|
&& activeTab !== 'documents'
|
|
&& TAB_ENDPOINTS[activeTab] && (
|
|
<div style={{ padding: '40px', textAlign: 'center', color: '#888' }}>
|
|
<p>No data loaded. Check the browser console for logs.</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
|
|
// ─── Overview Panel (lightweight, stays local) ───────────────
|
|
function OverviewPanel({ data }) {
|
|
return (
|
|
<div className="overview-panel">
|
|
<div className="stats-grid">
|
|
<StatCard label="Active Clients" value={data.activeClients} />
|
|
<StatCard label="Active Users" value={data.activeUsers} />
|
|
<StatCard label="Active Sessions" value={data.activeSessions} />
|
|
<StatCard label="API Calls (24h)" value={data.apiCalls24h} />
|
|
</div>
|
|
<p className="server-time">Server Time: {new Date(data.serverTimeUtc).toLocaleString()}</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function StatCard({ label, value }) {
|
|
return (
|
|
<div className="stat-card">
|
|
<div className="stat-value">{value ?? '—'}</div>
|
|
<div className="stat-label">{label}</div>
|
|
</div>
|
|
);
|
|
}
|