Merge branch 'ksh'
This commit is contained in:
commit
9c8ec879d9
|
|
@ -42,6 +42,7 @@ export function ItemSelectionModal({
|
|||
// 모달 열릴 때 초기 검색
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
console.log("🚪 모달 열림 - uniqueField:", uniqueField, "multiSelect:", multiSelect);
|
||||
search("", 1); // 빈 검색어로 전체 목록 조회
|
||||
setSelectedItems([]);
|
||||
} else {
|
||||
|
|
@ -56,26 +57,67 @@ export function ItemSelectionModal({
|
|||
};
|
||||
|
||||
const handleToggleItem = (item: any) => {
|
||||
const itemValue = uniqueField ? item[uniqueField] : undefined;
|
||||
|
||||
console.log("🖱️ 행 클릭:", {
|
||||
item,
|
||||
uniqueField,
|
||||
itemValue,
|
||||
currentSelected: selectedItems.length,
|
||||
selectedValues: uniqueField ? selectedItems.map(s => s[uniqueField]) : []
|
||||
});
|
||||
|
||||
if (!multiSelect) {
|
||||
setSelectedItems([item]);
|
||||
return;
|
||||
}
|
||||
|
||||
const isSelected = selectedItems.some((selected) =>
|
||||
uniqueField
|
||||
? selected[uniqueField] === item[uniqueField]
|
||||
: selected === item
|
||||
);
|
||||
// uniqueField 값이 undefined인 경우 객체 참조로 비교
|
||||
if (uniqueField && (itemValue === undefined || itemValue === null)) {
|
||||
console.warn(`⚠️ uniqueField "${uniqueField}"의 값이 undefined입니다. 객체 참조로 비교합니다.`);
|
||||
const itemIsSelected = selectedItems.includes(item);
|
||||
|
||||
console.log("📊 선택 상태 (객체 참조):", itemIsSelected);
|
||||
|
||||
if (itemIsSelected) {
|
||||
const newSelected = selectedItems.filter((selected) => selected !== item);
|
||||
console.log("➖ 제거 후:", newSelected.length);
|
||||
setSelectedItems(newSelected);
|
||||
} else {
|
||||
console.log("➕ 추가");
|
||||
setSelectedItems([...selectedItems, item]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSelected) {
|
||||
setSelectedItems(
|
||||
selectedItems.filter((selected) =>
|
||||
uniqueField
|
||||
? selected[uniqueField] !== item[uniqueField]
|
||||
: selected !== item
|
||||
)
|
||||
);
|
||||
const itemIsSelected = selectedItems.some((selected) => {
|
||||
if (!uniqueField) {
|
||||
return selected === item;
|
||||
}
|
||||
const selectedValue = selected[uniqueField];
|
||||
if (selectedValue === undefined || selectedValue === null) {
|
||||
return false;
|
||||
}
|
||||
return selectedValue === itemValue;
|
||||
});
|
||||
|
||||
console.log("📊 선택 상태:", itemIsSelected);
|
||||
|
||||
if (itemIsSelected) {
|
||||
const newSelected = selectedItems.filter((selected) => {
|
||||
if (!uniqueField) {
|
||||
return selected !== item;
|
||||
}
|
||||
const selectedValue = selected[uniqueField];
|
||||
if (selectedValue === undefined || selectedValue === null) {
|
||||
return true;
|
||||
}
|
||||
return selectedValue !== itemValue;
|
||||
});
|
||||
console.log("➖ 제거 후:", newSelected.length);
|
||||
setSelectedItems(newSelected);
|
||||
} else {
|
||||
console.log("➕ 추가");
|
||||
setSelectedItems([...selectedItems, item]);
|
||||
}
|
||||
};
|
||||
|
|
@ -98,13 +140,46 @@ export function ItemSelectionModal({
|
|||
|
||||
// 선택된 항목인지 확인
|
||||
const isSelected = (item: any): boolean => {
|
||||
return selectedItems.some((selected) =>
|
||||
uniqueField
|
||||
? selected[uniqueField] === item[uniqueField]
|
||||
: selected === item
|
||||
);
|
||||
if (!uniqueField) {
|
||||
return selectedItems.includes(item);
|
||||
}
|
||||
|
||||
const itemValue = item[uniqueField];
|
||||
|
||||
// uniqueField 값이 undefined인 경우 객체 참조로 비교
|
||||
if (itemValue === undefined || itemValue === null) {
|
||||
console.warn(`⚠️ uniqueField "${uniqueField}"의 값이 undefined입니다. 객체 참조로 비교합니다.`);
|
||||
return selectedItems.includes(item);
|
||||
}
|
||||
|
||||
const result = selectedItems.some((selected) => {
|
||||
const selectedValue = selected[uniqueField];
|
||||
|
||||
// selectedValue도 undefined면 안전하게 처리
|
||||
if (selectedValue === undefined || selectedValue === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isMatch = selectedValue === itemValue;
|
||||
|
||||
if (isMatch) {
|
||||
console.log("✅ 매칭 발견:", {
|
||||
selectedValue,
|
||||
itemValue,
|
||||
uniqueField
|
||||
});
|
||||
}
|
||||
|
||||
return isMatch;
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// 유효한 컬럼만 필터링
|
||||
const validColumns = sourceColumns.filter(col => col != null && col !== "");
|
||||
const totalColumns = validColumns.length + (multiSelect ? 1 : 0);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-[95vw] sm:max-w-[900px] max-h-[90vh] overflow-y-auto">
|
||||
|
|
@ -147,6 +222,11 @@ export function ItemSelectionModal({
|
|||
{selectedItems.length > 0 && (
|
||||
<div className="text-sm text-primary">
|
||||
{selectedItems.length}개 항목 선택됨
|
||||
{uniqueField && (
|
||||
<span className="ml-2 text-xs text-muted-foreground">
|
||||
({selectedItems.map(item => item[uniqueField]).join(", ")})
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -168,7 +248,7 @@ export function ItemSelectionModal({
|
|||
선택
|
||||
</th>
|
||||
)}
|
||||
{sourceColumns.map((col) => (
|
||||
{validColumns.map((col) => (
|
||||
<th
|
||||
key={col}
|
||||
className="px-4 py-2 text-left font-medium text-muted-foreground"
|
||||
|
|
@ -182,7 +262,7 @@ export function ItemSelectionModal({
|
|||
{loading && filteredResults.length === 0 ? (
|
||||
<tr>
|
||||
<td
|
||||
colSpan={sourceColumns.length + (multiSelect ? 1 : 0)}
|
||||
colSpan={totalColumns}
|
||||
className="px-4 py-8 text-center"
|
||||
>
|
||||
<Loader2 className="h-6 w-6 animate-spin mx-auto" />
|
||||
|
|
@ -192,7 +272,7 @@ export function ItemSelectionModal({
|
|||
) : filteredResults.length === 0 ? (
|
||||
<tr>
|
||||
<td
|
||||
colSpan={sourceColumns.length + (multiSelect ? 1 : 0)}
|
||||
colSpan={totalColumns}
|
||||
className="px-4 py-8 text-center text-muted-foreground"
|
||||
>
|
||||
{results.length > 0
|
||||
|
|
@ -203,10 +283,22 @@ export function ItemSelectionModal({
|
|||
) : (
|
||||
filteredResults.map((item, index) => {
|
||||
const selected = isSelected(item);
|
||||
const uniqueFieldValue = uniqueField ? item[uniqueField] : undefined;
|
||||
const itemKey = (uniqueFieldValue !== undefined && uniqueFieldValue !== null)
|
||||
? uniqueFieldValue
|
||||
: `item-${index}`;
|
||||
|
||||
console.log("🔍 행 렌더링:", {
|
||||
index,
|
||||
itemKey,
|
||||
selected,
|
||||
uniqueFieldValue,
|
||||
selectedCount: selectedItems.length
|
||||
});
|
||||
|
||||
return (
|
||||
<tr
|
||||
key={index}
|
||||
key={itemKey}
|
||||
className={`border-t transition-colors ${
|
||||
selected
|
||||
? "bg-primary/10"
|
||||
|
|
@ -215,14 +307,20 @@ export function ItemSelectionModal({
|
|||
onClick={() => handleToggleItem(item)}
|
||||
>
|
||||
{multiSelect && (
|
||||
<td className="px-4 py-2">
|
||||
<Checkbox
|
||||
checked={selected}
|
||||
onCheckedChange={() => handleToggleItem(item)}
|
||||
/>
|
||||
<td
|
||||
className="px-4 py-2"
|
||||
onClick={(e) => {
|
||||
// 체크박스 영역 클릭을 행 클릭으로 전파
|
||||
e.stopPropagation();
|
||||
handleToggleItem(item);
|
||||
}}
|
||||
>
|
||||
<div className="pointer-events-none">
|
||||
<Checkbox checked={selected} readOnly />
|
||||
</div>
|
||||
</td>
|
||||
)}
|
||||
{sourceColumns.map((col) => (
|
||||
{validColumns.map((col) => (
|
||||
<td key={col} className="px-4 py-2">
|
||||
{item[col] || "-"}
|
||||
</td>
|
||||
|
|
|
|||
Loading…
Reference in New Issue