"use client"; /** * SettingsModalShell.tsx — 컴포넌트 설정 모달 공통 Shell * * [역할] * 모든 컴포넌트 설정 모달이 동일한 형식을 유지하도록 하는 재사용 모듈. * 파란색 그라데이션 헤더 + 탭(헤더 하단 인라인) + 스크롤 콘텐츠 + 하단 Footer 구조. */ import React, { useState, useCallback, useEffect, useRef } from "react"; import { Dialog, DialogContent, DialogTitle, DialogDescription } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { X, Save, AlertTriangle, CheckCircle } from "lucide-react"; const DND_ROOT_ID = "report-designer-dnd-root"; export interface ModalTabDef { key: string; icon: React.ReactNode; label: string; } export interface ModalAlert { type: "success" | "warning"; message: string; } interface SettingsModalShellProps { open: boolean; onOpenChange: (open: boolean) => void; title: string; icon?: React.ReactNode; tabs: ModalTabDef[]; activeTab: string; onTabChange: (key: string) => void; onSave: () => void; onClose: () => void; alert?: ModalAlert | null; children: React.ReactNode; maxWidth?: string; saveLabel?: string; } export function SettingsModalShell({ open, onOpenChange, title, icon, tabs, activeTab, onTabChange, onSave, onClose, alert, children, maxWidth = "max-w-4xl", saveLabel = "저장", }: SettingsModalShellProps) { const [dndContainer, setDndContainer] = useState(undefined); useEffect(() => { if (open) { const el = document.getElementById(DND_ROOT_ID); setDndContainer(el ?? undefined); } }, [open]); return ( button]:hidden`} > {title} {title} 설정 모달 {/* Gradient Header */}
{/* Title row */}
{icon && {icon}}

{title}

{/* Tabs row */} {tabs.length > 0 && (
{tabs.map((tab) => ( ))}
)}
{/* 토스트 알림 */} {alert && (
{alert.type === "success" ? (
) : (
)}
{alert.type === "success" ? "성공" : "알림"} {alert.message}
)} {/* Content Area */}
{children}
{/* Footer */}
); } // ─── 토스트 알림 훅 ────────────────────────────────────────────────────────── export function useModalAlert() { const [alert, setAlert] = useState(null); const timerRef = useRef | null>(null); useEffect(() => { return () => { if (timerRef.current) clearTimeout(timerRef.current); }; }, []); const showAlert = useCallback((type: ModalAlert["type"], message: string) => { if (timerRef.current) clearTimeout(timerRef.current); setAlert({ type, message }); timerRef.current = setTimeout(() => setAlert(null), 3000); }, []); const clearAlert = useCallback(() => setAlert(null), []); return { alert, showAlert, clearAlert }; }