Polish email template system with UX improvements

- Consolidated multiple preview canvases into single shared preview with "Simpan & Preview" button
- Fixed double scrollbar issue in preview box by using fixed height container and scrolling=no
- Added modular email components to Tiptap editor:
  * EmailButton with URL, text, and full-width options
  * OTPBox with monospace font and dashed border styling
  * EmailTable with brutalist styling and proper header support
- Generated contextual initial email content for all template types:
  * Payment success with professional details table
  * Access granted with celebration styling and prominent CTA
  * Order created with clear next steps and status information
  * Payment reminder with urgent styling and warning alerts
  * Consulting scheduled with session details and preparation tips
  * Event reminder with high-energy countdown and call-to-action
  * Bootcamp progress with motivational progress tracking
- Enhanced RichTextEditor toolbar with email component buttons and visual separators
- Improved NotifikasiTab with streamlined preview workflow

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
dwindown
2025-12-22 20:35:50 +07:00
parent efc085e231
commit 37680bd25b
3 changed files with 697 additions and 41 deletions

View File

@@ -32,47 +32,312 @@ const SHORTCODES_HELP = {
};
const DEFAULT_TEMPLATES: { key: string; name: string; defaultSubject: string; defaultBody: string }[] = [
{
key: 'payment_success',
{
key: 'payment_success',
name: 'Pembayaran Berhasil',
defaultSubject: 'Pembayaran Berhasil - Order #{order_id}',
defaultBody: '<h2>Halo {nama}!</h2><p>Terima kasih, pembayaran Anda sebesar <strong>{total}</strong> telah berhasil dikonfirmasi.</p><p><strong>Detail Pesanan:</strong></p><ul><li>Order ID: {order_id}</li><li>Tanggal: {tanggal_pesanan}</li><li>Metode: {metode_pembayaran}</li></ul><p>Produk: {produk}</p>'
defaultBody: `
<h2>Pembayaran Berhasil! 🎉</h2>
<p>Halo <strong>{nama}</strong>, terima kasih atas pembayaran Anda. Kami senang menginformasikan bahwa pembayaran Anda telah berhasil dikonfirmasi.</p>
<h3>Detail Pembayaran</h3>
<table style="width: 100%; border: 2px solid #000; margin-bottom: 25px; border-collapse: collapse;">
<thead>
<tr>
<th style="background-color: #000; color: #FFF; padding: 12px; text-align: left; font-size: 14px; text-transform: uppercase; font-weight: 700; border: 1px solid #000;">Parameter</th>
<th style="background-color: #000; color: #FFF; padding: 12px; text-align: left; font-size: 14px; text-transform: uppercase; font-weight: 700; border: 1px solid #000;">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Order ID</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;"><strong>{order_id}</strong></td>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Tanggal Pesanan</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">{tanggal_pesanan}</td>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Total Pembayaran</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;"><strong>{total}</strong></td>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Metode Pembayaran</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">{metode_pembayaran}</td>
</tr>
</tbody>
</table>
<h3>Produk yang Dibeli</h3>
<p><strong>{produk}</strong></p>
<p style="margin-top: 30px;">
<a href="#" style="display:inline-block;background-color:#000;color:#FFF !important;padding:14px 28px;font-weight:700;text-transform:uppercase;text-decoration:none !important;font-size:16px;border:2px solid #000;box-shadow:4px 4px 0px 0px #000000;margin:10px 0;transition:all 0.1s;text-align:center">
Lihat Detail Pesanan
</a>
</p>
<blockquote style="margin: 0 0 20px 0; padding: 15px 20px; border-left: 6px solid #00A651; background-color: #E6F4EA; font-style: italic; font-weight: 500; color: #005A2B;">
<strong>Info:</strong> Anda akan menerima email terpisah untuk mengakses produk Anda.
</blockquote>
`
},
{
key: 'access_granted',
{
key: 'access_granted',
name: 'Akses Produk Diberikan',
defaultSubject: 'Akses Anda Sudah Aktif - {produk}',
defaultBody: '<h2>Halo {nama}!</h2><p>Selamat! Akses Anda ke <strong>{produk}</strong> sudah aktif.</p><p><a href="{link_akses}" style="display:inline-block;padding:12px 24px;background:#0066cc;color:white;text-decoration:none;border-radius:6px;">Akses Sekarang</a></p>'
defaultBody: `
<h2>Selamat! Akses Aktif 🚀</h2>
<p>Halo <strong>{nama}</strong>, selamat! Akses Anda ke <strong>{produk}</strong> sudah aktif dan siap digunakan.</p>
<p>Anda sekarang dapat mengakses semua materi dan fitur yang tersedia dalam produk ini.</p>
<div style="background-color: #F4F4F5; border: 2px dashed #000; padding: 20px; text-align: center; margin: 20px 0; letter-spacing: 5px; font-family: 'Courier New', Courier, monospace; font-size: 32px; font-weight: 700; color: #000;">
ACCESS GRANTED
</div>
<p style="margin-top: 30px; text-align: center;">
<a href="{link_akses}" style="display:inline-block;background-color:#000;color:#FFF !important;padding:14px 28px;font-weight:700;text-transform:uppercase;text-decoration:none !important;font-size:16px;border:2px solid #000;box-shadow:4px 4px 0px 0px #000000;margin:10px 0;transition:all 0.1s;width:100%;box-sizing:border-box">
Akses Sekarang
</a>
</p>
<h3>Penting:</h3>
<ul>
<li>Simpan link akses ini dengan aman</li>
<li>Jangan bagikan kredensial Anda kepada orang lain</li>
<li>Jika mengalami kendala, hubungi support kami</li>
</ul>
`
},
{
key: 'order_created',
{
key: 'order_created',
name: 'Pesanan Dibuat',
defaultSubject: 'Pesanan Anda #{order_id} Sedang Diproses',
defaultBody: '<h2>Halo {nama}!</h2><p>Pesanan Anda dengan nomor <strong>{order_id}</strong> telah kami terima.</p><p>Total: <strong>{total}</strong></p><p>Silakan selesaikan pembayaran sebelum batas waktu.</p>'
defaultSubject: 'Pesanan #{order_id} Sedang Diproses',
defaultBody: `
<h2>Pesanan Diterima ✅</h2>
<p>Halo <strong>{nama}</strong>, terima kasih telah melakukan pesanan. Kami telah menerima pesanan Anda dengan detail sebagai berikut:</p>
<table style="width: 100%; border: 2px solid #000; margin-bottom: 25px; border-collapse: collapse;">
<thead>
<tr>
<th style="background-color: #000; color: #FFF; padding: 12px; text-align: left; font-size: 14px; text-transform: uppercase; font-weight: 700; border: 1px solid #000;">Informasi Pesanan</th>
<th style="background-color: #000; color: #FFF; padding: 12px; text-align: left; font-size: 14px; text-transform: uppercase; font-weight: 700; border: 1px solid #000;">Detail</th>
</tr>
</thead>
<tbody>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Nomor Pesanan</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;"><strong>{order_id}</strong></td>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Total Pembayaran</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;"><strong>{total}</strong></td>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Status</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Menunggu Pembayaran</td>
</tr>
</tbody>
</table>
<h3>Langkah Selanjutnya:</h3>
<ol>
<li>Selesaikan pembayaran sebelum batas waktu</li>
<li>Setelah pembayaran dikonfirmasi, Anda akan menerima email akses produk</li>
<li>Simpan bukti pembayaran untuk arsip Anda</li>
</ol>
<blockquote style="margin: 0 0 20px 0; padding: 15px 20px; border-left: 6px solid #E11D48; background-color: #FFE4E6; font-style: italic; font-weight: 500; color: #881337;">
<strong>Penting:</strong> Segera lakukan pembayaran agar pesanan tidak kedaluwarsa.
</blockquote>
`
},
{
key: 'payment_reminder',
{
key: 'payment_reminder',
name: 'Pengingat Pembayaran',
defaultSubject: 'Jangan Lupa Bayar - Order #{order_id}',
defaultBody: '<h2>Halo {nama}!</h2><p>Pesanan Anda dengan nomor <strong>{order_id}</strong> menunggu pembayaran.</p><p>Total: <strong>{total}</strong></p><p>Segera selesaikan pembayaran agar tidak kedaluwarsa.</p>'
defaultSubject: 'Reminder: Segera Selesaikan Pembayaran #{order_id}',
defaultBody: `
<h2>Reminder Pembayaran ⏰</h2>
<p>Halo <strong>{nama}</strong>, ini adalah pengingat bahwa pesanan Anda masih menunggu pembayaran.</p>
<table style="width: 100%; border: 2px solid #000; margin-bottom: 25px; border-collapse: collapse;">
<thead>
<tr>
<th style="background-color: #000; color: #FFF; padding: 12px; text-align: left; font-size: 14px; text-transform: uppercase; font-weight: 700; border: 1px solid #000;">Detail Pesanan</th>
<th style="background-color: #000; color: #FFF; padding: 12px; text-align: left; font-size: 14px; text-transform: uppercase; font-weight: 700; border: 1px solid #000;">Informasi</th>
</tr>
</thead>
<tbody>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Order ID</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;"><strong>{order_id}</strong></td>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Total Pembayaran</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;"><strong>{total}</strong></td>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Tanggal Pesanan</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">{tanggal_pesanan}</td>
</tr>
</tbody>
</table>
<p style="margin-top: 30px; text-align: center;">
<a href="#" style="display:inline-block;background-color:#E11D48;color:#FFF !important;padding:14px 28px;font-weight:700;text-transform:uppercase;text-decoration:none !important;font-size:16px;border:2px solid #E11D48;box-shadow:4px 4px 0px 0px #E11D48;margin:10px 0;transition:all 0.1s;width:100%;box-sizing:border-box">
Bayar Sekarang
</a>
</p>
<blockquote style="margin: 0 0 20px 0; padding: 15px 20px; border-left: 6px solid #E11D48; background-color: #FFE4E6; font-style: italic; font-weight: 500; color: #881337;">
<strong>Peringatan:</strong> Jika pembayaran tidak diselesaikan dalam batas waktu, pesanan akan otomatis dibatalkan.
</blockquote>
`
},
{
key: 'consulting_scheduled',
{
key: 'consulting_scheduled',
name: 'Konsultasi Terjadwal',
defaultSubject: 'Konsultasi Anda Sudah Terjadwal - {tanggal_konsultasi}',
defaultBody: '<h2>Halo {nama}!</h2><p>Sesi konsultasi Anda telah dikonfirmasi:</p><ul><li>Tanggal: <strong>{tanggal_konsultasi}</strong></li><li>Jam: <strong>{jam_konsultasi}</strong></li></ul><p>Link meeting: <a href="{link_meet}">{link_meet}</a></p><p>Jika ada pertanyaan, hubungi kami.</p>'
defaultSubject: 'Konsultasi Terjadwal - {tanggal_konsultasi}',
defaultBody: `
<h2>Sesi Konsultasi Dikonfirmasi 📅</h2>
<p>Halo <strong>{nama}</strong>, sesi konsultasi Anda telah berhasil dijadwalkan. Berikut adalah detailnya:</p>
<table style="width: 100%; border: 2px solid #000; margin-bottom: 25px; border-collapse: collapse;">
<thead>
<tr>
<th style="background-color: #000; color: #FFF; padding: 12px; text-align: left; font-size: 14px; text-transform: uppercase; font-weight: 700; border: 1px solid #000;">Detail Sesi</th>
<th style="background-color: #000; color: #FFF; padding: 12px; text-align: left; font-size: 14px; text-transform: uppercase; font-weight: 700; border: 1px solid #000;">Informasi</th>
</tr>
</thead>
<tbody>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Tanggal</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;"><strong>{tanggal_konsultasi}</strong></td>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Waktu</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;"><strong>{jam_konsultasi}</strong></td>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Link Meeting</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">
<a href="{link_meet}" style="color: #000; text-decoration: underline; font-weight: 700;">{link_meet}</a>
</td>
</tr>
</tbody>
</table>
<p style="margin-top: 30px; text-align: center;">
<a href="{link_meet}" style="display:inline-block;background-color:#0066cc;color:#FFF !important;padding:14px 28px;font-weight:700;text-transform:uppercase;text-decoration:none !important;font-size:16px;border:2px solid #0066cc;box-shadow:4px 4px 0px 0px #0066cc;margin:10px 0;transition:all 0.1s">
Bergabung ke Meeting
</a>
</p>
<h3>Persiapan Sebelum Sesi:</h3>
<ul>
<li>Uji koneksi internet Anda</li>
<li>Siapkan materi atau pertanyaan yang akan dibahas</li>
<li>Login 10 menit sebelum jadwal</li>
<li>Gunakan laptop dengan kamera dan mikrofon</li>
</ul>
<blockquote style="margin: 0 0 20px 0; padding: 15px 20px; border-left: 6px solid #1976D2; background-color: #E3F2FD; font-style: italic; font-weight: 500; color: #0D47A1;">
<strong>Tip:</strong> Gunakan Google Chrome untuk pengalaman meeting terbaik.
</blockquote>
`
},
{
key: 'event_reminder',
{
key: 'event_reminder',
name: 'Reminder Webinar/Bootcamp',
defaultSubject: 'Reminder: {judul_event} Dimulai {tanggal_event}',
defaultBody: '<h2>Halo {nama}!</h2><p>Jangan lupa, <strong>{judul_event}</strong> akan dimulai:</p><ul><li>Tanggal: {tanggal_event}</li><li>Jam: {jam_event}</li></ul><p><a href="{link_event}" style="display:inline-block;padding:12px 24px;background:#0066cc;color:white;text-decoration:none;border-radius:6px;">Bergabung</a></p>'
defaultSubject: 'Reminder: {judul_event} - {tanggal_event}',
defaultBody: `
<h2>Jangan Sampai Ketinggalan! 🔥</h2>
<p>Halo <strong>{nama}</strong>, jangan lupa bahwa <strong>{judul_event}</strong> akan segera dimulai!</p>
<div style="background-color: #F4F4F5; border: 2px dashed #000; padding: 20px; text-align: center; margin: 20px 0;">
<h3 style="margin-top: 0; color: #E11D48;">EVENT STARTING SOON!</h3>
<div style="font-size: 24px; font-weight: 700; letter-spacing: 2px; margin: 10px 0;">
{judul_event}
</div>
</div>
<table style="width: 100%; border: 2px solid #000; margin-bottom: 25px; border-collapse: collapse;">
<thead>
<tr>
<th style="background-color: #000; color: #FFF; padding: 12px; text-align: left; font-size: 14px; text-transform: uppercase; font-weight: 700; border: 1px solid #000;">Event Detail</th>
<th style="background-color: #000; color: #FFF; padding: 12px; text-align: left; font-size: 14px; text-transform: uppercase; font-weight: 700; border: 1px solid #000;">Informasi</th>
</tr>
</thead>
<tbody>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Judul Event</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;"><strong>{judul_event}</strong></td>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Tanggal</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">{tanggal_event}</td>
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">Waktu</td>
<td style="padding: 12px; border: 1px solid #000; font-size: 15px; vertical-align: top;">{jam_event}</td>
</tr>
</tbody>
</table>
<p style="margin-top: 30px; text-align: center;">
<a href="{link_event}" style="display:inline-block;background-color:#00A651;color:#FFF !important;padding:14px 28px;font-weight:700;text-transform:uppercase;text-decoration:none !important;font-size:16px;border:2px solid #00A651;box-shadow:4px 4px 0px 0px #00A651;margin:10px 0;transition:all 0.1s;width:100%;box-sizing:border-box">
Bergabung Sekarang
</a>
</p>
<h3>Persiapan Event:</h3>
<ul>
<li>Stabilkan koneksi internet Anda</li>
<li>Siapkan notebook untuk mencatat</li>
<li>Login 15 menit sebelum event dimulai</li>
<li>Siapkan pertanyaan untuk sesi Q&A</li>
</ul>
`
},
{
key: 'bootcamp_progress',
{
key: 'bootcamp_progress',
name: 'Progress Bootcamp',
defaultSubject: 'Update Progress Bootcamp Anda',
defaultBody: '<h2>Halo {nama}!</h2><p>Ini adalah update progress bootcamp Anda.</p><p>Terus semangat belajar!</p>'
defaultSubject: 'Update Progress Bootcamp - {nama}',
defaultBody: `
<h2>Progress Update 📈</h2>
<p>Halo <strong>{nama}</strong>, ini adalah update terbaru tentang progress bootcamp Anda.</p>
<div style="background-color: #F4F4F5; border: 2px dashed #000; padding: 20px; text-align: center; margin: 20px 0;">
<div style="font-size: 18px; font-weight: 700; margin-bottom: 10px;">PROGRESS ANDA</div>
<div style="font-size: 48px; font-weight: 900; color: #00A651;">75%</div>
<div style="font-size: 14px; color: #666;">Completed Modules: 15/20</div>
</div>
<h3>Module Selesai:</h3>
<ul>
<li>✅ Fundamentals & Basics</li>
<li>✅ Advanced Concepts</li>
<li>✅ Practical Applications</li>
<li>✅ Project Workshop</li>
</ul>
<h3>Module Berikutnya:</h3>
<ul>
<li>🔄 Final Assessment</li>
<li>📋 Portfolio Development</li>
</ul>
<p style="margin-top: 30px; text-align: center;">
<a href="#" style="display:inline-block;background-color:#000;color:#FFF !important;padding:14px 28px;font-weight:700;text-transform:uppercase;text-decoration:none !important;font-size:16px;border:2px solid #000;box-shadow:4px 4px 0px 0px #000000;margin:10px 0;transition:all 0.1s">
Lanjut Belajar
</a>
</p>
<blockquote style="margin: 0 0 20px 0; padding: 15px 20px; border-left: 6px solid #00A651; background-color: #E6F4EA; font-style: italic; font-weight: 500; color: #005A2B;">
<strong>Motivasi:</strong> Anda sudah 75% selesai! Terus semangat, kesuksesan Anda sudah di depan mata!
</blockquote>
`
},
];
@@ -81,6 +346,8 @@ export function NotifikasiTab() {
const [loading, setLoading] = useState(true);
const [expandedTemplates, setExpandedTemplates] = useState<Set<string>>(new Set());
const [testingTemplate, setTestingTemplate] = useState<string | null>(null);
const [selectedTemplate, setSelectedTemplate] = useState<NotificationTemplate | null>(null);
const [previewMode, setPreviewMode] = useState<'master' | 'content'>('master');
useEffect(() => {
fetchData();
@@ -316,14 +583,16 @@ export function NotifikasiTab() {
</div>
</div>
{/* Email Preview */}
<div className="space-y-4">
<h4 className="font-semibold">Email Preview</h4>
<EmailTemplatePreview
template={template}
onTest={sendTestEmail}
isTestSending={testingTemplate === template.id}
/>
<div className="flex gap-2">
<Button
onClick={() => {
updateTemplate(template);
setSelectedTemplate(template);
}}
className="shadow-sm flex-1"
>
Simpan & Preview
</Button>
</div>
{template.last_payload_example && (
@@ -350,6 +619,34 @@ export function NotifikasiTab() {
))}
</CardContent>
</Card>
{/* Consolidated Email Preview */}
{selectedTemplate && (
<Card className="border-2 border-border">
<CardHeader>
<CardTitle className="flex items-center justify-between">
<span>Preview: {selectedTemplate.name}</span>
<Button
variant="outline"
size="sm"
onClick={() => setSelectedTemplate(null)}
>
Tutup Preview
</Button>
</CardTitle>
<CardDescription>
Preview template email dengan master styling
</CardDescription>
</CardHeader>
<CardContent>
<EmailTemplatePreview
template={selectedTemplate}
onTest={sendTestEmail}
isTestSending={testingTemplate === selectedTemplate.id}
/>
</CardContent>
</Card>
)}
</div>
);
}