From 7433eea5b4bbc0899e255b88e1a7e91f26e9d95b Mon Sep 17 00:00:00 2001 From: joonhoekim <26rote@gmail.com> Date: Wed, 17 Sep 2025 18:04:10 +0900 Subject: (김준회) 자재그룹 선택기 오류수정, 공용사용을 위한 다이얼로그 컴포넌트 구현, data-table 오류 수정 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../material-group-selector-dialog-single.tsx | 208 +++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 components/common/material/material-group-selector-dialog-single.tsx (limited to 'components/common/material/material-group-selector-dialog-single.tsx') diff --git a/components/common/material/material-group-selector-dialog-single.tsx b/components/common/material/material-group-selector-dialog-single.tsx new file mode 100644 index 00000000..bb039d0a --- /dev/null +++ b/components/common/material/material-group-selector-dialog-single.tsx @@ -0,0 +1,208 @@ +"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 { MaterialGroupSelector } from "./material-group-selector"; +import { MaterialSearchItem } from "@/lib/material/material-group-service"; + +/** + * 자재그룹 단일 선택 Dialog 컴포넌트 + * + * @description + * - MaterialGroupSelector를 Dialog로 래핑한 단일 선택 컴포넌트 + * - 버튼 클릭 시 Dialog가 열리고, 자재를 선택하면 Dialog가 닫히며 결과를 반환 + * + * @MaterialSearchItem_Structure + * 상태에서 관리되는 자재그룹 객체의 형태: + * ```typescript + * interface MaterialSearchItem { + * materialGroupCode: string; // 자재그룹코드 (예: "BG2001") + * materialGroupDescription: string; // 자재그룹명 (예: "DOUBLE WETDOOR HINGE") + * materialGroupUom?: string; // 단위 (예: "EA", "KG") + * displayText: string; // 표시용 텍스트 (code + " - " + description) + * } + * ``` + * + * @state + * - open: Dialog 열림/닫힘 상태 + * - selectedMaterial: 현재 선택된 자재 (단일) + * - tempSelectedMaterial: Dialog 내에서 임시로 선택된 자재 (확인 버튼 클릭 전까지) + * + * @callback + * - onMaterialSelect: 자재 선택 완료 시 호출되는 콜백 + * - 매개변수: MaterialSearchItem | null + * - 선택된 자재 정보 또는 null (선택 해제 시) + * + * @usage + * ```tsx + * { + * setSelectedMaterial(material); + * console.log('선택된 자재:', material); + * }} + * placeholder="자재를 검색하세요..." + * /> + * ``` + */ + +interface MaterialGroupSelectorDialogSingleProps { + /** Dialog를 여는 트리거 버튼 텍스트 */ + triggerLabel?: string; + /** 현재 선택된 자재 */ + selectedMaterial?: MaterialSearchItem | null; + /** 자재 선택 완료 시 호출되는 콜백 */ + onMaterialSelect?: (material: MaterialSearchItem | null) => void; + /** 검색 입력창 placeholder */ + placeholder?: string; + /** Dialog 제목 */ + title?: string; + /** Dialog 설명 */ + description?: string; + /** 트리거 버튼 비활성화 여부 */ + disabled?: boolean; + /** 트리거 버튼 variant */ + triggerVariant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link"; + /** 제외할 자재그룹코드들 */ + excludeMaterialCodes?: Set; + /** 초기 데이터 표시 여부 */ + showInitialData?: boolean; +} + +export function MaterialGroupSelectorDialogSingle({ + triggerLabel = "자재 선택", + selectedMaterial = null, + onMaterialSelect, + placeholder = "자재를 검색하세요...", + title = "자재 선택", + description = "원하는 자재를 검색하고 선택해주세요.", + disabled = false, + triggerVariant = "outline", + excludeMaterialCodes, + showInitialData = true, +}: MaterialGroupSelectorDialogSingleProps) { + // Dialog 열림/닫힘 상태 + const [open, setOpen] = useState(false); + + // Dialog 내에서 임시로 선택된 자재 (확인 버튼 클릭 전까지) + const [tempSelectedMaterial, setTempSelectedMaterial] = useState(null); + + // Dialog 열림 시 현재 선택된 자재로 임시 선택 초기화 + const handleOpenChange = useCallback((newOpen: boolean) => { + setOpen(newOpen); + if (newOpen) { + setTempSelectedMaterial(selectedMaterial || null); + } + }, [selectedMaterial]); + + // 자재 선택 처리 (Dialog 내에서) + const handleMaterialChange = useCallback((materials: MaterialSearchItem[]) => { + setTempSelectedMaterial(materials.length > 0 ? materials[0] : null); + }, []); + + // 확인 버튼 클릭 시 선택 완료 + const handleConfirm = useCallback(() => { + onMaterialSelect?.(tempSelectedMaterial); + setOpen(false); + }, [tempSelectedMaterial, onMaterialSelect]); + + // 취소 버튼 클릭 시 + const handleCancel = useCallback(() => { + setTempSelectedMaterial(selectedMaterial || null); + setOpen(false); + }, [selectedMaterial]); + + // 선택 해제 + const handleClear = useCallback(() => { + setTempSelectedMaterial(null); + }, []); + + return ( + + + + + + + + {title} + {description} + + +
+ +
+ + + + {tempSelectedMaterial && ( + + )} + + +
+
+ ); +} + +/** + * 사용 예시: + * + * ```tsx + * const [selectedMaterial, setSelectedMaterial] = useState(null); + * + * return ( + * { + * setSelectedMaterial(material); + * if (material) { + * console.log('선택된 자재:', { + * code: material.materialGroupCode, + * description: material.materialGroupDescription, + * uom: material.materialGroupUom + * }); + * } else { + * console.log('자재 선택이 해제되었습니다.'); + * } + * }} + * title="자재 선택" + * description="필요한 자재를 검색하고 선택해주세요." + * /> + * ); + * ``` + */ \ No newline at end of file -- cgit v1.2.3