2026-04-09 10:01:23 +08:00
|
|
|
"use client"
|
|
|
|
|
|
|
|
|
|
import Link from "next/link"
|
|
|
|
|
import {
|
|
|
|
|
BotMessageSquareIcon,
|
|
|
|
|
CircleDashedIcon,
|
|
|
|
|
HeadsetIcon,
|
|
|
|
|
SparklesIcon,
|
|
|
|
|
WavesIcon,
|
|
|
|
|
} from "lucide-react"
|
|
|
|
|
|
|
|
|
|
import type { DashboardOverview } from "@/lib/api/dashboard"
|
|
|
|
|
import {
|
|
|
|
|
Card,
|
|
|
|
|
CardContent,
|
|
|
|
|
CardDescription,
|
|
|
|
|
CardHeader,
|
|
|
|
|
CardTitle,
|
|
|
|
|
} from "@/components/ui/card"
|
2026-05-25 12:06:15 +08:00
|
|
|
import { useI18n } from "@/i18n/provider"
|
2026-04-09 10:01:23 +08:00
|
|
|
|
|
|
|
|
type SummaryCardsProps = {
|
|
|
|
|
summary: DashboardOverview["summary"]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type SummaryCardItem = {
|
|
|
|
|
key: keyof DashboardOverview["summary"]
|
2026-05-25 12:06:15 +08:00
|
|
|
titleKey: string
|
|
|
|
|
descriptionKey: string
|
2026-04-09 10:01:23 +08:00
|
|
|
link: string
|
|
|
|
|
icon: typeof BotMessageSquareIcon
|
|
|
|
|
format?: (value: number) => string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const cards: SummaryCardItem[] = [
|
|
|
|
|
{
|
|
|
|
|
key: "todayNewConversations",
|
2026-05-25 12:06:15 +08:00
|
|
|
titleKey: "dashboardHome.summaryTodayNewConversations",
|
|
|
|
|
descriptionKey: "dashboardHome.summaryTodayNewConversationsDescription",
|
2026-05-09 21:34:54 +08:00
|
|
|
link: "/dashboard/conversations",
|
2026-04-09 10:01:23 +08:00
|
|
|
icon: BotMessageSquareIcon,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
key: "processingConversations",
|
2026-05-25 12:06:15 +08:00
|
|
|
titleKey: "dashboardHome.summaryProcessingConversations",
|
|
|
|
|
descriptionKey: "dashboardHome.summaryProcessingConversationsDescription",
|
2026-05-09 21:34:54 +08:00
|
|
|
link: "/dashboard/conversations",
|
2026-04-09 10:01:23 +08:00
|
|
|
icon: WavesIcon,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
key: "pendingDispatchConversations",
|
2026-05-25 12:06:15 +08:00
|
|
|
titleKey: "dashboardHome.summaryPendingDispatchConversations",
|
|
|
|
|
descriptionKey: "dashboardHome.summaryPendingDispatchConversationsDescription",
|
2026-05-09 21:34:54 +08:00
|
|
|
link: "/dashboard/conversations",
|
2026-04-09 10:01:23 +08:00
|
|
|
icon: CircleDashedIcon,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
key: "onlineAgents",
|
2026-05-25 12:06:15 +08:00
|
|
|
titleKey: "dashboardHome.summaryOnlineAgents",
|
|
|
|
|
descriptionKey: "dashboardHome.summaryOnlineAgentsDescription",
|
2026-05-09 21:34:54 +08:00
|
|
|
link: "/dashboard/agents",
|
2026-04-09 10:01:23 +08:00
|
|
|
icon: HeadsetIcon,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
key: "aiServiceRate",
|
2026-05-25 12:06:15 +08:00
|
|
|
titleKey: "dashboardHome.summaryAiServiceRate",
|
|
|
|
|
descriptionKey: "dashboardHome.summaryAiServiceRateDescription",
|
2026-05-09 21:34:54 +08:00
|
|
|
link: "/dashboard/ai-agents",
|
2026-04-09 10:01:23 +08:00
|
|
|
icon: SparklesIcon,
|
|
|
|
|
format: (value: number) => `${value.toFixed(1)}%`,
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
export function SummaryCards({ summary }: SummaryCardsProps) {
|
2026-05-25 12:06:15 +08:00
|
|
|
const t = useI18n()
|
|
|
|
|
|
2026-04-09 10:01:23 +08:00
|
|
|
return (
|
2026-06-21 10:09:52 +08:00
|
|
|
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-5">
|
2026-04-09 10:01:23 +08:00
|
|
|
{cards.map((item) => {
|
|
|
|
|
const Icon = item.icon
|
|
|
|
|
const rawValue = summary[item.key]
|
|
|
|
|
const value =
|
|
|
|
|
typeof item.format === "function"
|
|
|
|
|
? item.format(Number(rawValue))
|
|
|
|
|
: Number(rawValue).toLocaleString()
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Link key={item.key} href={item.link}>
|
2026-06-21 10:09:52 +08:00
|
|
|
<Card className="h-full rounded-md shadow-none transition-colors hover:border-primary/40">
|
|
|
|
|
<CardHeader className="flex flex-row items-start justify-between space-y-0 p-4 pb-2">
|
2026-04-09 10:01:23 +08:00
|
|
|
<div className="space-y-1">
|
2026-05-25 12:06:15 +08:00
|
|
|
<CardTitle className="text-sm font-medium">{t(item.titleKey)}</CardTitle>
|
|
|
|
|
<CardDescription>{t(item.descriptionKey)}</CardDescription>
|
2026-04-09 10:01:23 +08:00
|
|
|
</div>
|
2026-06-21 10:09:52 +08:00
|
|
|
<div className="rounded-md bg-muted p-2 text-muted-foreground">
|
2026-04-09 10:01:23 +08:00
|
|
|
<Icon className="size-4" />
|
|
|
|
|
</div>
|
|
|
|
|
</CardHeader>
|
2026-06-21 10:09:52 +08:00
|
|
|
<CardContent className="px-4 pb-4">
|
|
|
|
|
<div className="text-2xl font-semibold tracking-tight">{value}</div>
|
2026-04-09 10:01:23 +08:00
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
</Link>
|
|
|
|
|
)
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|