summaryrefslogtreecommitdiff
path: root/components/common
diff options
context:
space:
mode:
Diffstat (limited to 'components/common')
-rw-r--r--components/common/material/README.md82
-rw-r--r--components/common/material/material-selector.tsx36
2 files changed, 109 insertions, 9 deletions
diff --git a/components/common/material/README.md b/components/common/material/README.md
new file mode 100644
index 00000000..30f16d38
--- /dev/null
+++ b/components/common/material/README.md
@@ -0,0 +1,82 @@
+# MaterialSelector
+
+자재그룹코드를 검색하고 선택할 수 있는 드롭다운 컴포넌트
+
+## 주요 기능
+
+- 자재그룹코드 및 자재그룹코드명(=자재명) 으로 검색 및 선택
+- 단일/다중 선택 모드
+- 페이지네이션 10페이지로 구현
+- 초기 데이터 로드 여부 설정 가능 (기본값은 초기 데이터 로드 활성화, 벤더 회원가입시 공급품목에서는 비활성화)
+
+## 사용 예시
+
+`selectedMaterials` 상태에 선택된 자재 정보가 저장되며, 이를 통해 선택된 자재를 활용할 수 있습니다.
+
+### 기본 사용법
+```tsx
+import { MaterialSelector } from "@/components/common/material/material-selector";
+
+function MyComponent() {
+ const [selectedMaterials, setSelectedMaterials] = useState<MaterialSearchItem[]>([]);
+
+ return (
+ <MaterialSelector
+ selectedMaterials={selectedMaterials}
+ onMaterialsChange={setSelectedMaterials}
+ />
+ );
+}
+```
+
+### 단일 선택 모드
+```tsx
+<MaterialSelector
+ selectedMaterials={selectedMaterials}
+ onMaterialsChange={setSelectedMaterials}
+ singleSelect={true}
+ placeholder="자재를 선택하세요..."
+/>
+```
+
+### 초기 데이터 로드 비활성화
+```tsx
+<MaterialSelector
+ selectedMaterials={selectedMaterials}
+ onMaterialsChange={setSelectedMaterials}
+ showInitialData={false}
+/>
+```
+
+### 최대 선택 개수 제한
+```tsx
+<MaterialSelector
+ selectedMaterials={selectedMaterials}
+ onMaterialsChange={setSelectedMaterials}
+ maxSelections={5}
+/>
+```
+
+### 특정 자재코드 제외
+```tsx
+const excludeCodes = new Set(['MAT001', 'MAT002']);
+
+<MaterialSelector
+ selectedMaterials={selectedMaterials}
+ onMaterialsChange={setSelectedMaterials}
+ excludeMaterialCodes={excludeCodes}
+/>
+```
+
+## Props
+
+- `selectedMaterials` (`MaterialSearchItem[]`, 기본값: `[]`) - 선택된 자재 목록
+- `onMaterialsChange` (`(materials: MaterialSearchItem[]) => void`) - 자재 선택 변경 콜백
+- `singleSelect` (`boolean`, 기본값: `false`) - 단일 선택 모드 여부
+- `showInitialData` (`boolean`, 기본값: `true`) - 초기 클릭시 자재 목록 로드 여부
+- `maxSelections` (`number`) - 최대 선택 가능 개수
+- `excludeMaterialCodes` (`Set<string>`) - 제외할 자재그룹코드 목록
+- `disabled` (`boolean`, 기본값: `false`) - 비활성화 여부
+- `placeholder` (`string`, 기본값: `"자재를 검색하세요..."`) - 검색 입력 플레이스홀더
+- `noValuePlaceHolder` (`string`, 기본값: `"자재를 검색해주세요"`) - 선택된 값이 없을 때 표시 텍스트
+- `closeOnSelect` (`boolean`, 기본값: `true`) - 선택 후 드롭다운 닫기 여부
diff --git a/components/common/material/material-selector.tsx b/components/common/material/material-selector.tsx
index b24a2f4f..67b8c25c 100644
--- a/components/common/material/material-selector.tsx
+++ b/components/common/material/material-selector.tsx
@@ -4,7 +4,6 @@ import React, { useState, useCallback } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
-import { ScrollArea } from "@/components/ui/scroll-area";
import {
Popover,
PopoverContent,
@@ -33,6 +32,7 @@ interface MaterialSelectorProps {
className?: string;
closeOnSelect?: boolean;
excludeMaterialCodes?: Set<string>; // 제외할 자재그룹코드들
+ showInitialData?: boolean; // 초기 클릭시 자재그룹들을 로드할지 여부
}
export function MaterialSelector({
@@ -45,7 +45,8 @@ export function MaterialSelector({
maxSelections,
className,
closeOnSelect = true,
- excludeMaterialCodes
+ excludeMaterialCodes,
+ showInitialData = true
}: MaterialSelectorProps) {
const [open, setOpen] = useState(false);
@@ -54,6 +55,7 @@ export function MaterialSelector({
const [isSearching, setIsSearching] = useState(false);
const [searchError, setSearchError] = useState<string | null>(null);
const [currentPage, setCurrentPage] = useState(1);
+ const [initialDataLoaded, setInitialDataLoaded] = useState(false);
const [pagination, setPagination] = useState({
page: 1,
perPage: 10,
@@ -107,11 +109,22 @@ export function MaterialSelector({
}
}, []);
+ // Popover 열림시 초기 데이터 로드
+ React.useEffect(() => {
+ if (open && showInitialData && !initialDataLoaded && !searchQuery.trim()) {
+ setInitialDataLoaded(true);
+ performSearch("", 1); // 빈 쿼리로 초기 데이터 로드
+ }
+ }, [open, showInitialData, initialDataLoaded, searchQuery, performSearch]);
+
// Debounced 검색어 변경 시 검색 실행 (검색어가 있을 때만)
React.useEffect(() => {
if (debouncedSearchQuery.trim()) {
setCurrentPage(1);
performSearch(debouncedSearchQuery, 1);
+ } else if (showInitialData && initialDataLoaded) {
+ // 검색어가 없고 초기 데이터를 보여주는 경우 초기 데이터 유지
+ // 아무것도 하지 않음 (기존 데이터 유지)
} else {
// 검색어가 없으면 결과 초기화
setSearchResults([]);
@@ -124,14 +137,15 @@ export function MaterialSelector({
hasPrevPage: false,
});
}
- }, [debouncedSearchQuery, performSearch]);
+ }, [debouncedSearchQuery, performSearch, showInitialData, initialDataLoaded]);
// 페이지 변경 처리 - useCallback으로 메모이제이션
const handlePageChange = useCallback((newPage: number) => {
if (newPage >= 1 && newPage <= pagination.pageCount) {
- performSearch(debouncedSearchQuery, newPage);
+ const query = debouncedSearchQuery.trim() || (showInitialData && initialDataLoaded ? "" : debouncedSearchQuery);
+ performSearch(query, newPage);
}
- }, [pagination.pageCount, performSearch, debouncedSearchQuery]);
+ }, [pagination.pageCount, performSearch, debouncedSearchQuery, showInitialData, initialDataLoaded]);
// 자재 선택 처리 - useCallback으로 메모이제이션
const handleMaterialSelect = useCallback((material: MaterialSearchItem) => {
@@ -244,11 +258,15 @@ export function MaterialSelector({
</div>
<CommandList>
- <ScrollArea className="h-64">
- {!searchQuery.trim() ? (
+ <div className="h-64 overflow-y-auto">
+ {!searchQuery.trim() && !showInitialData ? (
<div className="p-4 text-center text-sm text-muted-foreground">
자재를 검색하려면 검색어를 입력해주세요.
</div>
+ ) : !searchQuery.trim() && showInitialData && !initialDataLoaded ? (
+ <div className="p-4 text-center text-sm text-muted-foreground">
+ 자재 목록을 로드하려면 클릭해주세요.
+ </div>
) : isSearching ? (
<div className="p-4 text-center text-sm text-muted-foreground">
검색 중...
@@ -303,7 +321,7 @@ export function MaterialSelector({
)}
</div>
<div className="text-xs text-muted-foreground">
- 코드: {material.materialGroupCode}
+ 자재그룹코드: {material.materialGroupCode}
</div>
</div>
</CommandItem>
@@ -311,7 +329,7 @@ export function MaterialSelector({
})}
</CommandGroup>
)}
- </ScrollArea>
+ </div>
{/* 페이지네이션 */}
{searchResults.length > 0 && pagination.pageCount > 1 && (