ERP-node/frontend/lib/registry/pop-components/pop-dashboard/items/StatCard.tsx

96 lines
2.9 KiB
TypeScript
Raw Normal View History

"use client";
/**
*
*
* (// )
*
*/
import React from "react";
import type { DashboardItem } from "../../types";
import { TEXT_ALIGN_CLASSES } from "../../types";
import { abbreviateNumber } from "../utils/formula";
// ===== Props =====
export interface StatCardProps {
item: DashboardItem;
/** 카테고리별 건수 맵 (카테고리 label -> 건수) */
categoryData: Record<string, number>;
}
// ===== 기본 색상 팔레트 =====
const DEFAULT_STAT_COLORS = [
"#6366f1", // indigo
"#f59e0b", // amber
"#10b981", // emerald
"#ef4444", // rose
"#8b5cf6", // violet
];
// ===== 메인 컴포넌트 =====
export function StatCardComponent({ item, categoryData }: StatCardProps) {
const { visibility, statConfig, itemStyle } = item;
const categories = statConfig?.categories ?? [];
const total = Object.values(categoryData).reduce((sum, v) => sum + v, 0);
// 라벨 정렬만 사용자 설정
const labelAlignClass = TEXT_ALIGN_CLASSES[itemStyle?.labelAlign ?? "center"];
return (
<div className="@container flex h-full w-full flex-col items-center justify-center p-3">
{/* 라벨 - 사용자 정렬 적용 */}
{visibility.showLabel && (
<p className={`w-full mb-1 text-muted-foreground text-xs @[250px]:text-sm ${labelAlignClass}`}>
{item.label}
</p>
)}
{/* 총합 - @container 반응형 */}
{visibility.showValue && (
<p className="mb-2 text-lg font-bold @[200px]:text-2xl @[350px]:text-3xl">
{abbreviateNumber(total)}
</p>
)}
{/* 카테고리별 건수 */}
<div className="flex flex-wrap gap-2 @[200px]:gap-3">
{categories.map((cat, index) => {
const count = categoryData[cat.label] ?? 0;
const color =
cat.color ?? DEFAULT_STAT_COLORS[index % DEFAULT_STAT_COLORS.length];
return (
<div key={cat.label} className="flex items-center gap-1">
{/* 색상 점 */}
<span
className="inline-block h-2 w-2 rounded-full @[200px]:h-2.5 @[200px]:w-2.5"
style={{ backgroundColor: color }}
/>
{/* 라벨 + 건수 */}
<span className="text-[10px] text-muted-foreground @[150px]:text-xs">
{cat.label}
</span>
<span className="text-[10px] font-medium @[150px]:text-xs">
{abbreviateNumber(count)}
</span>
</div>
);
})}
</div>
{/* 보조 라벨 (단위 등) */}
{visibility.showSubLabel && (
<p className="mt-1 text-[10px] text-muted-foreground @[150px]:text-xs">
{visibility.showUnit && item.kpiConfig?.unit
? `단위: ${item.kpiConfig.unit}`
: ""}
</p>
)}
</div>
);
}