"use client"; import type { CSSProperties } from "react"; import { useEffect } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useAppLocale } from "@/features/i18n/LocaleProvider"; import { getPreviewMessages } from "@/features/i18n/messages/preview"; import { useEditorStore } from "@/features/editor/state/editorStore"; import { PublicPageRenderer } from "@/features/editor/components/PublicPageRenderer"; export default function PreviewPage() { const router = useRouter(); const locale = useAppLocale(); const m = getPreviewMessages(locale); const blocks = useEditorStore((state) => state.blocks); const projectConfig = useEditorStore((state) => (state as any).projectConfig); const replaceBlocks = useEditorStore((state) => state.replaceBlocks); const updateProjectConfig = useEditorStore((state) => state.updateProjectConfig); const resetHistory = useEditorStore((state) => (state as any).resetHistory as () => void); useEffect(() => { let cancelled = false; const checkAuth = async () => { try { const res = await fetch("/api/auth/me"); if (!res.ok && res.status === 401 && !cancelled) { router.push("/login"); } } catch { // 네트워크 오류 등은 일단 무시하고, 페이지 접근을 막지 않는다. } }; void checkAuth(); return () => { cancelled = true; }; }, [router]); useEffect(() => { if (typeof window === "undefined") return; const configSlugRaw = (projectConfig as any)?.slug?.trim?.(); const configSlug = typeof configSlugRaw === "string" && configSlugRaw.length > 0 ? configSlugRaw : ""; let querySlug = ""; try { const url = new URL(window.location.href); const fromQuery = url.searchParams.get("slug")?.trim(); if (fromQuery) { querySlug = fromQuery; } } catch { // URL 파싱 오류는 무시하고, autosave 복원 없이 진행한다. } const effectiveSlug = querySlug || configSlug; if (!effectiveSlug) return; const key = `pb:autosave:${effectiveSlug}`; const raw = window.localStorage.getItem(key); if (!raw) { // autosave 스냅샷이 없을 때만 URL 쿼리 슬러그를 projectConfig.slug 에 동기화한다. if (querySlug && querySlug !== configSlug) { updateProjectConfig({ slug: querySlug } as any); } return; } try { const parsed = JSON.parse(raw) as { blocks?: any[]; projectConfig?: any }; if (Array.isArray(parsed.blocks)) { replaceBlocks(parsed.blocks as any); } if (parsed.projectConfig) { updateProjectConfig(parsed.projectConfig as any); } else if (querySlug && querySlug !== configSlug) { // 스냅샷에 projectConfig 가 없을 때만 쿼리 슬러그를 반영한다. updateProjectConfig({ slug: querySlug } as any); } // 프리뷰 진입 시 autosave 프로젝트를 복원하는 경우에도 에디터 히스토리는 새 프로젝트 기준으로만 유지되도록 초기화한다. resetHistory(); } catch { return; } }, [projectConfig?.slug, replaceBlocks, updateProjectConfig]); const canvasStyle: CSSProperties = {}; const preset = projectConfig?.canvasPreset ?? "full"; const mainStyle: CSSProperties = {}; { const raw = typeof projectConfig?.bodyBgColorHex === "string" ? projectConfig.bodyBgColorHex.trim() : ""; if (raw) { mainStyle.backgroundColor = raw; } } const handleExportZip = async () => { try { const payload = { blocks, projectConfig, }; const response = await fetch("/api/export", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(payload), }); if (!response.ok) { return; } const blob = await response.blob(); const url = URL.createObjectURL(blob); const slug = (projectConfig?.slug ?? "").trim() || "page-builder-export"; const link = document.createElement("a"); link.href = url; link.download = `${slug}.zip`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } catch (error) { console.error("프리뷰 ZIP 내보내기 중 오류", error); } }; const widthPx = typeof projectConfig?.canvasWidthPx === "number" && projectConfig.canvasWidthPx > 0 ? projectConfig.canvasWidthPx : null; const projectSlugRaw = (projectConfig as any)?.slug?.trim?.(); const projectSlug = typeof projectSlugRaw === "string" && projectSlugRaw.length > 0 ? projectSlugRaw : ""; const editorHref = projectSlug ? `/editor?slug=${encodeURIComponent(projectSlug)}` : "/editor"; if (widthPx != null) { canvasStyle.maxWidth = `${widthPx}px`; } else if (preset === "mobile") { canvasStyle.maxWidth = "390px"; } else if (preset === "tablet") { canvasStyle.maxWidth = "768px"; } else if (preset === "desktop") { canvasStyle.maxWidth = "1200px"; } if (projectConfig?.canvasBgColorHex && projectConfig.canvasBgColorHex.trim()) { canvasStyle.backgroundColor = projectConfig.canvasBgColorHex; } return (

{m.headerTitle}

{m.headerDescription}

{m.navProjects} {m.navBackToEditor}
{/* 에디터 크롬 없이 순수 페이지 형태로 블록들을 렌더링하되, projectConfig 에 따라 최대 폭을 제한한다. */}
); }