Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | 'use client'; /** * StatsCards - Support statistics overview cards */ import React from 'react'; import { SupportStats } from '@/types/support'; import { Icon } from '@/components/ui/icons'; import { IconName } from '@/components/ui/icons/registry'; export interface StatsCardsProps { /** Support statistics */ stats: SupportStats; } export default function StatsCards({ stats }: StatsCardsProps) { const cards: { label: string; value: string | number; icon: IconName; color: string }[] = [ { label: 'Total Tickets', value: stats.totalTickets, icon: 'ticket', color: 'blue'}, { label: 'Open Tickets', value: stats.openTickets, icon: 'clock-circle', color: 'yellow'}, { label: 'Resolved Today', value: stats.resolvedToday ?? 0, icon: 'check-circle-filled', color: 'green'}, { label: 'Avg Response Time', value: formatResponseTime(stats.avgResponseTime), icon: 'bolt', color: 'purple'}, ]; const colorStyles: Record<string, { bg: string; text: string; icon: string }> = { blue: { bg: 'bg-blue-50 dark:bg-blue-900/20', text: 'text-blue-600 dark:text-blue-400', icon: 'bg-blue-100 dark:bg-blue-900/40 text-blue-600 dark:text-blue-400'}, yellow: { bg: 'bg-yellow-50 dark:bg-yellow-900/20', text: 'text-yellow-600 dark:text-yellow-400', icon: 'bg-yellow-100 dark:bg-yellow-900/40 text-yellow-600 dark:text-yellow-400'}, green: { bg: 'bg-green-50 dark:bg-green-900/20', text: 'text-green-600 dark:text-green-400', icon: 'bg-green-100 dark:bg-green-900/40 text-green-600 dark:text-green-400'}, purple: { bg: 'bg-purple-50 dark:bg-purple-900/20', text: 'text-purple-600 dark:text-purple-400', icon: 'bg-purple-100 dark:bg-purple-900/40 text-purple-600 dark:text-purple-400'}}; return ( <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4"> {cards.map((card) => { const style = colorStyles[card.color]; return ( <div key={card.label} className={`${style.bg} rounded-lg p-6 border border-gray-200 dark:border-gray-700`} > <div className="flex items-center justify-between"> <div> <p className="text-sm font-medium text-gray-600 dark:text-gray-400">{card.label}</p> <p className={`text-2xl font-bold ${style.text} mt-1`}> {card.value} </p> </div> <div className={`${style.icon} p-3 rounded-full`}> <Icon name={card.icon} size={24} /> </div> </div> </div> ); })} </div> ); } /** * Format response time from seconds to human-readable string */ function formatResponseTime(seconds: number | null): string { if (seconds === null) { return 'N/A'; } const minutes = seconds / 60; if (minutes < 60) { return `${Math.round(minutes)}m`; } const hours = Math.floor(minutes / 60); const mins = Math.round(minutes % 60); if (hours < 24) { return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`; } const days = Math.floor(hours / 24); const remainingHours = hours % 24; return remainingHours > 0 ? `${days}d ${remainingHours}h` : `${days}d`; } |