'use client' import { TrendUp } from '@phosphor-icons/react' import { Pie, PieChart, Tooltip } from 'recharts' import { ChartContainer, type ChartConfig, } from '@/components/charts' import type { FrustrationSummary } from '@/lib/api/stats' interface FrustrationTrendProps { summary: FrustrationSummary | null loading: boolean } function SkeletonCard() { return (
) } const LABELS: Record = { rage_clicks: 'Rage Clicks', dead_clicks: 'Dead Clicks', prev_rage_clicks: 'Prev Rage Clicks', prev_dead_clicks: 'Prev Dead Clicks', } const COLORS = { rage_clicks: 'rgba(253, 94, 15, 0.7)', dead_clicks: 'rgba(180, 83, 9, 0.7)', prev_rage_clicks: 'rgba(253, 94, 15, 0.35)', prev_dead_clicks: 'rgba(180, 83, 9, 0.35)', } as const const chartConfig = { count: { label: 'Count' }, rage_clicks: { label: 'Rage Clicks', color: COLORS.rage_clicks }, dead_clicks: { label: 'Dead Clicks', color: COLORS.dead_clicks }, prev_rage_clicks: { label: 'Prev Rage Clicks', color: COLORS.prev_rage_clicks }, prev_dead_clicks: { label: 'Prev Dead Clicks', color: COLORS.prev_dead_clicks }, } satisfies ChartConfig function CustomTooltip({ active, payload }: { active?: boolean; payload?: Array<{ payload: { type: string; count: number; fill: string } }> }) { if (!active || !payload?.length) return null const item = payload[0].payload return (
{LABELS[item.type] ?? item.type} {item.count.toLocaleString()}
) } export default function FrustrationTrend({ summary, loading }: FrustrationTrendProps) { if (loading || !summary) return const hasData = summary.rage_clicks > 0 || summary.dead_clicks > 0 || summary.prev_rage_clicks > 0 || summary.prev_dead_clicks > 0 const totalCurrent = summary.rage_clicks + summary.dead_clicks const totalPrevious = summary.prev_rage_clicks + summary.prev_dead_clicks const totalChange = totalPrevious > 0 ? Math.round(((totalCurrent - totalPrevious) / totalPrevious) * 100) : null const hasPrevious = totalPrevious > 0 const chartData = [ { type: 'rage_clicks', count: summary.rage_clicks, fill: COLORS.rage_clicks }, { type: 'dead_clicks', count: summary.dead_clicks, fill: COLORS.dead_clicks }, { type: 'prev_rage_clicks', count: summary.prev_rage_clicks, fill: COLORS.prev_rage_clicks }, { type: 'prev_dead_clicks', count: summary.prev_dead_clicks, fill: COLORS.prev_dead_clicks }, ].filter(d => d.count > 0) if (!hasData) { return (

Frustration Trend

Rage vs. dead click breakdown

No trend data yet

Frustration trend data will appear here once rage clicks or dead clicks are detected on your site.

) } return (

Frustration Trend

{hasPrevious ? 'Rage and dead clicks split across current and previous period' : 'Rage vs. dead click breakdown'}

} />
{totalChange !== null ? ( <> {totalChange > 0 ? 'Up' : totalChange < 0 ? 'Down' : 'No change'} by {Math.abs(totalChange)}% vs previous period ) : totalCurrent > 0 ? ( <> {totalCurrent.toLocaleString()} new signals this period ) : ( 'No frustration signals detected' )}
) }