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

153 lines
4.0 KiB
TypeScript

"use client";
/**
* 차트 서브타입 컴포넌트
*
* Recharts 기반 막대/원형/라인 차트
* 컨테이너 크기가 너무 작으면 "차트 표시 불가" 메시지
*/
import React from "react";
import {
BarChart,
Bar,
PieChart,
Pie,
Cell,
LineChart,
Line,
XAxis,
YAxis,
Tooltip,
ResponsiveContainer,
} from "recharts";
import type { DashboardItem } from "../../types";
// ===== Props =====
export interface ChartItemProps {
item: DashboardItem;
/** 차트에 표시할 데이터 행 */
rows: Record<string, unknown>[];
/** 컨테이너 너비 (px) - 최소 크기 판단용 */
containerWidth: number;
}
// ===== 기본 색상 팔레트 =====
const DEFAULT_COLORS = [
"#6366f1", // indigo
"#8b5cf6", // violet
"#06b6d4", // cyan
"#10b981", // emerald
"#f59e0b", // amber
"#ef4444", // rose
"#ec4899", // pink
"#14b8a6", // teal
];
// ===== 최소 표시 크기 =====
const MIN_CHART_WIDTH = 120;
// ===== 메인 컴포넌트 =====
export function ChartItemComponent({
item,
rows,
containerWidth,
}: ChartItemProps) {
const { chartConfig, visibility } = item;
const chartType = chartConfig?.chartType ?? "bar";
const colors = chartConfig?.colors?.length
? chartConfig.colors
: DEFAULT_COLORS;
const xKey = chartConfig?.xAxisColumn ?? "name";
const yKey = chartConfig?.yAxisColumn ?? "value";
// 컨테이너가 너무 작으면 메시지 표시
if (containerWidth < MIN_CHART_WIDTH) {
return (
<div className="flex h-full w-full items-center justify-center p-1">
<span className="text-[10px] text-muted-foreground"></span>
</div>
);
}
// 데이터 없음
if (!rows.length) {
return (
<div className="flex h-full w-full items-center justify-center">
<span className="text-xs text-muted-foreground"> </span>
</div>
);
}
return (
<div className="@container flex h-full w-full flex-col p-1">
{/* 라벨 */}
{visibility.showLabel && (
<p className="mb-1 truncate text-[10px] text-muted-foreground @[200px]:text-xs">
{item.label}
</p>
)}
{/* 차트 영역 */}
<div className="min-h-0 flex-1">
<ResponsiveContainer width="100%" height="100%">
{chartType === "bar" ? (
<BarChart data={rows as Record<string, string | number>[]}>
<XAxis
dataKey={xKey}
tick={{ fontSize: 10 }}
hide={containerWidth < 200}
/>
<YAxis tick={{ fontSize: 10 }} hide={containerWidth < 200} />
<Tooltip />
<Bar dataKey={yKey} fill={colors[0]} radius={[2, 2, 0, 0]} />
</BarChart>
) : chartType === "line" ? (
<LineChart data={rows as Record<string, string | number>[]}>
<XAxis
dataKey={xKey}
tick={{ fontSize: 10 }}
hide={containerWidth < 200}
/>
<YAxis tick={{ fontSize: 10 }} hide={containerWidth < 200} />
<Tooltip />
<Line
type="monotone"
dataKey={yKey}
stroke={colors[0]}
strokeWidth={2}
dot={containerWidth > 250}
/>
</LineChart>
) : (
/* pie */
<PieChart>
<Pie
data={rows as Record<string, string | number>[]}
dataKey={yKey}
nameKey={xKey}
cx="50%"
cy="50%"
outerRadius="80%"
label={containerWidth > 250}
>
{rows.map((_, index) => (
<Cell
key={`cell-${index}`}
fill={colors[index % colors.length]}
/>
))}
</Pie>
<Tooltip />
</PieChart>
)}
</ResponsiveContainer>
</div>
</div>
);
}