"use client"; import { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Checkbox } from "@/components/ui/checkbox"; import { Loader2, Link2, Monitor, Folder, ChevronRight } from "lucide-react"; import { screenApi } from "@/lib/api/screen"; import { GroupCopyInfo } from "./PopCategoryTree"; import { getCompanyList } from "@/lib/api/company"; import { ScreenDefinition } from "@/types/screen"; import { Company } from "@/types/company"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { toast } from "sonner"; interface LinkedScreenInfo { screenId: number; screenName: string; screenCode: string; references: Array<{ componentId: string; referenceType: string; }>; deploy: boolean; newScreenName: string; newScreenCode: string; } interface ScreenEntry { screenId: number; screenName: string; newScreenName: string; newScreenCode: string; included: boolean; } interface PopDeployModalProps { open: boolean; onOpenChange: (open: boolean) => void; screen: ScreenDefinition | null; groupScreens?: ScreenDefinition[]; groupName?: string; groupInfo?: GroupCopyInfo; allScreens: ScreenDefinition[]; onDeployed?: () => void; } export function PopDeployModal({ open, onOpenChange, screen, groupScreens, groupName, groupInfo, allScreens, onDeployed, }: PopDeployModalProps) { const isGroupMode = !!(groupScreens && groupScreens.length > 0); const [companies, setCompanies] = useState([]); const [targetCompanyCode, setTargetCompanyCode] = useState(""); // 단일 화면 모드 const [screenName, setScreenName] = useState(""); const [screenCode, setScreenCode] = useState(""); const [linkedScreens, setLinkedScreens] = useState([]); // 그룹 모드 const [groupEntries, setGroupEntries] = useState([]); const [analyzing, setAnalyzing] = useState(false); const [deploying, setDeploying] = useState(false); // 회사 목록 로드 useEffect(() => { if (open) { getCompanyList({ status: "active" }) .then((list) => { setCompanies(list.filter((c) => c.company_code !== "*")); }) .catch(console.error); } }, [open]); // 모달 열릴 때 초기화 useEffect(() => { if (!open) return; setTargetCompanyCode(""); setLinkedScreens([]); if (isGroupMode && groupScreens) { setGroupEntries( groupScreens.map((s) => ({ screenId: s.screenId, screenName: s.screenName, newScreenName: s.screenName, newScreenCode: "", included: true, })), ); setScreenName(""); setScreenCode(""); } else if (screen) { setScreenName(screen.screenName); setScreenCode(""); setGroupEntries([]); analyzeLinks(screen.screenId); } }, [open, screen, groupScreens, isGroupMode]); // 회사 선택 시 화면 코드 자동 생성 useEffect(() => { if (!targetCompanyCode) return; if (isGroupMode) { const count = groupEntries.filter((e) => e.included).length; if (count > 0) { screenApi .generateMultipleScreenCodes(targetCompanyCode, count) .then((codes) => { let codeIdx = 0; setGroupEntries((prev) => prev.map((e) => e.included ? { ...e, newScreenCode: codes[codeIdx++] || "" } : e, ), ); }) .catch(console.error); } } else { const count = 1 + linkedScreens.filter((ls) => ls.deploy).length; screenApi .generateMultipleScreenCodes(targetCompanyCode, count) .then((codes) => { setScreenCode(codes[0] || ""); setLinkedScreens((prev) => prev.map((ls, idx) => ({ ...ls, newScreenCode: codes[idx + 1] || "", })), ); }) .catch(console.error); } }, [targetCompanyCode]); const analyzeLinks = async (screenId: number) => { setAnalyzing(true); try { const result = await screenApi.analyzePopScreenLinks(screenId); const linked: LinkedScreenInfo[] = result.linkedScreenIds.map( (linkedId) => { const linkedScreen = allScreens.find( (s) => s.screenId === linkedId, ); const refs = result.references.filter( (r) => r.targetScreenId === linkedId, ); return { screenId: linkedId, screenName: linkedScreen?.screenName || `화면 ${linkedId}`, screenCode: linkedScreen?.screenCode || "", references: refs.map((r) => ({ componentId: r.componentId, referenceType: r.referenceType, })), deploy: true, newScreenName: linkedScreen?.screenName || `화면 ${linkedId}`, newScreenCode: "", }; }, ); setLinkedScreens(linked); } catch (error) { console.error("연결 분석 실패:", error); } finally { setAnalyzing(false); } }; const handleDeploy = async () => { if (!targetCompanyCode) return; setDeploying(true); try { let screensToSend: Array<{ sourceScreenId: number; screenName: string; screenCode: string; }>; if (isGroupMode) { screensToSend = groupEntries .filter((e) => e.included && e.newScreenCode) .map((e) => ({ sourceScreenId: e.screenId, screenName: e.newScreenName, screenCode: e.newScreenCode, })); } else { if (!screen || !screenName || !screenCode) return; screensToSend = [ { sourceScreenId: screen.screenId, screenName, screenCode, }, ...linkedScreens .filter((ls) => ls.deploy) .map((ls) => ({ sourceScreenId: ls.screenId, screenName: ls.newScreenName, screenCode: ls.newScreenCode, })), ]; } if (screensToSend.length === 0) { toast.error("복사할 화면이 없습니다."); return; } const deployPayload: Parameters[0] = { screens: screensToSend, targetCompanyCode, }; if (isGroupMode && groupInfo) { deployPayload.groupStructure = groupInfo; } const result = await screenApi.deployPopScreens(deployPayload); const groupMsg = result.createdGroups ? ` (카테고리 ${result.createdGroups}개 생성)` : ""; toast.success( `POP 화면 ${result.deployedScreens.length}개가 복사되었습니다.${groupMsg}`, ); onOpenChange(false); onDeployed?.(); } catch (error: any) { toast.error(error?.response?.data?.message || "복사에 실패했습니다."); } finally { setDeploying(false); } }; const totalCount = isGroupMode ? groupEntries.filter((e) => e.included).length : 1 + linkedScreens.filter((ls) => ls.deploy).length; const canDeploy = isGroupMode ? !deploying && targetCompanyCode && groupEntries.some((e) => e.included) : !deploying && targetCompanyCode && screenName && screenCode; return ( POP 화면 복사 {isGroupMode ? `"${groupName}" 카테고리의 화면 ${groupScreens!.length}개를 다른 회사로 복사합니다.` : screen ? `"${screen.screenName}" (ID: ${screen.screenId}) 화면을 다른 회사로 복사합니다.` : "화면을 선택해주세요."}
{/* 대상 회사 선택 */}
{/* ===== 그룹 모드: 카테고리 구조 + 화면 목록 ===== */} {isGroupMode ? (
{groupInfo ? (
{/* 메인 카테고리 */}
{groupInfo.groupName} 새 카테고리 생성
{/* 메인 카테고리의 직접 화면 */} {groupEntries .filter((e) => groupInfo.screenIds.includes(e.screenId)) .map((entry) => (
{ setGroupEntries((prev) => prev.map((e) => e.screenId === entry.screenId ? { ...e, included: !!checked } : e, ), ); }} /> {entry.screenName} #{entry.screenId}
))} {/* 하위 카테고리들 */} {groupInfo.children?.map((child) => (
{child.groupName}
{groupEntries .filter((e) => child.screenIds.includes(e.screenId), ) .map((entry) => (
{ setGroupEntries((prev) => prev.map((e) => e.screenId === entry.screenId ? { ...e, included: !!checked } : e, ), ); }} /> {entry.screenName} #{entry.screenId}
))}
))}
) : (
{groupEntries.map((entry) => (
{ setGroupEntries((prev) => prev.map((e) => e.screenId === entry.screenId ? { ...e, included: !!checked } : e, ), ); }} /> {entry.screenName} #{entry.screenId}
))}
)}

카테고리 구조와 화면 간 연결(cartScreenId 등)이 자동으로 복사됩니다.

) : ( <> {/* ===== 단일 모드: 화면명 + 코드 ===== */}
setScreenName(e.target.value)} placeholder="화면 이름" />
{/* 연결 화면 감지 */} {analyzing ? (
연결된 화면을 분석 중입니다...
) : linkedScreens.length > 0 ? (
연결된 POP 화면 {linkedScreens.length}개 감지됨
{linkedScreens.map((ls) => (
{ls.screenName}
ID: {ls.screenId} |{" "} {ls.references .map((r) => r.referenceType) .join(", ")}
{ setLinkedScreens((prev) => prev.map((item) => item.screenId === ls.screenId ? { ...item, deploy: !!checked } : item, ), ); }} /> 함께 복사
))}

함께 복사하면 화면 간 연결(cartScreenId 등)이 새 ID로 자동 치환됩니다.

) : ( !analyzing && (
연결된 POP 화면이 없습니다. 이 화면만 복사됩니다.
) )} )}
); }