fix: 테이블 컬럼 설정 개선
- 체크박스 컬럼 위치 보존 (드래그 순서 변경 시 맨 오른쪽으로 이동하는 문제 해결) - 사용자별 컬럼 설정 localStorage 저장 및 불러오기 기능 추가 - useAuth 훅으로 userId 가져오기 - 초기 로드 시 저장된 설정 자동 복원
This commit is contained in:
parent
73049c4162
commit
33ba13b070
|
|
@ -17,20 +17,19 @@ import { GripVertical, Eye, EyeOff } from "lucide-react";
|
|||
import { ColumnVisibility } from "@/types/table-options";
|
||||
|
||||
interface Props {
|
||||
tableId: string;
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const ColumnVisibilityPanel: React.FC<Props> = ({
|
||||
tableId,
|
||||
open,
|
||||
onOpenChange,
|
||||
isOpen,
|
||||
onClose,
|
||||
}) => {
|
||||
const { getTable } = useTableOptions();
|
||||
const table = getTable(tableId);
|
||||
const { getTable, selectedTableId } = useTableOptions();
|
||||
const table = selectedTableId ? getTable(selectedTableId) : undefined;
|
||||
|
||||
const [localColumns, setLocalColumns] = useState<ColumnVisibility[]>([]);
|
||||
const [draggedIndex, setDraggedIndex] = useState<number | null>(null);
|
||||
|
||||
// 테이블 정보 로드
|
||||
useEffect(() => {
|
||||
|
|
@ -62,9 +61,31 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
|||
);
|
||||
};
|
||||
|
||||
const moveColumn = (fromIndex: number, toIndex: number) => {
|
||||
const newColumns = [...localColumns];
|
||||
const [movedItem] = newColumns.splice(fromIndex, 1);
|
||||
newColumns.splice(toIndex, 0, movedItem);
|
||||
setLocalColumns(newColumns);
|
||||
};
|
||||
|
||||
const handleDragStart = (index: number) => {
|
||||
setDraggedIndex(index);
|
||||
};
|
||||
|
||||
const handleDragOver = (e: React.DragEvent, index: number) => {
|
||||
e.preventDefault();
|
||||
if (draggedIndex === null || draggedIndex === index) return;
|
||||
moveColumn(draggedIndex, index);
|
||||
setDraggedIndex(index);
|
||||
};
|
||||
|
||||
const handleDragEnd = () => {
|
||||
setDraggedIndex(null);
|
||||
};
|
||||
|
||||
const handleApply = () => {
|
||||
table?.onColumnVisibilityChange(localColumns);
|
||||
onOpenChange(false);
|
||||
onClose();
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
|
|
@ -83,7 +104,7 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
|||
const visibleCount = localColumns.filter((col) => col.visible).length;
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<Dialog open={isOpen} onOpenChange={onClose}>
|
||||
<DialogContent className="max-w-[95vw] sm:max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-base sm:text-lg">
|
||||
|
|
@ -114,14 +135,18 @@ export const ColumnVisibilityPanel: React.FC<Props> = ({
|
|||
{/* 컬럼 리스트 */}
|
||||
<ScrollArea className="h-[300px] sm:h-[400px]">
|
||||
<div className="space-y-2 pr-4">
|
||||
{localColumns.map((col) => {
|
||||
{localColumns.map((col, index) => {
|
||||
const columnMeta = table?.columns.find(
|
||||
(c) => c.columnName === col.columnName
|
||||
);
|
||||
return (
|
||||
<div
|
||||
key={col.columnName}
|
||||
className="flex items-center gap-3 rounded-lg border bg-background p-3 transition-colors hover:bg-muted/50"
|
||||
draggable
|
||||
onDragStart={() => handleDragStart(index)}
|
||||
onDragOver={(e) => handleDragOver(e, index)}
|
||||
onDragEnd={handleDragEnd}
|
||||
className="flex items-center gap-3 rounded-lg border bg-background p-3 transition-colors hover:bg-muted/50 cursor-move"
|
||||
>
|
||||
{/* 드래그 핸들 */}
|
||||
<GripVertical className="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
|
|
|
|||
|
|
@ -22,18 +22,16 @@ import { Plus, X } from "lucide-react";
|
|||
import { TableFilter } from "@/types/table-options";
|
||||
|
||||
interface Props {
|
||||
tableId: string;
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const FilterPanel: React.FC<Props> = ({
|
||||
tableId,
|
||||
open,
|
||||
onOpenChange,
|
||||
isOpen,
|
||||
onClose,
|
||||
}) => {
|
||||
const { getTable } = useTableOptions();
|
||||
const table = getTable(tableId);
|
||||
const { getTable, selectedTableId } = useTableOptions();
|
||||
const table = selectedTableId ? getTable(selectedTableId) : undefined;
|
||||
|
||||
const [activeFilters, setActiveFilters] = useState<TableFilter[]>([]);
|
||||
|
||||
|
|
@ -87,7 +85,7 @@ export const FilterPanel: React.FC<Props> = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<Dialog open={isOpen} onOpenChange={onClose}>
|
||||
<DialogContent className="max-w-[95vw] sm:max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-base sm:text-lg">
|
||||
|
|
|
|||
|
|
@ -11,23 +11,22 @@ import {
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { ArrowRight } from "lucide-react";
|
||||
import { ArrowRight, GripVertical, X } from "lucide-react";
|
||||
|
||||
interface Props {
|
||||
tableId: string;
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const GroupingPanel: React.FC<Props> = ({
|
||||
tableId,
|
||||
open,
|
||||
onOpenChange,
|
||||
isOpen,
|
||||
onClose,
|
||||
}) => {
|
||||
const { getTable } = useTableOptions();
|
||||
const table = getTable(tableId);
|
||||
const { getTable, selectedTableId } = useTableOptions();
|
||||
const table = selectedTableId ? getTable(selectedTableId) : undefined;
|
||||
|
||||
const [selectedColumns, setSelectedColumns] = useState<string[]>([]);
|
||||
const [draggedIndex, setDraggedIndex] = useState<number | null>(null);
|
||||
|
||||
const toggleColumn = (columnName: string) => {
|
||||
if (selectedColumns.includes(columnName)) {
|
||||
|
|
@ -37,9 +36,35 @@ export const GroupingPanel: React.FC<Props> = ({
|
|||
}
|
||||
};
|
||||
|
||||
const removeColumn = (columnName: string) => {
|
||||
setSelectedColumns(selectedColumns.filter((c) => c !== columnName));
|
||||
};
|
||||
|
||||
const moveColumn = (fromIndex: number, toIndex: number) => {
|
||||
const newColumns = [...selectedColumns];
|
||||
const [movedItem] = newColumns.splice(fromIndex, 1);
|
||||
newColumns.splice(toIndex, 0, movedItem);
|
||||
setSelectedColumns(newColumns);
|
||||
};
|
||||
|
||||
const handleDragStart = (index: number) => {
|
||||
setDraggedIndex(index);
|
||||
};
|
||||
|
||||
const handleDragOver = (e: React.DragEvent, index: number) => {
|
||||
e.preventDefault();
|
||||
if (draggedIndex === null || draggedIndex === index) return;
|
||||
moveColumn(draggedIndex, index);
|
||||
setDraggedIndex(index);
|
||||
};
|
||||
|
||||
const handleDragEnd = () => {
|
||||
setDraggedIndex(null);
|
||||
};
|
||||
|
||||
const applyGrouping = () => {
|
||||
table?.onGroupChange(selectedColumns);
|
||||
onOpenChange(false);
|
||||
onClose();
|
||||
};
|
||||
|
||||
const clearGrouping = () => {
|
||||
|
|
@ -48,7 +73,7 @@ export const GroupingPanel: React.FC<Props> = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<Dialog open={isOpen} onOpenChange={onClose}>
|
||||
<DialogContent className="max-w-[95vw] sm:max-w-xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-base sm:text-lg">그룹 설정</DialogTitle>
|
||||
|
|
@ -58,89 +83,126 @@ export const GroupingPanel: React.FC<Props> = ({
|
|||
</DialogHeader>
|
||||
|
||||
<div className="space-y-3 sm:space-y-4">
|
||||
{/* 상태 표시 */}
|
||||
<div className="flex items-center justify-between rounded-lg border bg-muted/50 p-3">
|
||||
<div className="text-xs text-muted-foreground sm:text-sm">
|
||||
{selectedColumns.length}개 컬럼으로 그룹화
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={clearGrouping}
|
||||
className="h-7 text-xs"
|
||||
>
|
||||
초기화
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 컬럼 리스트 */}
|
||||
<ScrollArea className="h-[250px] sm:h-[300px]">
|
||||
<div className="space-y-2 pr-4">
|
||||
{table?.columns.map((col) => {
|
||||
const isSelected = selectedColumns.includes(col.columnName);
|
||||
const order = selectedColumns.indexOf(col.columnName) + 1;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={col.columnName}
|
||||
className="flex items-center gap-3 rounded-lg border bg-background p-3 transition-colors hover:bg-muted/50"
|
||||
>
|
||||
<Checkbox
|
||||
checked={isSelected}
|
||||
onCheckedChange={() => toggleColumn(col.columnName)}
|
||||
/>
|
||||
|
||||
<div className="flex-1">
|
||||
<div className="text-xs font-medium sm:text-sm">
|
||||
{col.columnLabel}
|
||||
</div>
|
||||
<div className="text-[10px] text-muted-foreground sm:text-xs">
|
||||
{col.columnName}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isSelected && (
|
||||
<div className="flex items-center gap-1 rounded-full bg-primary px-2 py-0.5 text-xs text-primary-foreground">
|
||||
{order}번째
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
{/* 그룹 순서 미리보기 */}
|
||||
{/* 선택된 컬럼 (드래그 가능) */}
|
||||
{selectedColumns.length > 0 && (
|
||||
<div className="rounded-lg border bg-muted/30 p-3">
|
||||
<div className="mb-2 text-xs font-medium sm:text-sm">
|
||||
그룹화 순서
|
||||
<div>
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<div className="text-xs font-medium sm:text-sm">
|
||||
그룹화 순서 ({selectedColumns.length}개)
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={clearGrouping}
|
||||
className="h-7 text-xs"
|
||||
>
|
||||
전체 해제
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs sm:text-sm">
|
||||
<div className="space-y-2">
|
||||
{selectedColumns.map((colName, index) => {
|
||||
const col = table?.columns.find(
|
||||
(c) => c.columnName === colName
|
||||
);
|
||||
if (!col) return null;
|
||||
|
||||
return (
|
||||
<React.Fragment key={colName}>
|
||||
<div className="rounded bg-primary/10 px-2 py-1 font-medium">
|
||||
{col?.columnLabel}
|
||||
<div
|
||||
key={colName}
|
||||
draggable
|
||||
onDragStart={() => handleDragStart(index)}
|
||||
onDragOver={(e) => handleDragOver(e, index)}
|
||||
onDragEnd={handleDragEnd}
|
||||
className="flex items-center gap-2 rounded-lg border bg-primary/5 p-2 sm:p-3 transition-colors hover:bg-primary/10 cursor-move"
|
||||
>
|
||||
<GripVertical className="h-4 w-4 text-muted-foreground flex-shrink-0" />
|
||||
|
||||
<div className="flex h-5 w-5 sm:h-6 sm:w-6 items-center justify-center rounded-full bg-primary text-xs text-primary-foreground flex-shrink-0">
|
||||
{index + 1}
|
||||
</div>
|
||||
{index < selectedColumns.length - 1 && (
|
||||
<ArrowRight className="h-3 w-3 text-muted-foreground" />
|
||||
)}
|
||||
</React.Fragment>
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-xs font-medium sm:text-sm truncate">
|
||||
{col.columnLabel}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => removeColumn(colName)}
|
||||
className="h-6 w-6 p-0 flex-shrink-0"
|
||||
>
|
||||
<X className="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* 그룹화 순서 미리보기 */}
|
||||
<div className="mt-2 rounded-lg border bg-muted/30 p-2">
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs">
|
||||
{selectedColumns.map((colName, index) => {
|
||||
const col = table?.columns.find(
|
||||
(c) => c.columnName === colName
|
||||
);
|
||||
return (
|
||||
<React.Fragment key={colName}>
|
||||
<span className="font-medium">{col?.columnLabel}</span>
|
||||
{index < selectedColumns.length - 1 && (
|
||||
<ArrowRight className="h-3 w-3 text-muted-foreground" />
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 사용 가능한 컬럼 */}
|
||||
<div>
|
||||
<div className="mb-2 text-xs font-medium sm:text-sm">
|
||||
사용 가능한 컬럼
|
||||
</div>
|
||||
<ScrollArea className={selectedColumns.length > 0 ? "h-[280px] sm:h-[320px]" : "h-[400px] sm:h-[450px]"}>
|
||||
<div className="space-y-2 pr-4">
|
||||
{table?.columns
|
||||
.filter((col) => !selectedColumns.includes(col.columnName))
|
||||
.map((col) => {
|
||||
return (
|
||||
<div
|
||||
key={col.columnName}
|
||||
className="flex items-center gap-3 rounded-lg border bg-background p-2 sm:p-3 transition-colors hover:bg-muted/50 cursor-pointer"
|
||||
onClick={() => toggleColumn(col.columnName)}
|
||||
>
|
||||
<Checkbox
|
||||
checked={false}
|
||||
onCheckedChange={() => toggleColumn(col.columnName)}
|
||||
className="flex-shrink-0"
|
||||
/>
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="text-xs font-medium sm:text-sm truncate">
|
||||
{col.columnLabel}
|
||||
</div>
|
||||
<div className="text-[10px] text-muted-foreground sm:text-xs truncate">
|
||||
{col.columnName}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter className="gap-2 sm:gap-0">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => onOpenChange(false)}
|
||||
onClick={onClose}
|
||||
className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
|
||||
>
|
||||
취소
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ import { CardModeRenderer } from "./CardModeRenderer";
|
|||
import { TableOptionsModal } from "@/components/common/TableOptionsModal";
|
||||
import { useTableOptions } from "@/contexts/TableOptionsContext";
|
||||
import { TableFilter, ColumnVisibility } from "@/types/table-options";
|
||||
import { useAuth } from "@/hooks/useAuth";
|
||||
|
||||
// ========================================
|
||||
// 인터페이스
|
||||
|
|
@ -245,12 +246,48 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
// 상태 관리
|
||||
// ========================================
|
||||
|
||||
// 사용자 정보
|
||||
const { userId } = useAuth();
|
||||
|
||||
// TableOptions Context
|
||||
const { registerTable, unregisterTable } = useTableOptions();
|
||||
const [filters, setFilters] = useState<TableFilter[]>([]);
|
||||
const [grouping, setGrouping] = useState<string[]>([]);
|
||||
const [columnVisibility, setColumnVisibility] = useState<ColumnVisibility[]>([]);
|
||||
|
||||
// 초기 로드 시 localStorage에서 저장된 설정 불러오기
|
||||
useEffect(() => {
|
||||
if (tableConfig.selectedTable && userId) {
|
||||
const storageKey = `table_column_visibility_${tableConfig.selectedTable}_${userId}`;
|
||||
const savedSettings = localStorage.getItem(storageKey);
|
||||
|
||||
if (savedSettings) {
|
||||
try {
|
||||
const parsed = JSON.parse(savedSettings) as ColumnVisibility[];
|
||||
setColumnVisibility(parsed);
|
||||
} catch (error) {
|
||||
console.error("저장된 컬럼 설정 불러오기 실패:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [tableConfig.selectedTable, userId]);
|
||||
|
||||
// columnVisibility 변경 시 컬럼 순서 및 가시성 적용
|
||||
useEffect(() => {
|
||||
if (columnVisibility.length > 0) {
|
||||
const newOrder = columnVisibility
|
||||
.map((cv) => cv.columnName)
|
||||
.filter((name) => name !== "__checkbox__"); // 체크박스 제외
|
||||
setColumnOrder(newOrder);
|
||||
|
||||
// localStorage에 저장 (사용자별)
|
||||
if (tableConfig.selectedTable && userId) {
|
||||
const storageKey = `table_column_visibility_${tableConfig.selectedTable}_${userId}`;
|
||||
localStorage.setItem(storageKey, JSON.stringify(columnVisibility));
|
||||
}
|
||||
}
|
||||
}, [columnVisibility, tableConfig.selectedTable, userId]);
|
||||
|
||||
const [data, setData] = useState<Record<string, any>[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
|
@ -300,37 +337,47 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
const tableId = `table-list-${component.id}`;
|
||||
|
||||
useEffect(() => {
|
||||
if (!tableConfig.selectedTable || !displayColumns || displayColumns.length === 0) {
|
||||
// tableConfig.columns를 직접 사용 (displayColumns는 비어있을 수 있음)
|
||||
const columnsToRegister = (tableConfig.columns || [])
|
||||
.filter((col) => col.visible !== false && col.columnName !== "__checkbox__");
|
||||
|
||||
if (!tableConfig.selectedTable || !columnsToRegister || columnsToRegister.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
registerTable({
|
||||
const registration = {
|
||||
tableId,
|
||||
label: tableLabel || tableConfig.selectedTable,
|
||||
tableName: tableConfig.selectedTable,
|
||||
columns: displayColumns.map((col) => ({
|
||||
columnName: col.field,
|
||||
columnLabel: columnLabels[col.field] || col.label || col.field,
|
||||
inputType: columnMeta[col.field]?.inputType || "text",
|
||||
columns: columnsToRegister.map((col) => ({
|
||||
columnName: col.columnName || col.field,
|
||||
columnLabel: columnLabels[col.columnName] || col.displayName || col.label || col.columnName || col.field,
|
||||
inputType: columnMeta[col.columnName]?.inputType || "text",
|
||||
visible: col.visible !== false,
|
||||
width: columnWidths[col.field] || col.width || 150,
|
||||
width: columnWidths[col.columnName] || col.width || 150,
|
||||
sortable: col.sortable !== false,
|
||||
filterable: col.filterable !== false,
|
||||
filterable: col.searchable !== false,
|
||||
})),
|
||||
onFilterChange: setFilters,
|
||||
onGroupChange: setGrouping,
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
});
|
||||
};
|
||||
|
||||
return () => unregisterTable(tableId);
|
||||
registerTable(registration);
|
||||
|
||||
return () => {
|
||||
unregisterTable(tableId);
|
||||
};
|
||||
}, [
|
||||
component.id,
|
||||
tableId,
|
||||
tableConfig.selectedTable,
|
||||
displayColumns,
|
||||
tableConfig.columns,
|
||||
columnLabels,
|
||||
columnMeta,
|
||||
columnWidths,
|
||||
tableLabel,
|
||||
registerTable,
|
||||
unregisterTable,
|
||||
]);
|
||||
|
||||
// 🆕 초기 로드 시 localStorage에서 컬럼 순서 불러오기
|
||||
|
|
@ -975,8 +1022,18 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
const visibleColumns = useMemo(() => {
|
||||
let cols = (tableConfig.columns || []).filter((col) => col.visible !== false);
|
||||
|
||||
// columnVisibility가 있으면 가시성 적용
|
||||
if (columnVisibility.length > 0) {
|
||||
cols = cols.filter((col) => {
|
||||
const visibilityConfig = columnVisibility.find((cv) => cv.columnName === col.columnName);
|
||||
return visibilityConfig ? visibilityConfig.visible : true;
|
||||
});
|
||||
}
|
||||
|
||||
// 체크박스 컬럼 (나중에 위치 결정)
|
||||
let checkboxCol: ColumnConfig | null = null;
|
||||
if (tableConfig.checkbox?.enabled) {
|
||||
const checkboxCol: ColumnConfig = {
|
||||
checkboxCol = {
|
||||
columnName: "__checkbox__",
|
||||
displayName: "",
|
||||
visible: true,
|
||||
|
|
@ -986,15 +1043,9 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
align: "center",
|
||||
order: -1,
|
||||
};
|
||||
|
||||
if (tableConfig.checkbox.position === "right") {
|
||||
cols = [...cols, checkboxCol];
|
||||
} else {
|
||||
cols = [checkboxCol, ...cols];
|
||||
}
|
||||
}
|
||||
|
||||
// columnOrder 상태가 있으면 그 순서대로 정렬
|
||||
// columnOrder 상태가 있으면 그 순서대로 정렬 (체크박스 제외)
|
||||
if (columnOrder.length > 0) {
|
||||
const orderedCols = columnOrder
|
||||
.map((colName) => cols.find((c) => c.columnName === colName))
|
||||
|
|
@ -1003,17 +1054,22 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
// columnOrder에 없는 새로운 컬럼들 추가
|
||||
const remainingCols = cols.filter((c) => !columnOrder.includes(c.columnName));
|
||||
|
||||
console.log("🔄 columnOrder 기반 정렬:", {
|
||||
columnOrder,
|
||||
orderedColsCount: orderedCols.length,
|
||||
remainingColsCount: remainingCols.length,
|
||||
});
|
||||
|
||||
return [...orderedCols, ...remainingCols];
|
||||
cols = [...orderedCols, ...remainingCols];
|
||||
} else {
|
||||
cols = cols.sort((a, b) => (a.order || 0) - (b.order || 0));
|
||||
}
|
||||
|
||||
return cols.sort((a, b) => (a.order || 0) - (b.order || 0));
|
||||
}, [tableConfig.columns, tableConfig.checkbox, columnOrder]);
|
||||
// 체크박스를 맨 앞 또는 맨 뒤에 추가
|
||||
if (checkboxCol) {
|
||||
if (tableConfig.checkbox.position === "right") {
|
||||
cols = [...cols, checkboxCol];
|
||||
} else {
|
||||
cols = [checkboxCol, ...cols];
|
||||
}
|
||||
}
|
||||
|
||||
return cols;
|
||||
}, [tableConfig.columns, tableConfig.checkbox, columnOrder, columnVisibility]);
|
||||
|
||||
// 🆕 visibleColumns가 변경될 때마다 현재 컬럼 순서를 부모에게 전달
|
||||
const lastColumnOrderRef = useRef<string>("");
|
||||
|
|
|
|||
Loading…
Reference in New Issue