From caa01b321311de3983fb8bcf65bb20a6c047cf57 Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Tue, 9 Sep 2025 10:40:11 +0000
Subject: (김준회) 자재그룹코드 및 자재그룹명에 대해 별도 테이블 생성, 동기화
 로직 작성(일회성 사용이며 수신시점에는 자동저장하므로 추후 사용 불필요),
 자재그룹 선택기를 변경사항에 맞춰 업데이트, 자재그룹명은 MAKTX 로 김학의 프로
 답변에 따라 변경
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/material-groups/sync-button.tsx | 240 +++++++++++++++++++++++++++++
 1 file changed, 240 insertions(+)
 create mode 100644 components/material-groups/sync-button.tsx

(limited to 'components/material-groups/sync-button.tsx')

diff --git a/components/material-groups/sync-button.tsx b/components/material-groups/sync-button.tsx
new file mode 100644
index 00000000..7dc7da8f
--- /dev/null
+++ b/components/material-groups/sync-button.tsx
@@ -0,0 +1,240 @@
+"use client";
+
+import * as React from "react";
+import { Button } from "@/components/ui/button";
+import { Badge } from "@/components/ui/badge";
+import { 
+  Dialog, 
+  DialogContent, 
+  DialogDescription, 
+  DialogHeader, 
+  DialogTitle, 
+  DialogTrigger 
+} from "@/components/ui/dialog";
+import { 
+  RefreshCw, 
+  Database, 
+  CheckCircle, 
+  AlertCircle,
+  Clock,
+  TrendingUp
+} from "lucide-react";
+import { useToast } from "@/hooks/use-toast";
+import { 
+  syncMaterialGroupMaster, 
+  getMaterialGroupSyncStatus,
+  type SyncResult 
+} from "@/lib/material-groups/sync-service";
+
+export function MaterialGroupSyncButton() {
+  const [isOpen, setIsOpen] = React.useState(false);
+  const [isLoading, setIsLoading] = React.useState(false);
+  const [syncStatus, setSyncStatus] = React.useState<{
+    totalMDGRecords: number;
+    totalMasterRecords: number;
+    lastSyncDate?: string;
+  } | null>(null);
+  const [lastSyncResult, setLastSyncResult] = React.useState<SyncResult | null>(null);
+  const { toast } = useToast();
+
+  // 다이얼로그 열릴 때 상태 정보 로드
+  React.useEffect(() => {
+    if (isOpen) {
+      loadSyncStatus();
+    }
+  }, [isOpen]);
+
+  const loadSyncStatus = async () => {
+    try {
+      const status = await getMaterialGroupSyncStatus();
+      if (status.success && status.data) {
+        setSyncStatus(status.data);
+      }
+    } catch (error) {
+      console.error("동기화 상태 로드 실패:", error);
+    }
+  };
+
+  const handleSync = async () => {
+    setIsLoading(true);
+    try {
+      const result = await syncMaterialGroupMaster();
+      setLastSyncResult(result);
+      
+      if (result.success) {
+        toast({
+          title: "동기화 완료",
+          description: result.message,
+          variant: "default",
+        });
+        // 상태 다시 로드
+        await loadSyncStatus();
+      } else {
+        toast({
+          title: "동기화 실패",
+          description: result.message,
+          variant: "destructive",
+        });
+      }
+    } catch (error) {
+      toast({
+        title: "동기화 오류",
+        description: error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.",
+        variant: "destructive",
+      });
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  const formatDate = (dateString: string) => {
+    return new Date(dateString).toLocaleString('ko-KR', {
+      year: 'numeric',
+      month: '2-digit',
+      day: '2-digit',
+      hour: '2-digit',
+      minute: '2-digit'
+    });
+  };
+
+  const getSyncBadgeVariant = () => {
+    if (!syncStatus) return "secondary";
+    if (syncStatus.totalMDGRecords === syncStatus.totalMasterRecords) {
+      return "default"; // 동기화됨
+    }
+    return "destructive"; // 동기화 필요
+  };
+
+  return (
+    <Dialog open={isOpen} onOpenChange={setIsOpen}>
+      <DialogTrigger asChild>
+        <Button variant="outline" size="sm" className="gap-2">
+          <Database className="h-4 w-4" />
+          동기화
+          {syncStatus && (
+            <Badge variant={getSyncBadgeVariant()} className="ml-1">
+              {syncStatus.totalMasterRecords}
+            </Badge>
+          )}
+        </Button>
+      </DialogTrigger>
+      
+      <DialogContent className="sm:max-w-[500px]">
+        <DialogHeader>
+          <DialogTitle className="flex items-center gap-2">
+            <Database className="h-5 w-5" />
+            자재그룹 마스터 동기화
+          </DialogTitle>
+          <DialogDescription>
+            MDG 테이블로부터 자재그룹 마스터 데이터를 동기화합니다.
+          </DialogDescription>
+        </DialogHeader>
+        
+        <div className="space-y-4">
+          {/* 현재 상태 */}
+          {syncStatus && (
+            <div className="rounded-lg border p-4 space-y-3">
+              <h4 className="font-medium flex items-center gap-2">
+                <TrendingUp className="h-4 w-4" />
+                현재 상태
+              </h4>
+              
+              <div className="grid grid-cols-2 gap-4 text-sm">
+                <div>
+                  <span className="text-muted-foreground">MDG 자재그룹:</span>
+                  <div className="font-medium">{syncStatus.totalMDGRecords.toLocaleString()}개</div>
+                </div>
+                <div>
+                  <span className="text-muted-foreground">마스터 테이블:</span>
+                  <div className="font-medium">{syncStatus.totalMasterRecords.toLocaleString()}개</div>
+                </div>
+              </div>
+              
+              {syncStatus.lastSyncDate && (
+                <div className="text-sm">
+                  <span className="text-muted-foreground flex items-center gap-1">
+                    <Clock className="h-3 w-3" />
+                    최근 동기화:
+                  </span>
+                  <div className="font-medium">{formatDate(syncStatus.lastSyncDate)}</div>
+                </div>
+              )}
+              
+              <div className="flex items-center gap-2">
+                <Badge variant={getSyncBadgeVariant()}>
+                  {syncStatus.totalMDGRecords === syncStatus.totalMasterRecords 
+                    ? "동기화됨" 
+                    : "동기화 필요"}
+                </Badge>
+              </div>
+            </div>
+          )}
+
+          {/* 마지막 동기화 결과 */}
+          {lastSyncResult && (
+            <div className="rounded-lg border p-4 space-y-3">
+              <h4 className="font-medium flex items-center gap-2">
+                {lastSyncResult.success ? (
+                  <CheckCircle className="h-4 w-4 text-green-600" />
+                ) : (
+                  <AlertCircle className="h-4 w-4 text-red-600" />
+                )}
+                마지막 동기화 결과
+              </h4>
+              
+              <p className="text-sm text-muted-foreground">
+                {lastSyncResult.message}
+              </p>
+              
+              {lastSyncResult.data && (
+                <div className="grid grid-cols-3 gap-2 text-sm">
+                  <div className="text-center">
+                    <div className="font-medium text-green-600">
+                      {lastSyncResult.data.newRecords}
+                    </div>
+                    <div className="text-muted-foreground">신규</div>
+                  </div>
+                  <div className="text-center">
+                    <div className="font-medium text-blue-600">
+                      {lastSyncResult.data.updatedRecords}
+                    </div>
+                    <div className="text-muted-foreground">업데이트</div>
+                  </div>
+                  <div className="text-center">
+                    <div className="font-medium text-gray-600">
+                      {lastSyncResult.data.skippedRecords}
+                    </div>
+                    <div className="text-muted-foreground">건너뜀</div>
+                  </div>
+                </div>
+              )}
+            </div>
+          )}
+
+          {/* 동기화 실행 버튼 */}
+          <Button 
+            onClick={handleSync} 
+            disabled={isLoading}
+            className="w-full"
+          >
+            {isLoading ? (
+              <>
+                <RefreshCw className="mr-2 h-4 w-4 animate-spin" />
+                동기화 중...
+              </>
+            ) : (
+              <>
+                <RefreshCw className="mr-2 h-4 w-4" />
+                동기화 실행
+              </>
+            )}
+          </Button>
+          
+          <p className="text-xs text-muted-foreground text-center">
+            * 동기화는 기존 데이터를 업데이트하며 새로운 자재그룹을 추가합니다.
+          </p>
+        </div>
+      </DialogContent>
+    </Dialog>
+  );
+}
-- 
cgit v1.2.3

