feat(dashboard): FlowPilot cockpit dashboard + sidebar redesign

- Replace QuickStartPage with FlowPilot-centric dashboard
- Add StartSessionInput with Guided/Chat mode toggle
- Add PendingEscalations, ActiveFlowPilotSessions, PerformanceCards
- Add KnowledgeBaseCards, TeamSummary, RecentFlowPilotSessions
- Every number/card is a portal to its detail page
- Restructure sidebar: Resolve/Knowledge/Insights sections
- Remove redundant nav items (FlowPilot, Flow Editor, Flow Assist, etc.)
- Wire prefill from dashboard input to FlowPilot intake
- Update mobile nav to match new sidebar structure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 14:22:50 +00:00
parent 6122dda71d
commit 3d911d2dc9
13 changed files with 1704 additions and 633 deletions

View File

@@ -0,0 +1,95 @@
import { useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { CheckCircle, Clock, TrendingUp, Timer } from 'lucide-react'
import type { LucideIcon } from 'lucide-react'
import { sidebarApi } from '@/api'
import { cn } from '@/lib/utils'
interface StatCard {
label: string
value: string | number
icon: LucideIcon
iconColor: string
href: string
highlight?: boolean
}
export function PerformanceCards() {
const navigate = useNavigate()
const [resolved, setResolved] = useState(0)
const [active, setActive] = useState(0)
const [totalMinutes, setTotalMinutes] = useState(0)
useEffect(() => {
sidebarApi.getStats()
.then((stats) => {
setResolved(stats.resolved_today)
setActive(stats.active_count)
setTotalMinutes(stats.total_session_minutes_today)
})
.catch(() => {})
}, [])
const avgMttr = resolved > 0 ? Math.round(totalMinutes / resolved) : 0
const cards: StatCard[] = [
{
label: 'Resolved Today',
value: resolved,
icon: CheckCircle,
iconColor: '#34d399',
href: '/analytics',
highlight: true,
},
{
label: 'Avg Resolution',
value: avgMttr > 0 ? `${avgMttr}m` : '\u2014',
icon: Clock,
iconColor: '#22d3ee',
href: '/analytics',
},
{
label: 'Active Now',
value: active,
icon: TrendingUp,
iconColor: '#38bdf8',
href: '/sessions?filter=active',
},
{
label: 'Session Time',
value: totalMinutes > 0 ? `${totalMinutes}m` : '\u2014',
icon: Timer,
iconColor: '#fbbf24',
href: '/analytics',
},
]
return (
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
{cards.map((card, i) => (
<button
key={card.label}
onClick={() => navigate(card.href)}
className={cn(
'glass-card p-4 text-left fade-in',
i === 0 && 'active-glow'
)}
style={{ animationDelay: `${400 + i * 60}ms` }}
>
<div className="flex items-center justify-between mb-2">
<p className="font-label text-[0.5625rem] uppercase tracking-[0.1em] text-muted-foreground">
{card.label}
</p>
<card.icon size={14} style={{ color: card.iconColor }} />
</div>
<p className={cn(
'font-heading text-2xl font-extrabold tracking-tight',
card.highlight ? 'text-gradient-brand' : 'text-foreground'
)}>
{card.value}
</p>
</button>
))}
</div>
)
}