From a4bf0d8376962c922da90cd08781893a3658ecc2 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Thu, 6 Nov 2025 09:52:27 +0000
Subject: (최겸) 구매 보완 재실사 자동생성 삭제
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/pq/pq-review-table-new/site-visit-dialog.tsx | 189 ++++++++---------------
 1 file changed, 65 insertions(+), 124 deletions(-)

(limited to 'lib/pq/pq-review-table-new/site-visit-dialog.tsx')

diff --git a/lib/pq/pq-review-table-new/site-visit-dialog.tsx b/lib/pq/pq-review-table-new/site-visit-dialog.tsx
index a7cc3313..55468499 100644
--- a/lib/pq/pq-review-table-new/site-visit-dialog.tsx
+++ b/lib/pq/pq-review-table-new/site-visit-dialog.tsx
@@ -1,7 +1,7 @@
 "use client"
 
 import * as React from "react"
-import { CalendarIcon, X, Plus, Trash2, Check, Search } from "lucide-react"
+import { CalendarIcon, X, Plus, Trash2 } from "lucide-react"
 import { useForm, useFieldArray } from "react-hook-form"
 import { zodResolver } from "@hookform/resolvers/zod"
 import { format } from "date-fns"
@@ -36,18 +36,9 @@ import {
 } from "@/components/ui/popover"
 import { Checkbox } from "@/components/ui/checkbox"
 import { Badge } from "@/components/ui/badge"
-import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
-import {
-  Command,
-  CommandEmpty,
-  CommandGroup,
-  CommandInput,
-  CommandItem,
-  CommandList,
-} from "@/components/ui/command"
 import { toast } from "sonner"
 import { getSiteVisitRequestAction, getUsersForSiteVisitAction } from "@/lib/site-visit/service"
-import { cn } from "@/lib/utils"
+import { UserCombobox } from "./user-combobox"
 import {
   Dropzone,
   DropzoneDescription,
@@ -183,7 +174,7 @@ interface SiteVisitUser {
   id: number;
   name: string;
   email: string;
-  deptName: string | null;
+  department?: string;
 }
 
 // 참석자 섹션 컴포넌트
@@ -204,57 +195,55 @@ function AttendeeSection({
   });
 
   const isChecked = form.watch(`shiAttendees.${itemKey}.checked`);
-  const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);
-  const [searchQuery, setSearchQuery] = React.useState("");
   const [users, setUsers] = React.useState<SiteVisitUser[]>([]);
   const [isLoadingUsers, setIsLoadingUsers] = React.useState(false);
+  const [selectedUserId, setSelectedUserId] = React.useState<number | null>(null);
 
-  const loadUsers = React.useCallback(async () => {
-    setIsLoadingUsers(true);
-    try {
-      const result = await getUsersForSiteVisitAction(
-        searchQuery.trim() || undefined
-      );
-      if (result.success && result.data) {
-        setUsers(result.data);
-      }
-    } catch (error) {
-      console.error("사용자 목록 로드 오류:", error);
-      toast.error("사용자 목록을 불러오는데 실패했습니다.");
-    } finally {
-      setIsLoadingUsers(false);
-    }
-  }, [searchQuery]);
-
-  // 사용자 목록 가져오기
-  React.useEffect(() => {
-    if (isPopoverOpen && isChecked) {
-      loadUsers();
-    }
-  }, [isPopoverOpen, isChecked, loadUsers]);
-
-  // 검색 쿼리 변경 시 사용자 목록 다시 로드 (debounce)
+  // Dialog가 열릴 때 사용자 목록 로드
   React.useEffect(() => {
-    if (!isPopoverOpen || !isChecked) return;
+    if (isChecked && users.length === 0) {
+      const loadUsers = async () => {
+        setIsLoadingUsers(true);
+        try {
+          const result = await getUsersForSiteVisitAction();
+          if (result.success && result.data) {
+            setUsers(result.data.map((user: any) => ({
+              id: user.id,
+              name: user.name,
+              email: user.email,
+              department: user.deptName || undefined,
+            })));
+          }
+        } catch (error) {
+          console.error("사용자 목록 로드 오류:", error);
+          toast.error("사용자 목록을 불러오는데 실패했습니다.");
+        } finally {
+          setIsLoadingUsers(false);
+        }
+      };
 
-    const timer = setTimeout(() => {
       loadUsers();
-    }, 300);
+    }
+  }, [isChecked, users.length]);
 
-    return () => clearTimeout(timer);
-  }, [searchQuery, isPopoverOpen, isChecked, loadUsers]);
+  const handleUserSelect = (userId: number) => {
+    // 선택된 사용자 정보 찾기
+    const selectedUser = users.find(user => user.id === userId);
+    if (!selectedUser) return;
 
-  const handleUserSelect = (user: SiteVisitUser) => {
     // 현재 폼의 attendees 값 가져오기
     const currentAttendees = form.getValues(`shiAttendees.${itemKey}.attendees`) as Array<{
       name: string;
       department?: string;
       email: string;
-    }>;
+    }> | undefined;
     
-    // 이미 선택된 사용자인지 확인
-    const existingIndex = currentAttendees.findIndex(
-      (attendee) => attendee.email === user.email
+    // undefined이거나 배열이 아닌 경우 빈 배열로 처리
+    const attendees = Array.isArray(currentAttendees) ? currentAttendees : [];
+    
+    // 이미 선택된 사용자인지 확인 (이메일 기준)
+    const existingIndex = attendees.findIndex(
+      (attendee) => attendee.email === selectedUser.email
     );
 
     if (existingIndex >= 0) {
@@ -263,20 +252,14 @@ function AttendeeSection({
     } else {
       // 새로 추가
       append({
-        name: user.name,
-        department: user.deptName || "",
-        email: user.email,
+        name: selectedUser.name,
+        department: selectedUser.department || "",
+        email: selectedUser.email,
       });
     }
-  };
-
-  const isUserSelected = (userEmail: string) => {
-    const currentAttendees = form.getValues(`shiAttendees.${itemKey}.attendees`) as Array<{
-      name: string;
-      department?: string;
-      email: string;
-    }>;
-    return currentAttendees.some((attendee) => attendee.email === userEmail);
+    
+    // 선택 초기화
+    setSelectedUserId(null);
   };
 
   return (
@@ -296,7 +279,6 @@ function AttendeeSection({
                       // 체크 해제 시 참석자 목록 초기화
                       if (!checked) {
                         form.setValue(`shiAttendees.${itemKey}.attendees` as any, []);
-                        setIsPopoverOpen(false);
                       }
                     }}
                     disabled={isPending}
@@ -319,68 +301,27 @@ function AttendeeSection({
       {isChecked && (
         <div className="space-y-3">
           {/* 사용자 선택 UI */}
-          <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
-            <PopoverTrigger asChild>
-              <Button
-                type="button"
-                variant="outline"
-                className="w-full justify-start text-left font-normal"
-                disabled={isPending}
-              >
-                <Search className="mr-2 h-4 w-4" />
-                이름 또는 이메일로 검색...
-              </Button>
-            </PopoverTrigger>
-            <PopoverContent className="w-[400px] p-0" align="start">
-              <Command>
-                <CommandInput
-                  placeholder="이름 또는 이메일로 검색..."
-                  value={searchQuery}
-                  onValueChange={setSearchQuery}
-                />
-                <CommandList>
-                  <CommandEmpty>
-                    {isLoadingUsers ? "로딩 중..." : "검색 결과가 없습니다."}
-                  </CommandEmpty>
-                  <CommandGroup>
-                    {users.map((user) => {
-                      const selected = isUserSelected(user.email);
-                      return (
-                        <CommandItem
-                          key={user.id}
-                          value={`${user.name} ${user.email}`}
-                          onSelect={() => handleUserSelect(user)}
-                          className="cursor-pointer"
-                        >
-                          <Check
-                            className={cn(
-                              "mr-2 h-4 w-4",
-                              selected ? "opacity-100" : "opacity-0"
-                            )}
-                          />
-                          <div className="flex flex-col flex-1 min-w-0">
-                            <div className="flex items-center gap-2">
-                              <span className="font-medium truncate">
-                                {user.name}
-                              </span>
-                              {user.deptName && (
-                                <span className="text-xs text-muted-foreground truncate">
-                                  ({user.deptName})
-                                </span>
-                              )}
-                            </div>
-                            <span className="text-xs text-muted-foreground truncate">
-                              {user.email}
-                            </span>
-                          </div>
-                        </CommandItem>
-                      );
-                    })}
-                  </CommandGroup>
-                </CommandList>
-              </Command>
-            </PopoverContent>
-          </Popover>
+          <div className="flex items-center gap-2">
+            <div className="flex-1">
+              <UserCombobox
+                users={users}
+                value={selectedUserId}
+                onChange={handleUserSelect}
+                placeholder={isLoadingUsers ? "담당자 로딩 중..." : "담당자 선택..."}
+                disabled={isPending || isLoadingUsers}
+              />
+            </div>
+            <Button
+              type="button"
+              variant="outline"
+              size="icon"
+              onClick={() => setSelectedUserId(null)}
+              disabled={isPending || !selectedUserId}
+              title="선택 초기화"
+            >
+              <X className="h-4 w-4" />
+            </Button>
+          </div>
 
           {/* 선택된 사용자 목록 */}
           {fields.length > 0 && (
-- 
cgit v1.2.3

