"use client"; import React, { useState, useEffect, useMemo } from "react"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Button } from "@/components/ui/button"; import { X, Loader2 } from "lucide-react"; import type { TabsComponent, TabItem } from "@/types/screen-management"; import { InteractiveScreenViewerDynamic } from "@/components/screen/InteractiveScreenViewerDynamic"; import { cn } from "@/lib/utils"; interface TabsWidgetProps { component: TabsComponent; className?: string; style?: React.CSSProperties; menuObjid?: number; // πŸ†• λΆ€λͺ¨ ν™”λ©΄μ˜ 메뉴 OBJID } export function TabsWidget({ component, className, style, menuObjid }: TabsWidgetProps) { const { tabs = [], defaultTab, orientation = "horizontal", variant = "default", allowCloseable = false, persistSelection = false, } = component; const storageKey = `tabs-${component.id}-selected`; // 초기 선택 νƒ­ κ²°μ • const getInitialTab = () => { if (persistSelection && typeof window !== "undefined") { const saved = localStorage.getItem(storageKey); if (saved && tabs.some((t) => t.id === saved)) { return saved; } } return defaultTab || tabs[0]?.id || ""; }; const [selectedTab, setSelectedTab] = useState(getInitialTab()); const [visibleTabs, setVisibleTabs] = useState(tabs); const [loadingScreens, setLoadingScreens] = useState>({}); const [screenLayouts, setScreenLayouts] = useState>({}); // πŸ†• ν•œ λ²ˆμ΄λΌλ„ μ„ νƒλœ νƒ­ 좔적 (μ§€μ—° λ‘œλ”© + 캐싱) const [mountedTabs, setMountedTabs] = useState>(() => new Set([getInitialTab()])); // μ»΄ν¬λ„ŒνŠΈ νƒ­ λͺ©λ‘ λ³€κ²½ μ‹œ 동기화 useEffect(() => { setVisibleTabs(tabs.filter((tab) => !tab.disabled)); }, [tabs]); // μ„ νƒλœ νƒ­ λ³€κ²½ μ‹œ localStorage에 μ €μž₯ useEffect(() => { if (persistSelection && typeof window !== "undefined") { localStorage.setItem(storageKey, selectedTab); } }, [selectedTab, persistSelection, storageKey]); // 초기 λ‘œλ“œ μ‹œ μ„ νƒλœ νƒ­μ˜ ν™”λ©΄ 뢈러였기 useEffect(() => { const currentTab = visibleTabs.find((t) => t.id === selectedTab); if (currentTab && currentTab.screenId && !screenLayouts[currentTab.screenId]) { loadScreenLayout(currentTab.screenId); } }, [selectedTab, visibleTabs]); // ν™”λ©΄ λ ˆμ΄μ•„μ›ƒ λ‘œλ“œ const loadScreenLayout = async (screenId: number) => { if (screenLayouts[screenId]) { return; // 이미 λ‘œλ“œλ¨ } setLoadingScreens((prev) => ({ ...prev, [screenId]: true })); try { const { apiClient } = await import("@/lib/api/client"); const response = await apiClient.get(`/screen-management/screens/${screenId}/layout`); if (response.data.success && response.data.data) { setScreenLayouts((prev) => ({ ...prev, [screenId]: response.data.data })); } } catch (error) { console.error(`ν™”λ©΄ λ ˆμ΄μ•„μ›ƒ λ‘œλ“œ μ‹€νŒ¨ ${screenId}:`, error); } finally { setLoadingScreens((prev) => ({ ...prev, [screenId]: false })); } }; // νƒ­ λ³€κ²½ ν•Έλ“€λŸ¬ const handleTabChange = (tabId: string) => { setSelectedTab(tabId); // 마운트된 νƒ­ λͺ©λ‘μ— μΆ”κ°€ (ν•œ 번 마운트되면 μœ μ§€) setMountedTabs(prev => { if (prev.has(tabId)) return prev; const newSet = new Set(prev); newSet.add(tabId); return newSet; }); // ν•΄λ‹Ή νƒ­μ˜ ν™”λ©΄ λ‘œλ“œ const tab = visibleTabs.find((t) => t.id === tabId); if (tab && tab.screenId && !screenLayouts[tab.screenId]) { loadScreenLayout(tab.screenId); } }; // νƒ­ λ‹«κΈ° ν•Έλ“€λŸ¬ const handleCloseTab = (tabId: string, e: React.MouseEvent) => { e.stopPropagation(); const updatedTabs = visibleTabs.filter((tab) => tab.id !== tabId); setVisibleTabs(updatedTabs); // 닫은 탭이 μ„ νƒλœ νƒ­μ΄μ—ˆλ‹€λ©΄ λ‹€μŒ νƒ­ 선택 if (selectedTab === tabId && updatedTabs.length > 0) { setSelectedTab(updatedTabs[0].id); } }; // νƒ­ μŠ€νƒ€μΌ 클래슀 const getTabsListClass = () => { const baseClass = orientation === "vertical" ? "flex-col" : ""; const variantClass = variant === "pills" ? "bg-muted p-1 rounded-lg" : variant === "underline" ? "border-b" : "bg-muted p-1"; return `${baseClass} ${variantClass}`; }; if (visibleTabs.length === 0) { return (

탭이 μ—†μŠ΅λ‹ˆλ‹€

); } return (
{visibleTabs.map((tab) => (
{tab.label} {allowCloseable && ( )}
))}
{/* πŸ†• forceMount + CSS μˆ¨κΉ€μœΌλ‘œ νƒ­ μ „ν™˜ μ‹œ λ¦¬λ Œλ”λ§ λ°©μ§€ */}
{visibleTabs.map((tab) => { // ν•œ λ²ˆλ„ μ„ νƒλ˜μ§€ μ•Šμ€ 탭은 λ Œλ”λ§ν•˜μ§€ μ•ŠμŒ (μ§€μ—° λ‘œλ”©) const shouldRender = mountedTabs.has(tab.id); const isActive = selectedTab === tab.id; return ( {/* ν•œ 번 마운트된 νƒ­λ§Œ λ‚΄μš© λ Œλ”λ§ */} {shouldRender && ( <> {tab.screenId ? ( loadingScreens[tab.screenId] ? (
ν™”λ©΄ λ‘œλ”© 쀑...
) : screenLayouts[tab.screenId] ? ( (() => { const layoutData = screenLayouts[tab.screenId]; const { components = [], screenResolution } = layoutData; const designWidth = screenResolution?.width || 1920; const designHeight = screenResolution?.height || 1080; return (
{components.map((component: any) => ( ))}
); })() ) : (

화면을 뢈러올 수 μ—†μŠ΅λ‹ˆλ‹€

) ) : (

μ—°κ²°λœ 화면이 μ—†μŠ΅λ‹ˆλ‹€

)} )}
); })}
); }