diff options
| author | joonhoekim <26rote@gmail.com> | 2025-11-11 19:19:25 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-11-11 19:19:25 +0900 |
| commit | 043dfe2f7ac3965de60d3f3caf636237b9d986b0 (patch) | |
| tree | 77992ab61a94dc94743e3850fbe5a6527f1421eb /lib/vendor-regular-registrations/table/major-items-update-dialog.tsx | |
| parent | 4098a22b43c6ebc51688d03db59fd510e72dee10 (diff) | |
(김준회) 정규업체 등록관리: 주요품목 컬럼 오류 수정, 주요품목 업데이트 dialog 수정
Diffstat (limited to 'lib/vendor-regular-registrations/table/major-items-update-dialog.tsx')
| -rw-r--r-- | lib/vendor-regular-registrations/table/major-items-update-dialog.tsx | 167 |
1 files changed, 35 insertions, 132 deletions
diff --git a/lib/vendor-regular-registrations/table/major-items-update-dialog.tsx b/lib/vendor-regular-registrations/table/major-items-update-dialog.tsx index 26741a1b..04635d2c 100644 --- a/lib/vendor-regular-registrations/table/major-items-update-dialog.tsx +++ b/lib/vendor-regular-registrations/table/major-items-update-dialog.tsx @@ -3,7 +3,6 @@ import * as React from "react" import { useState } from "react" import { toast } from "sonner" -import { X, Plus, Search } from "lucide-react" import { Dialog, @@ -13,18 +12,11 @@ import { DialogTitle, } from "@/components/ui/dialog" import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { Badge } from "@/components/ui/badge" import { Label } from "@/components/ui/label" -import { searchItemsForPQ } from "@/lib/items/service" +import { MaterialGroupSelector } from "@/components/common/material/material-group-selector" +import { MaterialSearchItem } from "@/lib/material/material-group-service" import { updateMajorItems } from "../service" -// PQ 대상 품목 타입 정의 -interface PQItem { - itemCode: string - itemName: string -} - interface MajorItemsUpdateDialogProps { open: boolean onOpenChange: (open: boolean) => void @@ -43,12 +35,7 @@ export function MajorItemsUpdateDialog({ onSuccess, }: MajorItemsUpdateDialogProps) { const [isLoading, setIsLoading] = useState(false) - const [selectedItems, setSelectedItems] = useState<PQItem[]>([]) - - // 아이템 검색 관련 상태 - const [itemSearchQuery, setItemSearchQuery] = useState<string>("") - const [filteredItems, setFilteredItems] = useState<PQItem[]>([]) - const [showItemDropdown, setShowItemDropdown] = useState<boolean>(false) + const [selectedMaterials, setSelectedMaterials] = useState<MaterialSearchItem[]>([]) // 기존 아이템들 파싱 및 초기화 React.useEffect(() => { @@ -56,65 +43,26 @@ export function MajorItemsUpdateDialog({ try { const parsedItems = JSON.parse(currentItems) if (Array.isArray(parsedItems)) { - setSelectedItems(parsedItems) + // materialGroupCode와 materialGroupDescription이 있는 항목들만 변환 + const materials = parsedItems + .filter((item: any) => item.materialGroupCode && item.materialGroupDescription) + .map((item: any) => ({ + materialGroupCode: item.materialGroupCode, + materialGroupDescription: item.materialGroupDescription, + materialGroupUom: item.materialGroupUom, + displayText: `${item.materialGroupCode} - ${item.materialGroupDescription}`, + })) + setSelectedMaterials(materials) } } catch (error) { console.error("기존 주요품목 파싱 오류:", error) - setSelectedItems([]) + setSelectedMaterials([]) } } else if (open) { - setSelectedItems([]) + setSelectedMaterials([]) } }, [open, currentItems]) - // 아이템 검색 필터링 - React.useEffect(() => { - if (itemSearchQuery.trim() === "") { - setFilteredItems([]) - setShowItemDropdown(false) - return - } - - const searchItems = async () => { - try { - const results = await searchItemsForPQ(itemSearchQuery) - setFilteredItems(results) - setShowItemDropdown(true) - } catch (error) { - console.error("아이템 검색 오류:", error) - toast.error("아이템 검색 중 오류가 발생했습니다.") - setFilteredItems([]) - setShowItemDropdown(false) - } - } - - // 디바운싱: 300ms 후에 검색 실행 - const timeoutId = setTimeout(searchItems, 300) - return () => clearTimeout(timeoutId) - }, [itemSearchQuery]) - - // 아이템 선택 함수 - const handleSelectItem = (item: PQItem) => { - // 이미 선택된 아이템인지 확인 - const isAlreadySelected = selectedItems.some(selectedItem => - selectedItem.itemCode === item.itemCode - ) - - if (!isAlreadySelected) { - setSelectedItems(prev => [...prev, item]) - } - - // 검색 초기화 - setItemSearchQuery("") - setFilteredItems([]) - setShowItemDropdown(false) - } - - // 아이템 제거 함수 - const handleRemoveItem = (itemCode: string) => { - setSelectedItems(prev => prev.filter(item => item.itemCode !== itemCode)) - } - const handleSave = async () => { if (!registrationId) { toast.error("등록 ID가 없습니다.") @@ -123,9 +71,16 @@ export function MajorItemsUpdateDialog({ setIsLoading(true) try { + // MaterialSearchItem을 DB 저장 형식으로 변환 + const itemsToSave = selectedMaterials.map(material => ({ + materialGroupCode: material.materialGroupCode, + materialGroupDescription: material.materialGroupDescription, + materialGroupUom: material.materialGroupUom, + })) + const result = await updateMajorItems( registrationId, - JSON.stringify(selectedItems) + JSON.stringify(itemsToSave) ) if (result.success) { @@ -153,72 +108,20 @@ export function MajorItemsUpdateDialog({ </DialogDescription> </DialogHeader> - <div className="space-y-6 mt-6"> - {/* 선택된 아이템들 표시 */} - {selectedItems.length > 0 && ( - <div className="space-y-2"> - <Label>선택된 주요품목 ({selectedItems.length}개)</Label> - <div className="flex flex-wrap gap-2 max-h-40 overflow-y-auto border rounded-md p-3"> - {selectedItems.map((item) => ( - <Badge key={item.itemCode} variant="secondary" className="flex items-center gap-1"> - <span className="text-xs"> - {item.itemCode} - {item.itemName} - </span> - <Button - type="button" - variant="ghost" - size="sm" - className="h-4 w-4 p-0 hover:bg-destructive hover:text-destructive-foreground" - onClick={() => handleRemoveItem(item.itemCode)} - > - <X className="h-3 w-3" /> - </Button> - </Badge> - ))} - </div> - </div> - )} - - {/* 검색 입력 */} + <div className="space-y-4 mt-6"> <div className="space-y-2"> - <Label>품목 검색 및 추가</Label> - <div className="relative"> - <div className="relative"> - <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" /> - <Input - placeholder="아이템 코드 또는 이름으로 검색하세요" - value={itemSearchQuery} - onChange={(e) => setItemSearchQuery(e.target.value)} - className="pl-9" - /> - </div> - - {/* 검색 결과 드롭다운 */} - {showItemDropdown && ( - <div className="absolute top-full left-0 right-0 z-50 mt-1 max-h-48 overflow-y-auto bg-background border rounded-md shadow-lg"> - {filteredItems.length > 0 ? ( - filteredItems.map((item) => ( - <button - key={item.itemCode} - type="button" - className="w-full px-3 py-2 text-left text-sm hover:bg-muted focus:bg-muted focus:outline-none" - onClick={() => handleSelectItem(item)} - > - <div className="font-medium">{item.itemCode}</div> - <div className="text-muted-foreground text-xs">{item.itemName}</div> - </button> - )) - ) : ( - <div className="px-3 py-2 text-sm text-muted-foreground"> - 검색 결과가 없습니다. - </div> - )} - </div> - )} - </div> - + <Label>자재그룹 검색 및 선택</Label> + <MaterialGroupSelector + selectedMaterials={selectedMaterials} + onMaterialsChange={setSelectedMaterials} + singleSelect={false} + placeholder="자재그룹을 검색하세요..." + noValuePlaceHolder="자재그룹을 선택해주세요" + closeOnSelect={false} + showInitialData={true} + /> <div className="text-xs text-muted-foreground"> - 아이템 코드나 이름을 입력하여 검색하고 선택하세요. + 선택됨: {selectedMaterials.length}개 </div> </div> </div> |
