From 20800b214145ee6056f94ca18fa1054f145eb977 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Wed, 28 May 2025 00:32:31 +0000 Subject: (대표님) lib 파트 커밋 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../table/send-to-shi-button.tsx | 342 +++++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 lib/vendor-document-list/table/send-to-shi-button.tsx (limited to 'lib/vendor-document-list/table/send-to-shi-button.tsx') diff --git a/lib/vendor-document-list/table/send-to-shi-button.tsx b/lib/vendor-document-list/table/send-to-shi-button.tsx new file mode 100644 index 00000000..e0360144 --- /dev/null +++ b/lib/vendor-document-list/table/send-to-shi-button.tsx @@ -0,0 +1,342 @@ +// components/sync/send-to-shi-button.tsx (최종 버전) +"use client" + +import * as React from "react" +import { Send, Loader2, CheckCircle, AlertTriangle, Settings } from "lucide-react" +import { toast } from "sonner" + +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover" +import { Badge } from "@/components/ui/badge" +import { Progress } from "@/components/ui/progress" +import { Separator } from "@/components/ui/separator" +import { useSyncStatus, useTriggerSync } from "@/hooks/use-sync-status" +import type { EnhancedDocument } from "@/types/enhanced-documents" + +interface SendToSHIButtonProps { + contractId: number + documents?: EnhancedDocument[] + onSyncComplete?: () => void +} + +export function SendToSHIButton({ + contractId, + documents = [], + onSyncComplete +}: SendToSHIButtonProps) { + const [isDialogOpen, setIsDialogOpen] = React.useState(false) + const [syncProgress, setSyncProgress] = React.useState(0) + + const { + syncStatus, + isLoading: statusLoading, + error: statusError, + refetch: refetchStatus + } = useSyncStatus(contractId, 'SHI') + + const { + triggerSync, + isLoading: isSyncing, + error: syncError + } = useTriggerSync() + + // 에러 상태 표시 + React.useEffect(() => { + if (statusError) { + console.warn('Failed to load sync status:', statusError) + } + }, [statusError]) + + const handleSync = async () => { + if (!contractId) return + + setSyncProgress(0) + + try { + // 진행률 시뮬레이션 + const progressInterval = setInterval(() => { + setSyncProgress(prev => Math.min(prev + 10, 90)) + }, 200) + + const result = await triggerSync({ + contractId, + targetSystem: 'SHI' + }) + + clearInterval(progressInterval) + setSyncProgress(100) + + setTimeout(() => { + setSyncProgress(0) + setIsDialogOpen(false) + + if (result?.success) { + toast.success( + `동기화 완료: ${result.successCount || 0}건 성공`, + { + description: result.successCount > 0 + ? `${result.successCount}개 항목이 SHI 시스템으로 전송되었습니다.` + : '전송할 새로운 변경사항이 없습니다.' + } + ) + } else { + toast.error( + `동기화 부분 실패: ${result?.successCount || 0}건 성공, ${result?.failureCount || 0}건 실패`, + { + description: result?.errors?.[0] || '일부 항목 전송에 실패했습니다.' + } + ) + } + + refetchStatus() // SWR 캐시 갱신 + onSyncComplete?.() + }, 500) + + } catch (error) { + setSyncProgress(0) + + toast.error('동기화 실패', { + description: error instanceof Error ? error.message : '알 수 없는 오류가 발생했습니다.' + }) + } + } + + const getSyncStatusBadge = () => { + if (statusLoading) { + return 확인 중... + } + + if (statusError) { + return 오류 + } + + if (!syncStatus) { + return 데이터 없음 + } + + if (syncStatus.pendingChanges > 0) { + return ( + + + {syncStatus.pendingChanges}건 대기 + + ) + } + + if (syncStatus.syncedChanges > 0) { + return ( + + + 동기화됨 + + ) + } + + return 변경사항 없음 + } + + const canSync = !statusError && syncStatus?.syncEnabled && syncStatus?.pendingChanges > 0 + + return ( + <> + + + + + + +
+
+

SHI 동기화 상태

+
+ 현재 상태 + {getSyncStatusBadge()} +
+
+ + {syncStatus && !statusError && ( +
+ + +
+
+
대기 중
+
{syncStatus.pendingChanges || 0}건
+
+
+
동기화됨
+
{syncStatus.syncedChanges || 0}건
+
+
+ + {syncStatus.failedChanges > 0 && ( +
+
실패
+
{syncStatus.failedChanges}건
+
+ )} + + {syncStatus.lastSyncAt && ( +
+
마지막 동기화
+
+ {new Date(syncStatus.lastSyncAt).toLocaleString()} +
+
+ )} +
+ )} + + {statusError && ( +
+ +
+
연결 오류
+
동기화 상태를 확인할 수 없습니다.
+
+
+ )} + + + +
+ + + +
+
+
+
+ + {/* 동기화 진행 다이얼로그 */} + + + + SHI 시스템으로 동기화 + + 변경된 문서 데이터를 SHI 시스템으로 전송합니다. + + + +
+ {syncStatus && !statusError && ( +
+
+ 전송 대상 + {syncStatus.pendingChanges || 0}건 +
+ +
+ 문서, 리비전, 첨부파일의 변경사항이 포함됩니다. +
+ + {isSyncing && ( +
+
+ 진행률 + {syncProgress}% +
+ +
+ )} +
+ )} + + {statusError && ( +
+
+ 동기화 상태를 확인할 수 없습니다. 네트워크 연결을 확인해주세요. +
+
+ )} + +
+ + +
+
+
+
+ + ) +} \ No newline at end of file -- cgit v1.2.3