import React from 'react'; import { clsx } from 'clsx'; import { LucideIcon, TrendingUp, TrendingDown, Minus } from 'lucide-react'; import { Card, CardBody } from '@/components/ui/Card'; export interface TerritoryKPITileProps { title: string; value: string | number; icon: LucideIcon; trend?: { value: number; // Percentage change label: string; // e.g., "vs last period" }; format?: 'currency' | 'number' | 'percentage'; size?: 'sm' | 'md' | 'lg'; className?: string; } /** * TerritoryKPITile - Reusable metric display tile for territory manager dashboard * * Features: * - Glassmorphism design following project tokens * - Trend indicators with color-coded arrows * - Multiple format options (currency, number, percentage) * - Responsive sizing * - Proper accessibility with ARIA labels */ export const TerritoryKPITile: React.FC = ({ title, value, icon: Icon, trend, format = 'number', size = 'md', className }) => { // Format the value based on type const formatValue = (val: string | number): string => { const numVal = typeof val === 'string' ? parseFloat(val) : val; switch (format) { case 'currency': return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(numVal / 100); // Assuming value is in cents case 'percentage': return `${numVal.toFixed(1)}%`; case 'number': default: return new Intl.NumberFormat('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(numVal); } }; // Determine trend styling const getTrendColor = (change: number) => { if (change > 0) return 'text-success'; if (change < 0) return 'text-error'; return 'text-text-secondary'; }; const getTrendIcon = (change: number) => { if (change > 0) return TrendingUp; if (change < 0) return TrendingDown; return Minus; }; // Size variants const sizeClasses = { sm: { card: 'h-24', icon: 'h-4 w-4', value: 'text-lg font-bold', title: 'text-xs', trend: 'text-xs', }, md: { card: 'h-32', icon: 'h-5 w-5', value: 'text-2xl font-bold', title: 'text-sm', trend: 'text-xs', }, lg: { card: 'h-40', icon: 'h-6 w-6', value: 'text-3xl font-bold', title: 'text-base', trend: 'text-sm', }, }; const sizeConfig = sizeClasses[size]; const TrendIcon = trend ? getTrendIcon(trend.value) : null; return (
{/* Header with icon and trend */}
{/* Icon container */}
{/* Trend indicator */} {trend && TrendIcon && (
0 ? 'up' : trend.value < 0 ? 'down' : 'flat'} ${Math.abs(trend.value)}%`} >
)}
{/* Value and label */}
{/* Large value */}
{formatValue(value)}
{/* Title label */}
{title}
{/* Trend label */} {trend && (
{trend.label}
)}
); }; export default TerritoryKPITile;