145 lines
6.1 KiB
TypeScript
145 lines
6.1 KiB
TypeScript
"use client";
|
|
|
|
import React, { useState } from "react";
|
|
import { X, Eye, Mail, Code, Maximize2, Minimize2 } from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { MailTemplate, renderTemplateToHtml, extractTemplateVariables } from "@/lib/api/mail";
|
|
|
|
interface MailTemplatePreviewModalProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
template: MailTemplate | null;
|
|
}
|
|
|
|
export default function MailTemplatePreviewModal({ isOpen, onClose, template }: MailTemplatePreviewModalProps) {
|
|
const [viewMode, setViewMode] = useState<"preview" | "code">("preview");
|
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
const [variables, setVariables] = useState<Record<string, string>>({});
|
|
|
|
if (!isOpen || !template) return null;
|
|
|
|
const templateVariables = extractTemplateVariables(template);
|
|
const renderedHtml = renderTemplateToHtml(template, variables);
|
|
|
|
const handleVariableChange = (key: string, value: string) => {
|
|
setVariables((prev) => ({ ...prev, [key]: value }));
|
|
};
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
|
|
<div
|
|
className={`bg-card overflow-hidden rounded-xl border shadow-2xl transition-all ${
|
|
isFullscreen ? "h-full w-full" : "max-h-[90vh] w-full max-w-6xl"
|
|
}`}
|
|
>
|
|
{/* 헤더 */}
|
|
<div className="bg-muted sticky top-0 z-10 flex items-center justify-between border-b px-6 py-4">
|
|
<div className="flex items-center gap-3">
|
|
<Eye className="text-foreground h-6 w-6" />
|
|
<div>
|
|
<h2 className="text-foreground text-xl font-bold">{template.name}</h2>
|
|
<p className="text-muted-foreground text-sm">{template.subject}</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<button
|
|
onClick={() => setViewMode(viewMode === "preview" ? "code" : "preview")}
|
|
className="text-foreground hover:bg-background flex items-center gap-2 rounded-lg px-3 py-2 transition"
|
|
>
|
|
{viewMode === "preview" ? (
|
|
<>
|
|
<Code className="h-4 w-4" />
|
|
코드
|
|
</>
|
|
) : (
|
|
<>
|
|
<Eye className="h-4 w-4" />
|
|
미리보기
|
|
</>
|
|
)}
|
|
</button>
|
|
<button
|
|
onClick={() => setIsFullscreen(!isFullscreen)}
|
|
className="text-foreground hover:bg-background rounded-lg p-2 transition"
|
|
>
|
|
{isFullscreen ? <Minimize2 className="h-5 w-5" /> : <Maximize2 className="h-5 w-5" />}
|
|
</button>
|
|
<button onClick={onClose} className="text-foreground hover:bg-background rounded-lg p-2 transition">
|
|
<X className="h-5 w-5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 본문 */}
|
|
<div className="flex h-full overflow-hidden">
|
|
{/* 왼쪽: 변수 입력 (변수가 있을 때만) */}
|
|
{templateVariables.length > 0 && (
|
|
<div className="bg-muted/30 w-80 overflow-y-auto border-r p-6">
|
|
<h3 className="text-foreground mb-4 flex items-center gap-2 text-lg font-semibold">
|
|
<Mail className="text-foreground h-5 w-5" />
|
|
템플릿 변수
|
|
</h3>
|
|
<div className="space-y-4">
|
|
{templateVariables.map((variable) => (
|
|
<div key={variable}>
|
|
<label className="text-foreground mb-1 block text-sm font-medium">{variable}</label>
|
|
<input
|
|
type="text"
|
|
value={variables[variable] || ""}
|
|
onChange={(e) => handleVariableChange(variable, e.target.value)}
|
|
placeholder={`{${variable}}`}
|
|
className="focus:ring-primary focus:border-primary bg-background w-full rounded-lg border px-3 py-2 focus:ring-2"
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className="bg-muted mt-6 rounded-lg border p-4">
|
|
<p className="text-muted-foreground text-xs">💡 변수 값을 입력하면 미리보기에 반영됩니다.</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 오른쪽: 미리보기 또는 코드 */}
|
|
<div className="flex-1 overflow-y-auto p-6">
|
|
{viewMode === "preview" ? (
|
|
<div className="bg-card overflow-hidden rounded-lg border">
|
|
{/* 이메일 헤더 시뮬레이션 */}
|
|
<div className="bg-muted border-b px-6 py-4">
|
|
<div className="space-y-2 text-sm">
|
|
<div className="flex">
|
|
<span className="text-muted-foreground w-20 font-semibold">제목:</span>
|
|
<span className="text-foreground">{template.subject}</span>
|
|
</div>
|
|
<div className="flex">
|
|
<span className="text-muted-foreground w-20 font-semibold">발신:</span>
|
|
<span className="text-foreground">your-email@company.com</span>
|
|
</div>
|
|
<div className="flex">
|
|
<span className="text-muted-foreground w-20 font-semibold">수신:</span>
|
|
<span className="text-foreground">recipient@example.com</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 이메일 본문 */}
|
|
<div className="p-6" dangerouslySetInnerHTML={{ __html: renderedHtml }} />
|
|
</div>
|
|
) : (
|
|
<div className="bg-muted/50 overflow-x-auto rounded-lg border p-6 font-mono text-sm">
|
|
<pre className="text-foreground break-words whitespace-pre-wrap">{renderedHtml}</pre>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 푸터 */}
|
|
<div className="bg-muted/30 sticky bottom-0 flex justify-end gap-3 border-t px-6 py-4">
|
|
<Button variant="outline" onClick={onClose}>
|
|
닫기
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|