summaryrefslogtreecommitdiff
path: root/components/form-data/sedp-compare-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'components/form-data/sedp-compare-dialog.tsx')
-rw-r--r--components/form-data/sedp-compare-dialog.tsx233
1 files changed, 121 insertions, 112 deletions
diff --git a/components/form-data/sedp-compare-dialog.tsx b/components/form-data/sedp-compare-dialog.tsx
index 647f2810..1a9938bd 100644
--- a/components/form-data/sedp-compare-dialog.tsx
+++ b/components/form-data/sedp-compare-dialog.tsx
@@ -11,6 +11,8 @@ import { DataTableColumnJSON } from "./form-data-table-columns";
import { ExcelDownload } from "./sedp-excel-download";
import { Switch } from "../ui/switch";
import { Card, CardContent } from "@/components/ui/card";
+import { useTranslation } from "@/i18n/client"
+import { useParams } from "next/navigation"
interface SEDPCompareDialogProps {
isOpen: boolean;
@@ -56,85 +58,6 @@ const DisplayValue = ({ value, uom, isSedp = false }: { value: any; uom?: string
);
};
-// 범례 컴포넌트
-const ColorLegend = () => {
- return (
- <div className="flex items-center gap-4 text-sm p-2 bg-muted/20 rounded">
- <div className="flex items-center gap-1.5">
- <Info className="h-4 w-4 text-muted-foreground" />
- <span className="font-medium">범례:</span>
- </div>
- <div className="flex items-center gap-3">
- <div className="flex items-center gap-1.5">
- <div className="h-3 w-3 rounded-full bg-red-500"></div>
- <span className="line-through text-red-500">로컬 값</span>
- </div>
- <div className="flex items-center gap-1.5">
- <div className="h-3 w-3 rounded-full bg-green-500"></div>
- <span className="text-green-500">SEDP 값</span>
- </div>
- </div>
- </div>
- );
-};
-
-// 확장 가능한 차이점 표시 컴포넌트
-const DifferencesCard = ({
- attributes,
- columnLabelMap,
- showOnlyDifferences
-}: {
- attributes: ComparisonResult['attributes'];
- columnLabelMap: Record<string, string>;
- showOnlyDifferences: boolean;
-}) => {
- const attributesToShow = showOnlyDifferences
- ? attributes.filter(attr => !attr.isMatching)
- : attributes;
-
- if (attributesToShow.length === 0) {
- return (
- <div className="text-center text-muted-foreground py-4">
- 모든 속성이 일치합니다
- </div>
- );
- }
-
- return (
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3 p-4">
- {attributesToShow.map((attr) => (
- <Card key={attr.key} className={`${!attr.isMatching ? 'border-red-200' : 'border-green-200'}`}>
- <CardContent className="p-3">
- <div className="font-medium text-sm mb-2 truncate" title={attr.label}>
- {attr.label}
- {attr.uom && <span className="text-xs text-muted-foreground ml-1">({attr.uom})</span>}
- </div>
- {attr.isMatching ? (
- <div className="text-sm">
- <DisplayValue value={attr.localValue} uom={attr.uom} />
- </div>
- ) : (
- <div className="space-y-2">
- <div className="flex items-center gap-2 text-sm">
- <span className="text-xs text-muted-foreground min-w-[35px]">로컬:</span>
- <span className="line-through text-red-500 flex-1">
- <DisplayValue value={attr.localValue} uom={attr.uom} isSedp={false} />
- </span>
- </div>
- <div className="flex items-center gap-2 text-sm">
- <span className="text-xs text-muted-foreground min-w-[35px]">SEDP:</span>
- <span className="text-green-500 flex-1">
- <DisplayValue value={attr.sedpValue} uom={attr.uom} isSedp={true} />
- </span>
- </div>
- </div>
- )}
- </CardContent>
- </Card>
- ))}
- </div>
- );
-};
export function SEDPCompareDialog({
isOpen,
@@ -145,6 +68,92 @@ export function SEDPCompareDialog({
formCode,
fetchTagDataFromSEDP,
}: SEDPCompareDialogProps) {
+
+ const params = useParams() || {}
+ const lng = params.lng ? String(params.lng) : "ko"
+ const { t } = useTranslation(lng, "engineering")
+
+ // 범례 컴포넌트
+ const ColorLegend = () => {
+ return (
+ <div className="flex items-center gap-4 text-sm p-2 bg-muted/20 rounded">
+ <div className="flex items-center gap-1.5">
+ <Info className="h-4 w-4 text-muted-foreground" />
+ <span className="font-medium">{t("labels.legend")}:</span>
+ </div>
+ <div className="flex items-center gap-3">
+ <div className="flex items-center gap-1.5">
+ <div className="h-3 w-3 rounded-full bg-red-500"></div>
+ <span className="line-through text-red-500">{t("labels.localValue")}</span>
+ </div>
+ <div className="flex items-center gap-1.5">
+ <div className="h-3 w-3 rounded-full bg-green-500"></div>
+ <span className="text-green-500">{t("labels.sedpValue")}</span>
+ </div>
+ </div>
+ </div>
+ );
+ };
+
+ // 확장 가능한 차이점 표시 컴포넌트
+ const DifferencesCard = ({
+ attributes,
+ columnLabelMap,
+ showOnlyDifferences
+ }: {
+ attributes: ComparisonResult['attributes'];
+ columnLabelMap: Record<string, string>;
+ showOnlyDifferences: boolean;
+ }) => {
+ const attributesToShow = showOnlyDifferences
+ ? attributes.filter(attr => !attr.isMatching)
+ : attributes;
+
+ if (attributesToShow.length === 0) {
+ return (
+ <div className="text-center text-muted-foreground py-4">
+ {t("messages.allAttributesMatch")}
+ </div>
+ );
+ }
+
+ return (
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3 p-4">
+ {attributesToShow.map((attr) => (
+ <Card key={attr.key} className={`${!attr.isMatching ? 'border-red-200' : 'border-green-200'}`}>
+ <CardContent className="p-3">
+ <div className="font-medium text-sm mb-2 truncate" title={attr.label}>
+ {attr.label}
+ {attr.uom && <span className="text-xs text-muted-foreground ml-1">({attr.uom})</span>}
+ </div>
+ {attr.isMatching ? (
+ <div className="text-sm">
+ <DisplayValue value={attr.localValue} uom={attr.uom} />
+ </div>
+ ) : (
+ <div className="space-y-2">
+ <div className="flex items-center gap-2 text-sm">
+ <span className="text-xs text-muted-foreground min-w-[35px]">로컬:</span>
+ <span className="line-through text-red-500 flex-1">
+ <DisplayValue value={attr.localValue} uom={attr.uom} isSedp={false} />
+ </span>
+ </div>
+ <div className="flex items-center gap-2 text-sm">
+ <span className="text-xs text-muted-foreground min-w-[35px]">SEDP:</span>
+ <span className="text-green-500 flex-1">
+ <DisplayValue value={attr.sedpValue} uom={attr.uom} isSedp={true} />
+ </span>
+ </div>
+ </div>
+ )}
+ </CardContent>
+ </Card>
+ ))}
+ </div>
+ );
+ };
+
+
const [isLoading, setIsLoading] = React.useState(false);
const [comparisonResults, setComparisonResults] = React.useState<ComparisonResult[]>([]);
const [activeTab, setActiveTab] = React.useState("all");
@@ -181,7 +190,7 @@ export function SEDPCompareDialog({
// Filter and search results
const filteredResults = React.useMemo(() => {
let results = comparisonResults;
-
+
// Filter by tab
switch (activeTab) {
case "matching":
@@ -198,8 +207,8 @@ export function SEDPCompareDialog({
// Apply search filter
if (searchTerm.trim()) {
const search = searchTerm.toLowerCase();
- results = results.filter(r =>
- r.tagNo.toLowerCase().includes(search) ||
+ results = results.filter(r =>
+ r.tagNo.toLowerCase().includes(search) ||
r.tagDesc.toLowerCase().includes(search)
);
}
@@ -291,7 +300,7 @@ export function SEDPCompareDialog({
// Compare attributes
const attributeComparisons = columnsJSON
- .filter(col => col.key !== "TAG_NO" && col.key !== "TAG_DESC"&& col.key !== "status")
+ .filter(col => col.key !== "TAG_NO" && col.key !== "TAG_DESC" && col.key !== "status")
.map(col => {
const localValue = localItem[col.key];
const sedpValue = sedpItem.attributes.get(col.key);
@@ -370,7 +379,7 @@ export function SEDPCompareDialog({
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="max-w-6xl max-h-[90vh] overflow-hidden flex flex-col">
<DialogHeader>
- <DialogTitle className="mb-2">SEDP 데이터 비교</DialogTitle>
+ <DialogTitle className="mb-2">{t("dialogs.sedpDataComparison")}</DialogTitle>
<div className="flex items-center justify-between gap-2 pr-8">
<div className="flex items-center gap-4">
<div className="flex items-center gap-2">
@@ -380,22 +389,22 @@ export function SEDPCompareDialog({
id="show-differences"
/>
<label htmlFor="show-differences" className="text-sm cursor-pointer">
- 차이가 있는 항목만 표시
+ {t("switches.showOnlyDifferences")}
</label>
</div>
-
+
{/* 검색 입력 */}
<div className="relative">
<Search className="absolute left-2 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<Input
- placeholder="태그 번호 또는 설명 검색..."
+ placeholder={t("placeholders.searchTagOrDesc")}
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="pl-8 w-64"
/>
</div>
</div>
-
+
<div className="flex items-center gap-2">
<Badge variant={matchingTags === totalTags && totalMissingTags === 0 ? "default" : "destructive"}>
{matchingTags} / {totalTags} 일치 {totalMissingTags > 0 ? `(${totalMissingTags} 누락)` : ''}
@@ -411,7 +420,7 @@ export function SEDPCompareDialog({
) : (
<RefreshCw className="h-4 w-4" />
)}
- <span className="ml-2">새로고침</span>
+ <span className="ml-2">{t("buttons.refresh")}</span>
</Button>
</div>
</div>
@@ -424,11 +433,11 @@ export function SEDPCompareDialog({
<Tabs value={activeTab} onValueChange={setActiveTab} className="flex-1 flex flex-col overflow-hidden">
<TabsList>
- <TabsTrigger value="all">전체 태그 ({totalTags})</TabsTrigger>
- <TabsTrigger value="differences">차이 있음 ({nonMatchingTags})</TabsTrigger>
- <TabsTrigger value="matching">일치함 ({matchingTags})</TabsTrigger>
+ <TabsTrigger value="all">{t("tabs.allTags")} ({totalTags})</TabsTrigger>
+ <TabsTrigger value="differences">{t("tabs.differences")} ({nonMatchingTags})</TabsTrigger>
+ <TabsTrigger value="matching">{t("tabs.matching")} ({matchingTags})</TabsTrigger>
<TabsTrigger value="missing" className={totalMissingTags > 0 ? "text-red-500" : ""}>
- 누락된 태그 ({totalMissingTags})
+ {t("tabs.missingTags")} ({totalMissingTags})
</TabsTrigger>
</TabsList>
@@ -436,19 +445,19 @@ export function SEDPCompareDialog({
{isLoading ? (
<div className="flex items-center justify-center h-full">
<Loader className="h-8 w-8 animate-spin mr-2" />
- <span>데이터 비교 중...</span>
+ <span>{t("messages.dataComparing")}</span>
</div>
) : activeTab === "missing" ? (
// Missing tags tab content
<div className="space-y-6">
{missingTags.localOnly.length > 0 && (
<div>
- <h3 className="text-sm font-medium mb-2">로컬에만 있는 태그 ({missingTags.localOnly.length})</h3>
+ <h3 className="text-sm font-medium mb-2">{t("sections.localOnlyTags")} ({missingTags.localOnly.length})</h3>
<Table>
<TableHeader className="sticky top-0 bg-background z-10">
<TableRow>
- <TableHead className="w-[180px]">Tag Number</TableHead>
- <TableHead>Tag Description</TableHead>
+ <TableHead className="w-[180px]">{t("labels.tagNo")}</TableHead>
+ <TableHead>{t("labels.description")}</TableHead>
</TableRow>
</TableHeader>
<TableBody>
@@ -465,12 +474,12 @@ export function SEDPCompareDialog({
{missingTags.sedpOnly.length > 0 && (
<div>
- <h3 className="text-sm font-medium mb-2">SEDP에만 있는 태그 ({missingTags.sedpOnly.length})</h3>
+ <h3 className="text-sm font-medium mb-2">{t("sections.sedpOnlyTags")} ({missingTags.sedpOnly.length})</h3>
<Table>
<TableHeader className="sticky top-0 bg-background z-10">
<TableRow>
- <TableHead className="w-[180px]">Tag Number</TableHead>
- <TableHead>Tag Description</TableHead>
+ <TableHead className="w-[180px]">{t("labels.tagNo")}</TableHead>
+ <TableHead>{t("labels.description")}</TableHead>
</TableRow>
</TableHeader>
<TableBody>
@@ -487,7 +496,7 @@ export function SEDPCompareDialog({
{totalMissingTags === 0 && (
<div className="flex items-center justify-center h-full text-muted-foreground">
- 모든 태그가 양쪽 시스템에 존재합니다
+ {t("messages.allTagsExistInBothSystems")}
</div>
)}
</div>
@@ -498,9 +507,9 @@ export function SEDPCompareDialog({
<TableHeader className="sticky top-0 bg-muted/50 z-10">
<TableRow>
<TableHead className="w-12"></TableHead>
- <TableHead className="w-[180px]">Tag Number</TableHead>
- <TableHead className="w-[250px]">Tag Description</TableHead>
- <TableHead className="w-[120px]">상태</TableHead>
+ <TableHead className="w-[180px]">{t("labels.tagNo")}</TableHead>
+ <TableHead className="w-[250px]">{t("labels.description")}</TableHead>
+ <TableHead className="w-[120px]">{t("labels.status")}</TableHead>
<TableHead>차이점 개수</TableHead>
</TableRow>
</TableHeader>
@@ -508,7 +517,7 @@ export function SEDPCompareDialog({
{filteredResults.map((result) => (
<React.Fragment key={result.tagNo}>
{/* 메인 행 */}
- <TableRow
+ <TableRow
className={`hover:bg-muted/20 cursor-pointer ${!result.isMatching ? "bg-muted/10" : ""}`}
onClick={() => toggleRowExpansion(result.tagNo)}
>
@@ -533,29 +542,29 @@ export function SEDPCompareDialog({
{result.isMatching ? (
<Badge variant="default" className="flex items-center gap-1">
<CheckCircle className="h-3 w-3" />
- <span>일치</span>
+ <span>{t("labels.matching")}</span>
</Badge>
) : (
<Badge variant="destructive" className="flex items-center gap-1">
<AlertCircle className="h-3 w-3" />
- <span>차이</span>
+ <span>{t("labels.different")}</span>
</Badge>
)}
</TableCell>
<TableCell>
{!result.isMatching && (
<span className="text-sm text-muted-foreground">
- {result.attributes.filter(attr => !attr.isMatching).length}개 속성이 다름
+ {result.attributes.filter(attr => !attr.isMatching).length}{t("sections.differenceCount")}
</span>
)}
</TableCell>
</TableRow>
-
+
{/* 확장된 차이점 표시 행 */}
{expandedRows.has(result.tagNo) && (
<TableRow>
<TableCell colSpan={5} className="p-0 bg-muted/5">
- <DifferencesCard
+ <DifferencesCard
attributes={result.attributes}
columnLabelMap={columnLabelMap}
showOnlyDifferences={showOnlyDifferences}
@@ -570,7 +579,7 @@ export function SEDPCompareDialog({
</div>
) : (
<div className="flex items-center justify-center h-full text-muted-foreground">
- {searchTerm ? "검색 결과가 없습니다" : "현재 필터에 맞는 태그가 없습니다"}
+ {searchTerm ? t("messages.noSearchResults") : t("messages.noMatchingTags")}
</div>
)}
</TabsContent>
@@ -583,7 +592,7 @@ export function SEDPCompareDialog({
formCode={formCode}
disabled={isLoading || (nonMatchingTags === 0 && totalMissingTags === 0)}
/>
- <Button onClick={onClose}>닫기</Button>
+ <Button onClick={onClose}>{t("buttons.close")}</Button>
</DialogFooter>
</DialogContent>
</Dialog>