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

---
 .../ship/send-to-shi-button.tsx                    | 127 ++++++++++++---------
 1 file changed, 74 insertions(+), 53 deletions(-)

(limited to 'lib/vendor-document-list/ship/send-to-shi-button.tsx')

diff --git a/lib/vendor-document-list/ship/send-to-shi-button.tsx b/lib/vendor-document-list/ship/send-to-shi-button.tsx
index 7236dfde..447b461b 100644
--- a/lib/vendor-document-list/ship/send-to-shi-button.tsx
+++ b/lib/vendor-document-list/ship/send-to-shi-button.tsx
@@ -26,6 +26,8 @@ import { Alert, AlertDescription } from "@/components/ui/alert"
 // ✅ 업데이트된 Hook import
 import { useClientSyncStatus, useTriggerSync, syncUtils } from "@/hooks/use-sync-status"
 import type { EnhancedDocument } from "@/types/enhanced-documents"
+import { useParams } from "next/navigation"
+import { useTranslation } from "@/i18n/client"
 
 interface SendToSHIButtonProps {
   documents?: EnhancedDocument[]
@@ -42,6 +44,10 @@ export function SendToSHIButton({
   const [syncProgress, setSyncProgress] = React.useState(0)
   const [currentSyncingContract, setCurrentSyncingContract] = React.useState<number | null>(null)
 
+  const params = useParams()
+  const lng = (params?.lng as string) || "ko"
+  const { t } = useTranslation(lng, "engineering")
+
   const targetSystem = projectType === 'ship' ? "DOLCE" : "SWP"
   
   // 문서에서 유효한 계약 ID 목록 추출 (projectId 사용)
@@ -80,7 +86,7 @@ export function SendToSHIButton({
   // 동기화 실행 함수
   const handleSync = async () => {
     if (documentsContractIds.length === 0) {
-      toast.info('동기화할 계약이 없습니다.')
+      toast.info(t('shiSync.messages.noContractsToSync'))
       return
     }
     
@@ -105,7 +111,7 @@ export function SendToSHIButton({
       })
 
       if (contractsToSync.length === 0) {
-        toast.info('동기화할 변경사항이 없습니다.')
+        toast.info(t('shiSync.messages.noPendingChanges'))
         setIsDialogOpen(false)
         return
       }
@@ -132,13 +138,13 @@ export function SendToSHIButton({
             failedSyncs++
             totalFailureCount += result?.failureCount || 0
             const errorMsg = result?.errors?.[0] || result?.message || 'Unknown sync error'
-            errors.push(`Contract ${projectId}: ${errorMsg}`)
+            errors.push(t('shiSync.messages.contractError', { projectId, error: errorMsg }))
             console.error(`Contract ${projectId} sync failed:`, result)
           }
         } catch (error) {
           failedSyncs++
-          const errorMessage = error instanceof Error ? error.message : '알 수 없는 오류'
-          errors.push(`Contract ${projectId}: ${errorMessage}`)
+          const errorMessage = error instanceof Error ? error.message : t('shiSync.messages.unknownError')
+          errors.push(t('shiSync.messages.contractError', { projectId, error: errorMessage }))
           console.error(`Contract ${projectId} sync exception:`, error)
         }
 
@@ -155,23 +161,30 @@ export function SendToSHIButton({
         
         if (failedSyncs === 0) {
           toast.success(
-            `모든 계약 동기화 완료: ${totalSuccessCount}건 성공`,
+            t('shiSync.messages.allSyncCompleted', { successCount: totalSuccessCount }),
             {
-              description: `${successfulSyncs}개 계약에서 ${totalSuccessCount}개 항목이 SHI 시스템으로 전송되었습니다.`
+              description: t('shiSync.messages.allSyncCompletedDescription', {
+                contractCount: successfulSyncs,
+                itemCount: totalSuccessCount
+              })
             }
           )
         } else if (successfulSyncs > 0) {
           toast.warning(
-            `부분 동기화 완료: ${successfulSyncs}개 성공, ${failedSyncs}개 실패`,
+            t('shiSync.messages.partialSyncCompleted', { 
+              successfulCount: successfulSyncs, 
+              failedCount: failedSyncs 
+            }),
             {
-              description: errors.slice(0, 3).join(', ') + (errors.length > 3 ? ' 외 더보기...' : '')
+              description: errors.slice(0, 3).join(', ') + 
+                (errors.length > 3 ? t('shiSync.messages.andMore') : '')
             }
           )
         } else {
           toast.error(
-            `동기화 실패: ${failedSyncs}개 계약 모두 실패`,
+            t('shiSync.messages.allSyncFailed', { failedCount: failedSyncs }),
             {
-              description: errors[0] || '모든 계약 동기화에 실패했습니다.'
+              description: errors[0] || t('shiSync.messages.allContractsSyncFailed')
             }
           )
         }
@@ -186,7 +199,7 @@ export function SendToSHIButton({
       setCurrentSyncingContract(null)
       
       const errorMessage = syncUtils.formatError(error as Error)
-      toast.error('동기화 실패', {
+      toast.error(t('shiSync.messages.syncFailed'), {
         description: errorMessage
       })
       console.error('Sync process failed:', error)
@@ -199,7 +212,7 @@ export function SendToSHIButton({
       return (
         <Badge variant="secondary" className="gap-1">
           <Loader2 className="w-3 h-3 animate-spin" />
-          확인 중...
+          {t('shiSync.status.checking')}
         </Badge>
       )
     }
@@ -208,20 +221,20 @@ export function SendToSHIButton({
       return (
         <Badge variant="destructive" className="gap-1">
           <AlertTriangle className="w-3 h-3" />
-          연결 오류
+          {t('shiSync.status.connectionError')}
         </Badge>
       )
     }
 
     if (documentsContractIds.length === 0) {
-      return <Badge variant="secondary">계약 없음</Badge>
+      return <Badge variant="secondary">{t('shiSync.status.noContracts')}</Badge>
     }
 
     if (totalStats.totalPending > 0) {
       return (
         <Badge variant="destructive" className="gap-1">
           <AlertTriangle className="w-3 h-3" />
-          {totalStats.totalPending}건 대기
+          {t('shiSync.status.pendingItems', { count: totalStats.totalPending })}
         </Badge>
       )
     }
@@ -230,12 +243,12 @@ export function SendToSHIButton({
       return (
         <Badge variant="default" className="gap-1 bg-green-500 hover:bg-green-600">
           <CheckCircle className="w-3 h-3" />
-          동기화됨
+          {t('shiSync.status.synchronized')}
         </Badge>
       )
     }
 
-    return <Badge variant="secondary">변경사항 없음</Badge>
+    return <Badge variant="secondary">{t('shiSync.status.noChanges')}</Badge>
   }
 
   return (
@@ -254,7 +267,7 @@ export function SendToSHIButton({
               ) : (
                 <Send className="w-4 h-4" />
               )}
-              <span className="hidden sm:inline">Send to SHI</span>
+              <span className="hidden sm:inline">{t('shiSync.buttons.sendToSHI')}</span>
               {totalStats.totalPending > 0 && (
                 <Badge 
                   variant="destructive" 
@@ -271,7 +284,7 @@ export function SendToSHIButton({
           <div className="space-y-4">
             <div className="space-y-2">
               <div className="flex items-center justify-between">
-                <h4 className="font-medium">SHI 동기화 상태</h4>
+                <h4 className="font-medium">{t('shiSync.labels.syncStatus')}</h4>
                 <Button
                   variant="ghost"
                   size="sm"
@@ -288,12 +301,15 @@ export function SendToSHIButton({
               </div>
               
               <div className="flex items-center justify-between">
-                <span className="text-sm text-muted-foreground">전체 상태</span>
+                <span className="text-sm text-muted-foreground">{t('shiSync.labels.overallStatus')}</span>
                 {getSyncStatusBadge()}
               </div>
               
               <div className="text-xs text-muted-foreground">
-                {documentsContractIds.length}개 계약 대상 • {targetSystem} 시스템
+                {t('shiSync.descriptions.targetInfo', { 
+                  contractCount: documentsContractIds.length, 
+                  targetSystem 
+                })}
               </div>
             </div>
 
@@ -302,10 +318,12 @@ export function SendToSHIButton({
               <Alert variant="destructive">
                 <AlertTriangle className="h-4 w-4" />
                 <AlertDescription>
-                  일부 계약의 동기화 상태를 확인할 수 없습니다. 네트워크 연결을 확인해주세요.
+                  {t('shiSync.descriptions.statusCheckError')}
                   {process.env.NODE_ENV === 'development' && (
                     <div className="text-xs mt-1 font-mono">
-                      Debug: {contractStatuses.filter(({ error }) => error).length}개 계약에서 오류
+                      Debug: {t('shiSync.descriptions.contractsWithError', { 
+                        count: contractStatuses.filter(({ error }) => error).length 
+                      })}
                     </div>
                   )}
                 </AlertDescription>
@@ -319,46 +337,46 @@ export function SendToSHIButton({
                 
                 <div className="grid grid-cols-3 gap-4 text-sm">
                   <div className="text-center">
-                    <div className="text-muted-foreground">대기 중</div>
-                    <div className="font-medium text-orange-600">{totalStats.totalPending}건</div>
+                    <div className="text-muted-foreground">{t('shiSync.labels.pending')}</div>
+                    <div className="font-medium text-orange-600">{t('shiSync.labels.itemCount', { count: totalStats.totalPending })}</div>
                   </div>
                   <div className="text-center">
-                    <div className="text-muted-foreground">동기화됨</div>
-                    <div className="font-medium text-green-600">{totalStats.totalSynced}건</div>
+                    <div className="text-muted-foreground">{t('shiSync.labels.synced')}</div>
+                    <div className="font-medium text-green-600">{t('shiSync.labels.itemCount', { count: totalStats.totalSynced })}</div>
                   </div>
                   <div className="text-center">
-                    <div className="text-muted-foreground">실패</div>
-                    <div className="font-medium text-red-600">{totalStats.totalFailed}건</div>
+                    <div className="text-muted-foreground">{t('shiSync.labels.failed')}</div>
+                    <div className="font-medium text-red-600">{t('shiSync.labels.itemCount', { count: totalStats.totalFailed })}</div>
                   </div>
                 </div>
 
                 {/* 계약별 상세 상태 */}
                 {contractStatuses.length > 1 && (
                   <div className="space-y-2">
-                    <div className="text-sm font-medium">계약별 상태</div>
+                    <div className="text-sm font-medium">{t('shiSync.labels.statusByContract')}</div>
                     <ScrollArea className="h-32">
                       <div className="space-y-2">
                         {contractStatuses.map(({ projectId, syncStatus, isLoading, error }) => (
                           <div key={projectId} className="flex items-center justify-between text-xs p-2 rounded border">
-                            <span className="font-medium">Contract {projectId}</span>
+                            <span className="font-medium">{t('shiSync.labels.contractLabel', { projectId })}</span>
                             {isLoading ? (
                               <Badge variant="secondary" className="text-xs">
                                 <Loader2 className="w-3 h-3 mr-1 animate-spin" />
-                                로딩...
+                                {t('shiSync.status.loading')}
                               </Badge>
                             ) : error ? (
                               <Badge variant="destructive" className="text-xs">
                                 <AlertTriangle className="w-3 h-3 mr-1" />
-                                오류
+                                {t('shiSync.status.error')}
                               </Badge>
                             ) : syncStatus && syncStatus.pendingChanges > 0 ? (
                               <Badge variant="destructive" className="text-xs">
-                                {syncStatus.pendingChanges}건 대기
+                                {t('shiSync.status.pendingCount', { count: syncStatus.pendingChanges })}
                               </Badge>
                             ) : (
                               <Badge variant="secondary" className="text-xs">
                                 <CheckCircle className="w-3 h-3 mr-1" />
-                                최신
+                                {t('shiSync.status.upToDate')}
                               </Badge>
                             )}
                           </div>
@@ -374,7 +392,7 @@ export function SendToSHIButton({
             {documentsContractIds.length === 0 && (
               <Alert>
                 <AlertDescription>
-                  동기화할 문서가 없습니다. 문서를 선택해주세요.
+                  {t('shiSync.descriptions.noDocumentsToSync')}
                 </AlertDescription>
               </Alert>
             )}
@@ -392,12 +410,12 @@ export function SendToSHIButton({
                 {isSyncing ? (
                   <>
                     <Loader2 className="w-4 h-4 mr-2 animate-spin" />
-                    동기화 중...
+                    {t('shiSync.buttons.syncing')}
                   </>
                 ) : (
                   <>
                     <Send className="w-4 h-4 mr-2" />
-                    지금 동기화
+                    {t('shiSync.buttons.syncNow')}
                   </>
                 )}
               </Button>
@@ -426,10 +444,13 @@ export function SendToSHIButton({
           <DialogHeader>
             <DialogTitle className="flex items-center gap-2">
               <Send className="w-5 h-5" />
-              SHI 시스템으로 동기화
+              {t('shiSync.dialog.title')}
             </DialogTitle>
             <DialogDescription>
-              {documentsContractIds.length}개 계약의 변경된 문서 데이터를 {targetSystem} 시스템으로 전송합니다.
+              {t('shiSync.dialog.description', {
+                contractCount: documentsContractIds.length,
+                targetSystem
+              })}
             </DialogDescription>
           </DialogHeader>
 
@@ -437,30 +458,30 @@ export function SendToSHIButton({
             {!totalStats.hasError && documentsContractIds.length > 0 && (
               <div className="rounded-lg border p-4 space-y-3">
                 <div className="flex items-center justify-between text-sm">
-                  <span>전송 대상</span>
-                  <span className="font-medium">{totalStats.totalPending}건</span>
+                  <span>{t('shiSync.labels.syncTarget')}</span>
+                  <span className="font-medium">{t('shiSync.labels.itemCount', { count: totalStats.totalPending })}</span>
                 </div>
                 
                 <div className="flex items-center justify-between text-sm">
-                  <span>대상 계약</span>
-                  <span className="font-medium">{documentsContractIds.length}개</span>
+                  <span>{t('shiSync.labels.targetContracts')}</span>
+                  <span className="font-medium">{t('shiSync.labels.contractCount', { count: documentsContractIds.length })}</span>
                 </div>
                 
                 <div className="text-xs text-muted-foreground">
-                  문서, 리비전, 첨부파일의 변경사항이 포함됩니다.
+                  {t('shiSync.descriptions.includesChanges')}
                 </div>
 
                 {isSyncing && (
                   <div className="space-y-2">
                     <div className="flex items-center justify-between text-sm">
-                      <span>진행률</span>
+                      <span>{t('shiSync.labels.progress')}</span>
                       <span>{Math.round(syncProgress)}%</span>
                     </div>
                     <Progress value={syncProgress} className="h-2" />
                     {currentSyncingContract && (
                       <div className="text-xs text-muted-foreground flex items-center gap-1">
                         <Loader2 className="w-3 h-3 animate-spin" />
-                        현재 처리 중: Contract {currentSyncingContract}
+                        {t('shiSync.descriptions.currentlyProcessing', { contractId: currentSyncingContract })}
                       </div>
                     )}
                   </div>
@@ -472,7 +493,7 @@ export function SendToSHIButton({
               <Alert variant="destructive">
                 <AlertTriangle className="h-4 w-4" />
                 <AlertDescription>
-                  일부 계약의 동기화 상태를 확인할 수 없습니다. 네트워크 연결을 확인하고 다시 시도해주세요.
+                  {t('shiSync.descriptions.dialogStatusCheckError')}
                 </AlertDescription>
               </Alert>
             )}
@@ -480,7 +501,7 @@ export function SendToSHIButton({
             {documentsContractIds.length === 0 && (
               <Alert>
                 <AlertDescription>
-                  동기화할 계약이 없습니다. 문서를 선택해주세요.
+                  {t('shiSync.descriptions.noContractsToSync')}
                 </AlertDescription>
               </Alert>
             )}
@@ -491,7 +512,7 @@ export function SendToSHIButton({
                 onClick={() => setIsDialogOpen(false)}
                 disabled={isSyncing}
               >
-                취소
+                {t('buttons.cancel')}
               </Button>
               <Button
                 onClick={handleSync}
@@ -500,12 +521,12 @@ export function SendToSHIButton({
                 {isSyncing ? (
                   <>
                     <Loader2 className="w-4 h-4 mr-2 animate-spin" />
-                    동기화 중...
+                    {t('shiSync.buttons.syncing')}
                   </>
                 ) : (
                   <>
                     <Send className="w-4 h-4 mr-2" />
-                    동기화 시작
+                    {t('shiSync.buttons.startSync')}
                   </>
                 )}
               </Button>
-- 
cgit v1.2.3

