116 lines
4.1 KiB
TypeScript
116 lines
4.1 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import React from "react";
|
||
|
|
import { Card, CardContent } from "@/components/ui/card";
|
||
|
|
import { Badge } from "@/components/ui/badge";
|
||
|
|
import { CheckCircle, AlertTriangle, XCircle, Info } from "lucide-react";
|
||
|
|
|
||
|
|
// 타입 import
|
||
|
|
import { MappingInfoPanelProps } from "../types/redesigned";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 📊 매핑 정보 패널
|
||
|
|
* - 실시간 매핑 통계
|
||
|
|
* - 검증 상태 표시
|
||
|
|
* - 예상 처리량 정보
|
||
|
|
*/
|
||
|
|
const MappingInfoPanel: React.FC<MappingInfoPanelProps> = ({ stats, validationErrors }) => {
|
||
|
|
const errorCount = validationErrors.filter((e) => e.type === "error").length;
|
||
|
|
const warningCount = validationErrors.filter((e) => e.type === "warning").length;
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Card>
|
||
|
|
<CardContent className="space-y-3 p-4">
|
||
|
|
{/* 매핑 통계 */}
|
||
|
|
<div className="grid grid-cols-2 gap-2 text-sm">
|
||
|
|
<div className="flex justify-between">
|
||
|
|
<span className="text-muted-foreground">총 매핑:</span>
|
||
|
|
<Badge variant="outline">{stats.totalMappings}개</Badge>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex justify-between">
|
||
|
|
<span className="text-muted-foreground">유효한 매핑:</span>
|
||
|
|
<Badge variant="outline" className="text-green-600">
|
||
|
|
<CheckCircle className="mr-1 h-3 w-3" />
|
||
|
|
{stats.validMappings}개
|
||
|
|
</Badge>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{stats.invalidMappings > 0 && (
|
||
|
|
<div className="flex justify-between">
|
||
|
|
<span className="text-muted-foreground">타입 불일치:</span>
|
||
|
|
<Badge variant="outline" className="text-orange-600">
|
||
|
|
<AlertTriangle className="mr-1 h-3 w-3" />
|
||
|
|
{stats.invalidMappings}개
|
||
|
|
</Badge>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{stats.missingRequiredFields > 0 && (
|
||
|
|
<div className="flex justify-between">
|
||
|
|
<span className="text-muted-foreground">필수 필드 누락:</span>
|
||
|
|
<Badge variant="outline" className="text-red-600">
|
||
|
|
<XCircle className="mr-1 h-3 w-3" />
|
||
|
|
{stats.missingRequiredFields}개
|
||
|
|
</Badge>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 액션 정보 */}
|
||
|
|
{stats.totalMappings > 0 && (
|
||
|
|
<div className="space-y-2 border-t pt-2">
|
||
|
|
<div className="flex justify-between text-sm">
|
||
|
|
<span className="text-muted-foreground">액션:</span>
|
||
|
|
<Badge variant="secondary">{stats.actionType}</Badge>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{stats.estimatedRows > 0 && (
|
||
|
|
<div className="flex justify-between text-sm">
|
||
|
|
<span className="text-muted-foreground">예상 처리량:</span>
|
||
|
|
<span className="font-medium">~{stats.estimatedRows.toLocaleString()} rows</span>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* 검증 오류 요약 */}
|
||
|
|
{validationErrors.length > 0 && (
|
||
|
|
<div className="border-t pt-2">
|
||
|
|
<div className="flex items-center gap-2 text-sm">
|
||
|
|
<Info className="h-4 w-4 text-blue-500" />
|
||
|
|
<span className="text-muted-foreground">검증 결과:</span>
|
||
|
|
</div>
|
||
|
|
<div className="mt-2 space-y-1">
|
||
|
|
{errorCount > 0 && (
|
||
|
|
<Badge variant="destructive" className="text-xs">
|
||
|
|
오류 {errorCount}개
|
||
|
|
</Badge>
|
||
|
|
)}
|
||
|
|
{warningCount > 0 && (
|
||
|
|
<Badge variant="outline" className="ml-1 text-xs text-orange-600">
|
||
|
|
경고 {warningCount}개
|
||
|
|
</Badge>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* 빈 상태 */}
|
||
|
|
{stats.totalMappings === 0 && (
|
||
|
|
<div className="text-muted-foreground py-4 text-center text-sm">
|
||
|
|
<Database className="mx-auto mb-2 h-8 w-8 opacity-50" />
|
||
|
|
<p>아직 매핑된 필드가 없습니다.</p>
|
||
|
|
<p className="mt-1 text-xs">우측에서 연결을 설정해주세요.</p>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
// Database 아이콘 import 추가
|
||
|
|
import { Database } from "lucide-react";
|
||
|
|
|
||
|
|
export default MappingInfoPanel;
|