Add team activity page and dashboard navigation
This commit is contained in:
@@ -50,6 +50,7 @@ import SchedulerDashboard from './pages/SchedulerDashboard';
|
||||
import BillingPage from './pages/BillingPage';
|
||||
import ApprovalsPage from './pages/ApprovalsPage';
|
||||
import StripeDisputesDashboard from './pages/StripeDisputesDashboard';
|
||||
import TeamActivityPage from './pages/TeamActivityPage';
|
||||
import ProtectedRoute from './components/shared/ProtectedRoute';
|
||||
import GSCAuthCallback from './components/SEODashboard/components/GSCAuthCallback';
|
||||
import Landing from './components/Landing/Landing';
|
||||
@@ -622,6 +623,7 @@ const App: React.FC = () => {
|
||||
<Route path="/scheduler-dashboard" element={<ProtectedRoute><SchedulerDashboard /></ProtectedRoute>} />
|
||||
<Route path="/billing" element={<ProtectedRoute><BillingPage /></ProtectedRoute>} />
|
||||
<Route path="/approvals" element={<ProtectedRoute><ApprovalsPage /></ProtectedRoute>} />
|
||||
<Route path="/team-activity" element={<ProtectedRoute><TeamActivityPage /></ProtectedRoute>} />
|
||||
<Route path="/stripe-disputes" element={<ProtectedRoute><StripeDisputesDashboard /></ProtectedRoute>} />
|
||||
<Route path="/pricing" element={<PricingPage />} />
|
||||
<Route path="/research-test" element={<ResearchDashboard />} />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Box,
|
||||
Paper,
|
||||
@@ -85,6 +86,8 @@ const AGENT_TEAM: AgentStatus[] = [
|
||||
];
|
||||
|
||||
const TeamHuddleWidget: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<Paper
|
||||
elevation={0}
|
||||
@@ -195,7 +198,21 @@ const TeamHuddleWidget: React.FC = () => {
|
||||
</List>
|
||||
|
||||
<Box mt={2} pt={2} borderTop="1px solid #eee" display="flex" justifyContent="center">
|
||||
<Typography variant="caption" color="primary" sx={{ fontWeight: 600, cursor: 'pointer', '&:hover': { textDecoration: 'underline' } }}>
|
||||
<Typography
|
||||
component="button"
|
||||
type="button"
|
||||
variant="caption"
|
||||
color="primary"
|
||||
onClick={() => navigate('/team-activity')}
|
||||
sx={{
|
||||
border: 0,
|
||||
bgcolor: 'transparent',
|
||||
p: 0,
|
||||
fontWeight: 600,
|
||||
cursor: 'pointer',
|
||||
'&:hover': { textDecoration: 'underline' }
|
||||
}}
|
||||
>
|
||||
View Full Team Activity
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
109
frontend/src/pages/TeamActivityPage.tsx
Normal file
109
frontend/src/pages/TeamActivityPage.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Chip,
|
||||
Divider,
|
||||
Paper,
|
||||
Stack,
|
||||
Typography,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
} from '@mui/material';
|
||||
|
||||
const activeRuns = [
|
||||
{ id: 'run-9142', title: 'Q4 SEO Pillar Refresh', owner: 'SEO Specialist', progress: '67%' },
|
||||
{ id: 'run-9143', title: 'LinkedIn Carousel Draft', owner: 'Content Strategist', progress: '42%' },
|
||||
{ id: 'run-9144', title: 'Competitor Monitoring Sweep', owner: 'Competitor Analyst', progress: '88%' },
|
||||
];
|
||||
|
||||
const timelineEvents = [
|
||||
{ time: '09:20', detail: 'Strategy Architect approved updated campaign goals.' },
|
||||
{ time: '09:35', detail: 'Social Manager queued 6 posts for review.' },
|
||||
{ time: '10:05', detail: 'SEO Specialist flagged ranking drop on "AI copy tools".' },
|
||||
{ time: '10:24', detail: 'Content Strategist generated new briefing packet.' },
|
||||
];
|
||||
|
||||
const alerts = [
|
||||
{ severity: 'high', label: '2 content briefs are blocked on missing references.' },
|
||||
{ severity: 'medium', label: 'SERP volatility increased for 3 tracked keywords.' },
|
||||
];
|
||||
|
||||
const approvals = [
|
||||
{ id: 'ap-112', action: 'Publish LinkedIn thread for Campaign Alpha', requestedBy: 'Social Manager' },
|
||||
{ id: 'ap-113', action: 'Approve budget reallocation to ad creatives', requestedBy: 'Strategy Architect' },
|
||||
];
|
||||
|
||||
export default function TeamActivityPage() {
|
||||
return (
|
||||
<Box sx={{ p: { xs: 2, md: 3 } }}>
|
||||
<Typography variant="h4" sx={{ fontWeight: 700, mb: 1 }}>
|
||||
Team Activity
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||
Real-time view of active agent workstreams, timelines, alerts, and pending approvals.
|
||||
</Typography>
|
||||
|
||||
<Stack spacing={2.5}>
|
||||
<Paper sx={{ p: 2.5 }}>
|
||||
<Typography variant="h6" sx={{ fontWeight: 700, mb: 1.5 }}>Active Runs</Typography>
|
||||
<Stack spacing={1}>
|
||||
{activeRuns.map((run) => (
|
||||
<Stack key={run.id} direction="row" justifyContent="space-between" alignItems="center">
|
||||
<Box>
|
||||
<Typography sx={{ fontWeight: 600 }}>{run.title}</Typography>
|
||||
<Typography variant="caption" color="text.secondary">{run.owner}</Typography>
|
||||
</Box>
|
||||
<Chip size="small" label={run.progress} color="primary" variant="outlined" />
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
<Paper sx={{ p: 2.5 }}>
|
||||
<Typography variant="h6" sx={{ fontWeight: 700, mb: 1.5 }}>Event Timeline</Typography>
|
||||
<List disablePadding>
|
||||
{timelineEvents.map((event, index) => (
|
||||
<React.Fragment key={`${event.time}-${event.detail}`}>
|
||||
{index > 0 && <Divider sx={{ my: 1 }} />}
|
||||
<ListItem disableGutters sx={{ py: 0 }}>
|
||||
<ListItemText
|
||||
primary={<Typography sx={{ fontWeight: 600 }}>{event.detail}</Typography>}
|
||||
secondary={<Typography variant="caption">{event.time}</Typography>}
|
||||
/>
|
||||
</ListItem>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</List>
|
||||
</Paper>
|
||||
|
||||
<Paper sx={{ p: 2.5 }}>
|
||||
<Typography variant="h6" sx={{ fontWeight: 700, mb: 1.5 }}>Alerts</Typography>
|
||||
<Stack spacing={1}>
|
||||
{alerts.map((alert) => (
|
||||
<Chip
|
||||
key={alert.label}
|
||||
label={alert.label}
|
||||
color={alert.severity === 'high' ? 'error' : 'warning'}
|
||||
variant="outlined"
|
||||
sx={{ justifyContent: 'flex-start' }}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
</Paper>
|
||||
|
||||
<Paper sx={{ p: 2.5 }}>
|
||||
<Typography variant="h6" sx={{ fontWeight: 700, mb: 1.5 }}>Approvals Requiring Action</Typography>
|
||||
<Stack spacing={1}>
|
||||
{approvals.map((approval) => (
|
||||
<Box key={approval.id}>
|
||||
<Typography sx={{ fontWeight: 600 }}>{approval.action}</Typography>
|
||||
<Typography variant="caption" color="text.secondary">Requested by {approval.requestedBy}</Typography>
|
||||
</Box>
|
||||
))}
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user