"use client"; import React, { useState, useEffect } from "react"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Button } from "@/components/ui/button"; import { X } from "lucide-react"; import type { TabsComponent, TabItem, TabInlineComponent } from "@/types/screen-management"; import { cn } from "@/lib/utils"; import { useActiveTab } from "@/contexts/ActiveTabContext"; import { DynamicComponentRenderer } from "@/lib/registry/DynamicComponentRenderer"; interface TabsWidgetProps { component: TabsComponent; className?: string; style?: React.CSSProperties; menuObjid?: number; formData?: Record; onFormDataChange?: (data: Record) => void; isDesignMode?: boolean; // 디자인 모드 여부 onComponentSelect?: (tabId: string, componentId: string) => void; // 컴포넌트 선택 콜백 selectedComponentId?: string; // 선택된 컴포넌트 ID } export function TabsWidget({ component, className, style, menuObjid, formData = {}, onFormDataChange, isDesignMode = false, onComponentSelect, selectedComponentId, }: TabsWidgetProps) { const { setActiveTab, removeTabsComponent } = useActiveTab(); 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 [mountedTabs, setMountedTabs] = useState>(() => new Set([getInitialTab()])); // 컴포넌트 탭 목록 변경 시 동기화 useEffect(() => { setVisibleTabs(tabs.filter((tab) => !tab.disabled)); }, [tabs]); // 선택된 탭 변경 시 localStorage에 저장 + ActiveTab Context 업데이트 useEffect(() => { if (persistSelection && typeof window !== "undefined") { localStorage.setItem(storageKey, selectedTab); } const currentTabInfo = visibleTabs.find((t) => t.id === selectedTab); if (currentTabInfo) { setActiveTab(component.id, { tabId: selectedTab, tabsComponentId: component.id, label: currentTabInfo.label, }); } }, [selectedTab, persistSelection, storageKey, component.id, visibleTabs, setActiveTab]); // 컴포넌트 언마운트 시 ActiveTab Context에서 제거 useEffect(() => { return () => { removeTabsComponent(component.id); }; }, [component.id, removeTabsComponent]); // 탭 변경 핸들러 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 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}`; }; // 인라인 컴포넌트 렌더링 const renderTabComponents = (tab: TabItem) => { const components = tab.components || []; if (components.length === 0) { return (

{isDesignMode ? "컴포넌트를 드래그하여 추가하세요" : "컴포넌트가 없습니다"}

); } return (
{components.map((comp: TabInlineComponent) => { const isSelected = selectedComponentId === comp.id; return (
{ if (isDesignMode && onComponentSelect) { e.stopPropagation(); onComponentSelect(tab.id, comp.id); } }} >
); })}
); }; if (visibleTabs.length === 0) { return (

탭이 없습니다

); } return (
{visibleTabs.map((tab) => (
{tab.label} {tab.components && tab.components.length > 0 && ( ({tab.components.length}) )} {allowCloseable && ( )}
))}
{visibleTabs.map((tab) => { const shouldRender = mountedTabs.has(tab.id); const isActive = selectedTab === tab.id; return ( {shouldRender && renderTabComponents(tab)} ); })}
); }