import { countries } from '@/translations/countries'; import type { RouterOutputs } from '@/trpc/client'; import { cn } from '@/utils/cn'; import type { InsightPayload } from '@openpanel/validation'; import { ArrowDown, ArrowUp, FilterIcon, RotateCcwIcon } from 'lucide-react'; import { last } from 'ramda'; import { useState } from 'react'; import { DeltaChip } from '../delta-chip'; import { SerieIcon } from '../report-chart/common/serie-icon'; import { Badge } from '../ui/badge'; function formatWindowKind(windowKind: string): string { switch (windowKind) { case 'yesterday': return 'Yesterday'; case 'rolling_7d': return '7 Days'; case 'rolling_30d': return '30 Days'; } return windowKind; } interface InsightCardProps { insight: RouterOutputs['insight']['list'][number]; className?: string; onFilter?: () => void; } export function InsightCard({ insight, className, onFilter, }: InsightCardProps) { const payload = insight.payload; const dimensions = payload?.dimensions; const availableMetrics = Object.entries(payload?.metrics ?? {}); // Pick what to display: prefer share if available (geo/devices), else primaryMetric const [metricIndex, setMetricIndex] = useState( availableMetrics.findIndex(([key]) => key === payload?.primaryMetric), ); const currentMetricKey = availableMetrics[metricIndex][0]; const currentMetricEntry = availableMetrics[metricIndex][1]; const metricUnit = currentMetricEntry?.unit; const currentValue = currentMetricEntry?.current ?? null; const compareValue = currentMetricEntry?.compare ?? null; const direction = currentMetricEntry?.direction ?? 'flat'; const isIncrease = direction === 'up'; const isDecrease = direction === 'down'; const deltaText = metricUnit === 'ratio' ? `${Math.abs((currentMetricEntry?.delta ?? 0) * 100).toFixed(1)}pp` : `${Math.abs((currentMetricEntry?.changePct ?? 0) * 100).toFixed(1)}%`; // Format metric values const formatValue = (value: number | null): string => { if (value == null) return '-'; if (metricUnit === 'ratio') return `${(value * 100).toFixed(1)}%`; return Math.round(value).toLocaleString(); }; // Get the metric label const metricKeyToLabel = (key: string) => key === 'share' ? 'Share' : key === 'pageviews' ? 'Pageviews' : 'Sessions'; const metricLabel = metricKeyToLabel(currentMetricKey); const renderTitle = () => { if ( dimensions[0]?.key === 'country' || dimensions[0]?.key === 'referrer_name' || dimensions[0]?.key === 'device' ) { return ( {insight.displayName} ); } if (insight.displayName.startsWith('http')) { return ( {dimensions[1]?.displayName} ); } return insight.displayName; }; return (
{formatWindowKind(insight.windowKind)} {/* Severity: subtle dot instead of big pill */} {insight.severityBand && (
{insight.severityBand}
)}
{onFilter && (
{availableMetrics.length > 1 ? ( ) : (
)}
)}
{renderTitle()}
{/* Metric row */}
{metricLabel}
{formatValue(currentValue)}
{/* Inline compare, smaller */} {compareValue != null && (
vs {formatValue(compareValue)}
)}
{/* Delta chip */} {deltaText}
); }