diff --git a/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardComponent.tsx b/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardComponent.tsx index 53940b0a..7c6e7c50 100644 --- a/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardComponent.tsx +++ b/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardComponent.tsx @@ -111,19 +111,10 @@ export function PopDashboardComponent({ const containerRef = useRef(null); const [containerWidth, setContainerWidth] = useState(300); - // 빈 설정 - if (!config || !config.items.length) { - return ( -
- - 대시보드 아이템을 추가하세요 - -
- ); - } - - // 보이는 아이템만 필터링 - const visibleItems = config.items.filter((item) => item.visible); + // 보이는 아이템만 필터링 (hooks 이전에 early return 불가하므로 빈 배열 허용) + const visibleItems = Array.isArray(config?.items) + ? config.items.filter((item) => item.visible) + : []; // 컨테이너 크기 감지 useEffect(() => { @@ -140,6 +131,7 @@ export function PopDashboardComponent({ }, []); // 데이터 로딩 함수 + // eslint-disable-next-line react-hooks/exhaustive-deps const fetchAllData = useCallback(async () => { if (!visibleItems.length) { setLoading(false); @@ -165,7 +157,6 @@ export function PopDashboardComponent({ setDataMap(newDataMap); setLoading(false); - // eslint-disable-next-line react-hooks/exhaustive-deps }, [JSON.stringify(visibleItems.map((i) => i.id))]); // 초기 로딩 + 주기적 새로고침 @@ -186,6 +177,17 @@ export function PopDashboardComponent({ }; }, [fetchAllData, visibleItems]); + // 빈 설정 (모든 hooks 이후에 early return) + if (!config || !config.items?.length) { + return ( +
+ + 대시보드 아이템을 추가하세요 + +
+ ); + } + // 단일 아이템 렌더링 const renderSingleItem = (item: DashboardItem) => { const itemData = dataMap[item.id]; diff --git a/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardConfig.tsx b/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardConfig.tsx index 74126c22..26da10f5 100644 --- a/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardConfig.tsx +++ b/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardConfig.tsx @@ -45,7 +45,7 @@ import { validateExpression } from "./utils/formula"; interface ConfigPanelProps { config: PopDashboardConfig | undefined; - onChange: (config: PopDashboardConfig) => void; + onUpdate: (config: PopDashboardConfig) => void; } // ===== 기본값 ===== @@ -806,9 +806,10 @@ function GridLayoutEditor({ export function PopDashboardConfigPanel({ config, - onChange, + onUpdate: onChange, }: ConfigPanelProps) { - const cfg = config ?? DEFAULT_CONFIG; + // config가 빈 객체 {}로 전달될 수 있으므로 spread로 기본값 보장 + const cfg: PopDashboardConfig = { ...DEFAULT_CONFIG, ...(config || {}) }; const [activeTab, setActiveTab] = useState<"basic" | "items" | "layout">( "basic" ); diff --git a/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardPreview.tsx b/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardPreview.tsx index db64f04c..8d530b96 100644 --- a/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardPreview.tsx +++ b/frontend/lib/registry/pop-components/pop-dashboard/PopDashboardPreview.tsx @@ -64,7 +64,8 @@ export function PopDashboardPreviewComponent({ }: { config?: PopDashboardConfig; }) { - if (!config || !config.items.length) { + // config가 빈 객체 {} 또는 items가 없는 경우 방어 + if (!config || !Array.isArray(config.items) || !config.items.length) { return (