From 8642ee064ddf96f1db2b948b4cc8bbbd6cfee820 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Wed, 12 Nov 2025 10:42:36 +0000 Subject: (최겸) 구매 일반계약, 입찰 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../procurement-item-selector-dialog-single.tsx | 168 +++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 components/common/selectors/procurement-item/procurement-item-selector-dialog-single.tsx (limited to 'components/common/selectors/procurement-item/procurement-item-selector-dialog-single.tsx') diff --git a/components/common/selectors/procurement-item/procurement-item-selector-dialog-single.tsx b/components/common/selectors/procurement-item/procurement-item-selector-dialog-single.tsx new file mode 100644 index 00000000..dab65780 --- /dev/null +++ b/components/common/selectors/procurement-item/procurement-item-selector-dialog-single.tsx @@ -0,0 +1,168 @@ +"use client"; + +import React, { useState, useCallback } from "react"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { ProcurementItemSelector } from "./procurement-item-selector"; +import { ProcurementSearchItem } from "./procurement-item-service"; + +export interface ProcurementItemSelectorDialogSingleProps { + triggerLabel?: string; + triggerVariant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link"; + triggerSize?: "default" | "sm" | "lg" | "icon"; + selectedProcurementItem?: ProcurementSearchItem | null; + onProcurementItemSelect?: (item: ProcurementSearchItem | null) => void; + title?: string; + description?: string; + showConfirmButtons?: boolean; +} + +/** + * 품목 단일 선택 Dialog 컴포넌트 + * + * @description + * - ProcurementItemSelector를 Dialog로 래핑한 단일 선택 컴포넌트 + * - 버튼 클릭 시 Dialog가 열리고, 품목을 선택하면 Dialog가 닫히며 결과를 반환 + * + * @ProcurementSearchItem_Structure + * 상태에서 관리되는 품목 객체의 형태: + * ```typescript + * interface ProcurementSearchItem { + * itemCode: string; // 품목코드 + * itemName: string; // 품목명 + * material?: string; // 재질 + * specification?: string; // 규격 + * unit?: string; // 단위 + * displayText: string; // 표시용 텍스트 (code + " - " + name) + * } + * ``` + * + * @state + * - open: Dialog 열림/닫힘 상태 + * - selectedProcurementItem: 현재 선택된 품목 (단일) + * - tempSelectedProcurementItem: Dialog 내에서 임시로 선택된 품목 (확인 버튼 클릭 전까지) + * + * @callback + * - onProcurementItemSelect: 품목 선택 완료 시 호출되는 콜백 + * - 매개변수: ProcurementSearchItem | null + * - 선택된 품목 정보 또는 null (선택 해제 시) + * + * @usage + * ```tsx + * { + * console.log('선택된 품목:', item); + * setSelectedProcurementItem(item); + * }} + * title="품목 선택" + * description="품목을 검색하고 선택해주세요." + * /> + * ``` + */ +export function ProcurementItemSelectorDialogSingle({ + triggerLabel = "품목 선택", + triggerVariant = "outline", + triggerSize = "default", + selectedProcurementItem = null, + onProcurementItemSelect, + title = "품목 선택", + description = "품목을 검색하고 선택해주세요.", + showConfirmButtons = false, +}: ProcurementItemSelectorDialogSingleProps) { + const [open, setOpen] = useState(false); + const [tempSelectedProcurementItem, setTempSelectedProcurementItem] = + useState(selectedProcurementItem); + + // Dialog가 열릴 때 임시 선택 상태 초기화 + const handleOpenChange = useCallback((newOpen: boolean) => { + setOpen(newOpen); + if (newOpen) { + // Dialog 열 때 현재 선택된 값으로 임시 상태 초기화 + setTempSelectedProcurementItem(selectedProcurementItem); + } + }, [selectedProcurementItem]); + + // 품목 선택 시 임시 상태 업데이트 + const handleProcurementItemSelect = useCallback((item: ProcurementSearchItem | null) => { + setTempSelectedProcurementItem(item); + + // 확인 버튼이 없는 경우 즉시 적용하고 Dialog 닫기 + if (!showConfirmButtons) { + onProcurementItemSelect?.(item); + setOpen(false); + } + }, [onProcurementItemSelect, showConfirmButtons]); + + // 확인 버튼 클릭 시 선택 적용 + const handleConfirm = useCallback(() => { + onProcurementItemSelect?.(tempSelectedProcurementItem); + setOpen(false); + }, [onProcurementItemSelect, tempSelectedProcurementItem]); + + // 취소 버튼 클릭 시 Dialog 닫기 (변경사항 적용 안 함) + const handleCancel = useCallback(() => { + setOpen(false); + }, []); + + // 선택 해제 + const handleClear = useCallback(() => { + const newSelection = null; + setTempSelectedProcurementItem(newSelection); + + if (!showConfirmButtons) { + onProcurementItemSelect?.(newSelection); + setOpen(false); + } + }, [onProcurementItemSelect, showConfirmButtons]); + + return ( + + + + + + + {title} + {description} + + +
+ +
+ + {showConfirmButtons && ( + + + + + )} +
+
+ ); +} -- cgit v1.2.3