Surfaces the new GET /analytics/flowpilot/escalations endpoint as a card
above the EscalationQueue list. Closes the loop from yesterday's metric
endpoint commit — seniors and owners see the wedge stat the moment they
open the queue, which is the daily-reps version of the GTM ROI story.
Pieces:
- EscalationMetrics TS interface mirroring the backend Pydantic model
(incl. metric_definition disclaimer field)
- flowpilotAnalyticsApi.getEscalationMetrics(period) client method
- EscalationMetricCard component:
* loading skeleton, error state, zero-data empty state
* avg + median + n_with_action/n_claimed conversion rate
* humanized seconds → "Ns" / "N.N min" formatting
* inline disclaimer reminding callers this is in-product time-to-
first-action only, NOT the savings claim — pair with manual
baseline (per /codex review's two-metric correction)
- Wired into EscalationQueuePage above EscalationQueue
DS-aligned: card-flat, accent-dim usage held to interactive elements,
text-muted-foreground for secondary copy, font-heading on the headline
number, explicit transition properties (no `transition: all`). Respects
prefers-reduced-motion implicitly (only animation is the loading pulse,
which Tailwind's animate-pulse already gates).
tsc -b clean. No new tests in this commit — component is a thin
state-machine over an axios call; integration coverage comes from the
existing backend tests + the e2e Playwright work in the plan.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
30 lines
1.0 KiB
TypeScript
30 lines
1.0 KiB
TypeScript
import { useState } from 'react'
|
|
import { AlertTriangle } from 'lucide-react'
|
|
import { EscalationQueue, EscalationMetricCard } from '@/components/flowpilot'
|
|
|
|
export default function EscalationQueuePage() {
|
|
const [count, setCount] = useState<number | null>(null)
|
|
|
|
return (
|
|
<div className="mx-auto max-w-4xl p-6">
|
|
<div className="flex items-center gap-3 mb-6">
|
|
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-warning-dim">
|
|
<AlertTriangle size={16} className="text-warning" />
|
|
</span>
|
|
<div>
|
|
<h1 className="font-heading text-xl font-bold text-foreground">Escalation Queue</h1>
|
|
<p className="text-sm text-muted-foreground">
|
|
{count !== null && count > 0
|
|
? `${count} session${count !== 1 ? 's' : ''} waiting for pickup`
|
|
: 'Sessions from your team waiting for pickup'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<EscalationMetricCard period="30d" />
|
|
|
|
<EscalationQueue onCountChange={setCount} />
|
|
</div>
|
|
)
|
|
}
|