From 2a3cc7ba006ecf3ea92df4928624fd1057a45c32 Mon Sep 17 00:00:00 2001 From: leeheejin Date: Fri, 16 Jan 2026 17:39:35 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B0=B0=ED=8F=AC=EB=8B=A4=EC=8B=9C=20?= =?UTF-8?q?=EB=90=98=EA=B2=8C=20=EA=B3=A0=EC=B3=90=EB=86=93=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pivot-grid/PivotGridComponent.tsx | 101 +++++++++--------- 1 file changed, 48 insertions(+), 53 deletions(-) diff --git a/frontend/lib/registry/components/pivot-grid/PivotGridComponent.tsx b/frontend/lib/registry/components/pivot-grid/PivotGridComponent.tsx index f7c03b7d..9135231c 100644 --- a/frontend/lib/registry/components/pivot-grid/PivotGridComponent.tsx +++ b/frontend/lib/registry/components/pivot-grid/PivotGridComponent.tsx @@ -384,20 +384,36 @@ export const PivotGridComponent: React.FC = ({ localStorage.setItem(stateStorageKey, JSON.stringify(stateToSave)); }, [fields, pivotState, sortConfig, columnWidths, stateStorageKey]); - // 상태 복원 (localStorage) + // 상태 복원 (localStorage) - 프로덕션 안전성 강화 useEffect(() => { if (typeof window === "undefined") return; - const savedState = localStorage.getItem(stateStorageKey); - if (savedState) { - try { - const parsed = JSON.parse(savedState); - if (parsed.fields) setFields(parsed.fields); - if (parsed.pivotState) setPivotState(parsed.pivotState); - if (parsed.sortConfig) setSortConfig(parsed.sortConfig); - if (parsed.columnWidths) setColumnWidths(parsed.columnWidths); - } catch (e) { - console.warn("피벗 상태 복원 실패:", e); + + try { + const savedState = localStorage.getItem(stateStorageKey); + if (!savedState) return; + + const parsed = JSON.parse(savedState); + + // 필드 복원 시 유효성 검사 (중요!) + if (parsed.fields && Array.isArray(parsed.fields) && parsed.fields.length > 0) { + // 저장된 필드가 현재 데이터와 호환되는지 확인 + const validFields = parsed.fields.filter((f: PivotFieldConfig) => + f && typeof f.field === "string" && typeof f.area === "string" + ); + + if (validFields.length > 0) { + setFields(validFields); + } } + + // 나머지 상태 복원 + if (parsed.pivotState) setPivotState(parsed.pivotState); + if (parsed.sortConfig) setSortConfig(parsed.sortConfig); + if (parsed.columnWidths) setColumnWidths(parsed.columnWidths); + } catch (e) { + console.warn("피벗 상태 복원 실패, localStorage 초기화:", e); + // 손상된 상태는 제거 + localStorage.removeItem(stateStorageKey); } }, [stateStorageKey]); @@ -512,15 +528,15 @@ export const PivotGridComponent: React.FC = ({ return null; } - const visibleFields = fields.filter((f) => f.visible !== false); + // FieldChooser에서 이미 필드를 완전히 제거하므로 visible 필터링 불필요 // 행, 열, 데이터 영역에 필드가 하나도 없으면 null 반환 (필터는 제외) - if (visibleFields.filter((f) => ["row", "column", "data"].includes(f.area)).length === 0) { + if (fields.filter((f) => ["row", "column", "data"].includes(f.area)).length === 0) { return null; } const result = processPivotData( filteredData, - visibleFields, + fields, pivotState.expandedRowPaths, pivotState.expandedColumnPaths ); @@ -536,32 +552,18 @@ export const PivotGridComponent: React.FC = ({ }); return result; - }, [ - filteredData, - fields, - JSON.stringify(pivotState.expandedRowPaths), - JSON.stringify(pivotState.expandedColumnPaths) - ]); + }, [filteredData, fields, pivotState.expandedRowPaths, pivotState.expandedColumnPaths]); - // 🆕 초기 로드 시 첫 레벨 자동 확장 + // 초기 로드 시 첫 레벨 자동 확장 useEffect(() => { if (pivotResult && pivotResult.flatRows.length > 0 && !isInitialExpanded) { - console.log("🔶 피벗 결과 생성됨:", { - flatRowsCount: pivotResult.flatRows.length, - expandedRowPaths: pivotState.expandedRowPaths.length, - isInitialExpanded, - }); - // 첫 레벨 행들의 경로 수집 (level 0인 행들) - const firstLevelRows = pivotResult.flatRows.filter(row => row.level === 0 && row.hasChildren); - - console.log("🔶 첫 레벨 행 (level 0, hasChildren):", firstLevelRows.map(r => ({ path: r.path, caption: r.caption }))); + const firstLevelRows = pivotResult.flatRows.filter((row) => row.level === 0 && row.hasChildren); // 첫 레벨 행이 있으면 자동 확장 if (firstLevelRows.length > 0) { - const firstLevelPaths = firstLevelRows.map(row => row.path); - console.log("🔶 초기 자동 확장 실행 (한 번만):", firstLevelPaths); - setPivotState(prev => ({ + const firstLevelPaths = firstLevelRows.map((row) => row.path); + setPivotState((prev) => ({ ...prev, expandedRowPaths: firstLevelPaths, })); @@ -725,19 +727,16 @@ export const PivotGridComponent: React.FC = ({ // 필드 변경 const handleFieldsChange = useCallback( (newFields: PivotFieldConfig[]) => { - // 🆕 visible: false 필드 제거 (FieldChooser에서 "사용 안함"으로 설정한 필드) - const visibleFields = newFields.filter(f => f.visible !== false); - + // FieldChooser에서 이미 필드를 완전히 제거하므로 추가 필터링 불필요 console.log("🔷 [handleFieldsChange] 필드 변경:", { totalFields: newFields.length, - visibleFields: visibleFields.length, - removedFields: newFields.length - visibleFields.length, - filterFields: visibleFields.filter(f => f.area === "filter").length, - filterFieldNames: visibleFields.filter(f => f.area === "filter").map(f => f.field), + filterFields: newFields.filter(f => f.area === "filter").length, + filterFieldNames: newFields.filter(f => f.area === "filter").map(f => f.field), + rowFields: newFields.filter(f => f.area === "row").length, + columnFields: newFields.filter(f => f.area === "column").length, + dataFields: newFields.filter(f => f.area === "data").length, }); - console.log("🔷 [handleFieldsChange] setFields 호출 전"); - setFields(visibleFields); - console.log("🔷 [handleFieldsChange] setFields 호출 후"); + setFields(newFields); }, [] ); @@ -945,6 +944,8 @@ export const PivotGridComponent: React.FC = ({ // 인쇄 기능 (PDF 내보내기보다 먼저 정의해야 함) const handlePrint = useCallback(() => { + if (typeof window === "undefined") return; + const printContent = tableRef.current; if (!printContent) return; @@ -1047,8 +1048,10 @@ export const PivotGridComponent: React.FC = ({ // 상태 초기화 (확장/축소, 정렬, 필터만 초기화, 필드 설정은 유지) const handleResetState = useCallback(() => { - // 로컬 스토리지에서 상태 제거 - localStorage.removeItem(stateStorageKey); + // 로컬 스토리지에서 상태 제거 (SSR 보호) + if (typeof window !== "undefined") { + localStorage.removeItem(stateStorageKey); + } // 확장/축소, 정렬, 필터 상태만 초기화 setPivotState({ @@ -1061,9 +1064,6 @@ export const PivotGridComponent: React.FC = ({ setColumnWidths({}); setSelectedCell(null); setSelectionRange(null); - - // 🆕 필드 설정은 유지 (initialFields로 되돌리지 않음) - console.log("🔷 피벗 상태가 초기화되었습니다 (필드 설정은 유지)"); }, [stateStorageKey]); // 필드 숨기기/표시 상태 @@ -1081,11 +1081,6 @@ export const PivotGridComponent: React.FC = ({ }); }, []); - // 숨겨진 필드 제외한 활성 필드들 - const visibleFields = useMemo(() => { - return fields.filter((f) => !hiddenFields.has(f.field)); - }, [fields, hiddenFields]); - // 숨겨진 필드 목록 const hiddenFieldsList = useMemo(() => { return fields.filter((f) => hiddenFields.has(f.field)); -- 2.43.0