From cbb4c7fe0b94459162ad5e998bc05cd293e0ff96 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Mon, 11 Aug 2025 09:02:00 +0000
Subject: (대표님) 입찰, EDP 변경사항 대응, spreadJS 오류 수정, 벤더실사 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/form-data/sedp-compare-dialog.tsx | 233 ++++++++++++++-------------
 1 file changed, 121 insertions(+), 112 deletions(-)

(limited to 'components/form-data/sedp-compare-dialog.tsx')

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>
-- 
cgit v1.2.3

