Files
AdPlatform-Client/Client-Admin/src/components/Dashboard.jsx
Grae Jones fdb3e117a9
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
First build
2026-03-21 17:54:42 -07:00

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>
);
}