From 02eee979ea306061a118bb0c491e6e013e2ce3f0 Mon Sep 17 00:00:00 2001 From: leeheejin Date: Fri, 16 Jan 2026 15:17:49 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B3=A0=EC=B9=98=EA=B8=B0=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pivot-grid/PivotGridComponent.tsx | 53 ++++++++--- .../pivot-grid/components/FieldPanel.tsx | 88 ++++++++++++++++--- 2 files changed, 117 insertions(+), 24 deletions(-) diff --git a/frontend/lib/registry/components/pivot-grid/PivotGridComponent.tsx b/frontend/lib/registry/components/pivot-grid/PivotGridComponent.tsx index ccfbde88..c30472d8 100644 --- a/frontend/lib/registry/components/pivot-grid/PivotGridComponent.tsx +++ b/frontend/lib/registry/components/pivot-grid/PivotGridComponent.tsx @@ -432,10 +432,20 @@ export const PivotGridComponent: React.FC = ({ // 필터 영역 필드 const filterFields = useMemo( - () => - fields + () => { + const result = fields .filter((f) => f.area === "filter" && f.visible !== false) - .sort((a, b) => (a.areaIndex || 0) - (b.areaIndex || 0)), + .sort((a, b) => (a.areaIndex || 0) - (b.areaIndex || 0)); + + console.log("🔷 [filterFields] 필터 필드 계산:", { + totalFields: fields.length, + filterFieldsCount: result.length, + filterFieldNames: result.map(f => f.field), + allFieldAreas: fields.map(f => ({ field: f.field, area: f.area, visible: f.visible })), + }); + + return result; + }, [fields] ); @@ -715,7 +725,15 @@ export const PivotGridComponent: React.FC = ({ // 필드 변경 const handleFieldsChange = useCallback( (newFields: PivotFieldConfig[]) => { + console.log("🔷 [handleFieldsChange] 필드 변경:", { + totalFields: newFields.length, + filterFields: newFields.filter(f => f.area === "filter").length, + filterFieldNames: newFields.filter(f => f.area === "filter").map(f => f.field), + changedFields: newFields.filter(f => f.area === "filter"), + }); + console.log("🔷 [handleFieldsChange] setFields 호출 전"); setFields(newFields); + console.log("🔷 [handleFieldsChange] setFields 호출 후"); }, [] ); @@ -1023,10 +1041,12 @@ export const PivotGridComponent: React.FC = ({ console.log("피벗 상태가 저장되었습니다."); }, [saveStateToStorage]); - // 상태 초기화 + // 상태 초기화 (확장/축소, 정렬, 필터만 초기화, 필드 설정은 유지) const handleResetState = useCallback(() => { + // 로컬 스토리지에서 상태 제거 localStorage.removeItem(stateStorageKey); - setFields(initialFields); + + // 확장/축소, 정렬, 필터 상태만 초기화 setPivotState({ expandedRowPaths: [], expandedColumnPaths: [], @@ -1037,7 +1057,10 @@ export const PivotGridComponent: React.FC = ({ setColumnWidths({}); setSelectedCell(null); setSelectionRange(null); - }, [stateStorageKey, initialFields]); + + // 🆕 필드 설정은 유지 (initialFields로 되돌리지 않음) + console.log("🔷 피벗 상태가 초기화되었습니다 (필드 설정은 유지)"); + }, [stateStorageKey]); // 필드 숨기기/표시 상태 const [hiddenFields, setHiddenFields] = useState>(new Set()); @@ -1617,19 +1640,25 @@ export const PivotGridComponent: React.FC = ({ } /> diff --git a/frontend/lib/registry/components/pivot-grid/components/FieldPanel.tsx b/frontend/lib/registry/components/pivot-grid/components/FieldPanel.tsx index fed43afb..08dca70e 100644 --- a/frontend/lib/registry/components/pivot-grid/components/FieldPanel.tsx +++ b/frontend/lib/registry/components/pivot-grid/components/FieldPanel.tsx @@ -25,6 +25,7 @@ import { horizontalListSortingStrategy, useSortable, } from "@dnd-kit/sortable"; +import { useDroppable } from "@dnd-kit/core"; import { CSS } from "@dnd-kit/utilities"; import { cn } from "@/lib/utils"; import { PivotFieldConfig, PivotAreaType } from "../types"; @@ -244,22 +245,31 @@ const DroppableArea: React.FC = ({ const areaFields = fields.filter((f) => f.area === area && f.visible !== false); const fieldIds = areaFields.map((f) => `${area}-${f.field}`); + // 🆕 드롭 가능 영역 설정 + const { setNodeRef, isOver: isOverDroppable } = useDroppable({ + id: area, // "filter", "column", "row", "data" + }); + + const finalIsOver = isOver || isOverDroppable; + return (
{/* 영역 헤더 */} -
+
{icon} {title} {areaFields.length > 0 && ( - + {areaFields.length} )} @@ -267,11 +277,16 @@ const DroppableArea: React.FC = ({ {/* 필드 목록 */} -
+
{areaFields.length === 0 ? ( - - 필드를 여기로 드래그 - +
+ + ← 필드를 여기로 드래그하세요 + +
) : ( areaFields.map((field) => ( = ({ return; } - // 드롭 영역 감지 + // 드롭 영역 감지 (영역 자체의 ID를 우선 확인) const overId = over.id as string; + + // 1. overId가 영역 자체인 경우 (filter, column, row, data) + if (["filter", "column", "row", "data"].includes(overId)) { + setOverArea(overId as PivotAreaType); + console.log("🔷 [handleDragOver] 영역 감지:", overId); + return; + } + + // 2. overId가 필드인 경우 (예: row-part_name) const targetArea = overId.split("-")[0] as PivotAreaType; if (["filter", "column", "row", "data"].includes(targetArea)) { setOverArea(targetArea); + console.log("🔷 [handleDragOver] 필드 영역 감지:", targetArea); } }; // 드래그 종료 const handleDragEnd = (event: DragEndEvent) => { const { active, over } = event; + const currentOverArea = overArea; // handleDragOver에서 감지한 영역 저장 setActiveId(null); setOverArea(null); - if (!over) return; + if (!over) { + console.log("🔷 [FieldPanel] 드롭 대상 없음"); + return; + } const activeId = active.id as string; const overId = over.id as string; + console.log("🔷 [FieldPanel] 드래그 종료:", { + activeId, + overId, + detectedOverArea: currentOverArea, + }); + // 필드 정보 파싱 const [sourceArea, sourceField] = activeId.split("-") as [ PivotAreaType, string ]; - const [targetArea] = overId.split("-") as [PivotAreaType, string]; + + // targetArea 결정: handleDragOver에서 감지한 영역 우선 사용 + let targetArea: PivotAreaType; + if (currentOverArea) { + targetArea = currentOverArea; + } else if (["filter", "column", "row", "data"].includes(overId)) { + targetArea = overId as PivotAreaType; + } else { + targetArea = overId.split("-")[0] as PivotAreaType; + } + + console.log("🔷 [FieldPanel] 파싱 결과:", { + sourceArea, + sourceField, + targetArea, + usedOverArea: !!currentOverArea, + }); // 같은 영역 내 정렬 if (sourceArea === targetArea) { @@ -396,6 +447,12 @@ export const FieldPanel: React.FC = ({ // 다른 영역으로 이동 if (["filter", "column", "row", "data"].includes(targetArea)) { + console.log("🔷 [FieldPanel] 영역 이동:", { + field: sourceField, + from: sourceArea, + to: targetArea, + }); + const newFields = fields.map((f) => { if (f.field === sourceField && f.area === sourceArea) { return { @@ -406,6 +463,13 @@ export const FieldPanel: React.FC = ({ } return f; }); + + console.log("🔷 [FieldPanel] 변경된 필드:", { + totalFields: newFields.length, + filterFields: newFields.filter(f => f.area === "filter").length, + changedField: newFields.find(f => f.field === sourceField), + }); + onFieldsChange(newFields); } };