'use client'; /* IMPORT */ import { Bar, BarChart, Cell, LabelList, XAxis, YAxis } from 'recharts'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'; import { getRisksViewCount } from '../service'; import { LoaderCircle } from 'lucide-react'; import { type DateRange } from 'react-day-picker'; import { useEffect, useState, useMemo, useCallback } from 'react'; import { useParams, useRouter, useSearchParams } from 'next/navigation'; import { ValueType } from 'recharts/types/component/DefaultTooltipContent'; // ---------------------------------------------------------------------------------------------------- /* TYPES */ interface RisksDashboardProps { targetValues: string[]; defaultDateRange: DateRange; } interface CountData { [key: string]: number; } interface ChartData { name: string; count: number; color: string; } // ---------------------------------------------------------------------------------------------------- /* RISKS DASHBOARD COMPONENT */ function RisksDashboard(props: RisksDashboardProps) { const { targetValues, defaultDateRange } = props; const router = useRouter(); const searchParams = useSearchParams(); const params = useParams(); const [counts, setCounts] = useState({}); const [isLoading, setIsLoading] = useState(true); const [dateQuery, setDateQuery] = useState({ from: defaultDateRange.from?.toISOString() ?? '', to: defaultDateRange.to?.toISOString() ?? '', search: '', }); const language = params?.lng as string; const chartData: ChartData[] = useMemo(() => { const chartItems = ['단기연체', '노무비체불', '세금체납', '채무불이행', '행정처분', '당좌거래정지', '기업회생', '휴/폐업']; const colors = [ '#22c55e', '#6dd85d', '#b4e85b', '#f0f06d', '#fce46d', '#fcb36d', '#f98b6d', '#ef4444', ]; return chartItems.map((item, index) => ({ name: item, count: counts[item] ?? 0, color: colors[index], })); }, [counts]); const chartConfig: ChartConfig = { count: { label: '건수', }, }; const fetchAllCounts = useCallback(async () => { if (!dateQuery.from || !dateQuery.to) { return; } setIsLoading(true); try { const countPromises = targetValues.map(async (targetValue) => { const filters = [ { id: 'eventType', value: targetValue, type: 'text', operator: 'iLike', rowId: '', } ]; const searchParams = { filters, joinOperator: 'and', from: dateQuery.from, to: dateQuery.to, search: dateQuery.search, flags: [], page: 1, perPage: 10, sort: [{ id: 'occuredAt', desc: true }], }; const { count } = await getRisksViewCount(searchParams as any); return { targetValue, count }; }); const results = await Promise.all(countPromises); const newCounts: CountData = {}; results.forEach(({ targetValue, count }) => { newCounts[targetValue] = count; }); setCounts(newCounts); } catch (error) { console.error('리스크 데이터 개수 조회에 실패했습니다:', error); const resetCounts: CountData = {}; targetValues.forEach(value => { resetCounts[value] = 0; }); setCounts(resetCounts); } finally { setIsLoading(false); } }, [dateQuery, targetValues]); useEffect(() => { const urlParams = new URLSearchParams(searchParams?.toString()); const from = urlParams.get('from') ?? defaultDateRange.from?.toISOString() ?? ''; const to = urlParams.get('to') ?? defaultDateRange.to?.toISOString() ?? ''; const search = urlParams.get('search') ?? ''; setDateQuery((prev) => { if (prev.from === from && prev.to === to && prev.search === search) { return prev; } return { from, to, search }; }); }, [searchParams, defaultDateRange]); useEffect(() => { fetchAllCounts(); }, [fetchAllCounts]); const handleButtonClick = useCallback((targetValue: string) => { const newFilters = [ { id: 'eventType', value: targetValue, type: 'text', operator: 'iLike', rowId: '', } ]; const newUrlParams = new URLSearchParams(searchParams?.toString()); newUrlParams.set('filters', JSON.stringify(newFilters)); const baseUrl = `/${language}/evcp/risk-management`; const fullUrl = `${baseUrl}?${newUrlParams.toString()}`; const decodedUrl = decodeURIComponent(fullUrl); router.push(decodedUrl); router.refresh(); }, [searchParams, language, router]); return (
{targetValues.map((targetValue) => (
{targetValue}
))}
주요 리스크 현황 {chartData.filter(item => item.count > 0).length === 0 ? (
주요 리스크가 존재하지 않습니다.
) : ( item.count > 0)} layout="vertical" margin={{ left: 30, right: 30 }} > } formatter={(value) => [`${value}건`]} /> [`${value}건`]} /> {chartData.map((entry, index) => ( ))} )}
); } // ---------------------------------------------------------------------------------------------------- /* EXPORT */ export default RisksDashboard;