Improve shortcode UI and add payment link shortcodes

 UI Improvements:
- Completely redesigned shortcode display with clean categorization
- Added collapsible section for all available shortcodes
- Used emoji icons for better visual organization
- Improved color coding and typography
- Added "Used in this template" section with visual distinction

 New Shortcodes:
- Added {payment_link} for direct payment links in emails
- Added {thank_you_page} for public thank you page access
- Updated relevant templates to include new payment shortcodes

🎯 Key Features:
- Shortcodes organized by category (User, Order, Product, Access, etc.)
- Visual hierarchy with proper spacing and borders
- Hover effects and smooth transitions
- Better readability with proper contrast

🤖 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 22:17:51 +07:00
parent 3f8cd7937a
commit 7244433e12
3 changed files with 192 additions and 50 deletions

View File

@@ -179,53 +179,193 @@ export function EmailTemplatePreview({
</div> </div>
{/* Shortcodes Used */} {/* Shortcodes Used */}
<div className="p-3 bg-blue-50 border border-blue-200 rounded"> <div className="p-4 bg-blue-50 border border-blue-200 rounded-lg">
<h4 className="font-semibold text-sm mb-2">Shortcodes Used in This Template:</h4> <h4 className="font-semibold text-sm mb-3 flex items-center gap-2">
<div className="grid grid-cols-2 md:grid-cols-3 gap-2 text-sm max-h-32 overflow-y-auto"> <span className="w-2 h-2 bg-blue-500 rounded-full"></span>
{[ Shortcodes Available
// User information </h4>
'{nama}', '{email}',
// Order information {/* Used in this template */}
'{order_id}', '{tanggal_pesanan}', '{total}', '{metode_pembayaran}', '{status_pesanan}', '{invoice_url}', <div className="mb-4">
// Product information <p className="text-xs font-medium text-blue-700 mb-2">Used in this template:</p>
'{produk}', '{kategori_produk}', '{harga_produk}', '{deskripsi_produk}', <div className="flex flex-wrap gap-1">
// Access information {[
'{link_akses}', '{username_akses}', '{password_akses}', '{kadaluarsa_akses}', // User information
// Consulting information '{nama}', '{email}',
'{tanggal_konsultasi}', '{jam_konsultasi}', '{durasi_konsultasi}', '{link_meet}', // Order information
'{jenis_konsultasi}', '{topik_konsultasi}', '{order_id}', '{tanggal_pesanan}', '{total}', '{metode_pembayaran}', '{status_pesanan}', '{invoice_url}',
// Event information // Product information
'{judul_event}', '{tanggal_event}', '{jam_event}', '{link_event}', '{lokasi_event}', '{kapasitas_event}', '{produk}', '{kategori_produk}', '{harga_produk}', '{deskripsi_produk}',
// Bootcamp/Course information // Access information
'{judul_bootcamp}', '{progres_bootcamp}', '{modul_selesai}', '{modul_selanjutnya}', '{link_progress}', '{link_akses}', '{username_akses}', '{password_akses}', '{kadaluarsa_akses}',
// Company information // Consulting information
'{nama_perusahaan}', '{website_perusahaan}', '{email_support}', '{telepon_support}', '{tanggal_konsultasi}', '{jam_konsultasi}', '{durasi_konsultasi}', '{link_meet}',
// Payment information '{jenis_konsultasi}', '{topik_konsultasi}',
'{bank_tujuan}', '{nomor_rekening}', '{atas_nama}', '{jumlah_pembayaran}', '{batas_pembayaran}' // Event information
].filter(shortcode => '{judul_event}', '{tanggal_event}', '{jam_event}', '{link_event}', '{lokasi_event}', '{kapasitas_event}',
(template.email_subject && template.email_subject.includes(shortcode)) || // Bootcamp/Course information
(template.email_body_html && template.email_body_html.includes(shortcode)) '{judul_bootcamp}', '{progres_bootcamp}', '{modul_selesai}', '{modul_selanjutnya}', '{link_progress}',
).map(shortcode => ( // Company information
<code key={shortcode} className="bg-blue-100 px-2 py-1 rounded text-xs"> '{nama_perusahaan}', '{website_perusahaan}', '{email_support}', '{telepon_support}',
{shortcode} // Payment information
</code> '{bank_tujuan}', '{nomor_rekening}', '{atas_nama}', '{jumlah_pembayaran}', '{batas_pembayaran}',
))} '{payment_link}', '{thank_you_page}'
</div> ].filter(shortcode =>
{((template.email_subject && template.email_subject.includes('{')) || (template.email_subject && template.email_subject.includes(shortcode)) ||
(template.email_body_html && template.email_body_html.includes('{'))) && ( (template.email_body_html && template.email_body_html.includes(shortcode))
<div className="mt-3 pt-3 border-t border-blue-200"> ).map(shortcode => (
<p className="text-xs text-blue-700"> <code key={shortcode} className="bg-blue-100 text-blue-800 px-2 py-1 rounded text-xs font-mono border border-blue-300">
<strong>All Available Shortcodes:</strong> User ({`{nama}`}, {`{email}`}), Orders ({`{order_id}`}, {`{tanggal_pesanan}`}, {`{total}`}, {`{metode_pembayaran}`}, {`{status_pesanan}`}, {`{invoice_url}`}), {shortcode}
Products ({`{produk}`}, {`{kategori_produk}`}, {`{harga_produk}`}), </code>
Access ({`{link_akses}`}, {`{username_akses}`}, {`{password_akses}`}), ))}
Consulting ({`{tanggal_konsultasi}`}, {`{jam_konsultasi}`}, {`{link_meet}`}), {![
Events ({`{judul_event}`}, {`{tanggal_event}`}, {`{link_event}`}), // User information
Bootcamp ({`{judul_bootcamp}`}, {`{progres_bootcamp}`}, {`{modul_selesai}`}), '{nama}', '{email}',
Payment ({`{bank_tujuan}`}, {`{nomor_rekening}`}, {`{jumlah_pembayaran}`}), // Order information
Company ({`{nama_perusahaan}`}, {`{email_support}`}) '{order_id}', '{tanggal_pesanan}', '{total}', '{metode_pembayaran}', '{status_pesanan}', '{invoice_url}',
</p> // Product information
'{produk}', '{kategori_produk}', '{harga_produk}', '{deskripsi_produk}',
// Access information
'{link_akses}', '{username_akses}', '{password_akses}', '{kadaluarsa_akses}',
// Consulting information
'{tanggal_konsultasi}', '{jam_konsultasi}', '{durasi_konsultasi}', '{link_meet}',
'{jenis_konsultasi}', '{topik_konsultasi}',
// Event information
'{judul_event}', '{tanggal_event}', '{jam_event}', '{link_event}', '{lokasi_event}', '{kapasitas_event}',
// Bootcamp/Course information
'{judul_bootcamp}', '{progres_bootcamp}', '{modul_selesai}', '{modul_selanjutnya}', '{link_progress}',
// Company information
'{nama_perusahaan}', '{website_perusahaan}', '{email_support}', '{telepon_support}',
// Payment information
'{bank_tujuan}', '{nomor_rekening}', '{atas_nama}', '{jumlah_pembayaran}', '{batas_pembayaran}',
'{payment_link}', '{thank_you_page}'
].some(shortcode =>
(template.email_subject && template.email_subject.includes(shortcode)) ||
(template.email_body_html && template.email_body_html.includes(shortcode))
) && (
<span className="text-xs text-gray-500 italic">No shortcodes used yet</span>
)}
</div> </div>
)} </div>
{/* All available shortcodes */}
<details className="group">
<summary className="cursor-pointer text-xs font-medium text-blue-700 hover:text-blue-900 transition-colors flex items-center gap-1">
<span className="group-open:rotate-90 transition-transform"></span>
View all available shortcodes
</summary>
<div className="mt-3 pt-3 border-t border-blue-200 space-y-3">
{/* User Information */}
<div>
<p className="text-xs font-semibold text-gray-700 mb-1">👤 User Information</p>
<div className="flex flex-wrap gap-1">
{['{nama}', '{email}'].map(shortcode => (
<code key={shortcode} className="bg-gray-100 text-gray-700 px-2 py-1 rounded text-xs font-mono border border-gray-300">
{shortcode}
</code>
))}
</div>
</div>
{/* Order Information */}
<div>
<p className="text-xs font-semibold text-gray-700 mb-1">📦 Order Information</p>
<div className="flex flex-wrap gap-1">
{['{order_id}', '{tanggal_pesanan}', '{total}', '{metode_pembayaran}', '{status_pesanan}', '{invoice_url}'].map(shortcode => (
<code key={shortcode} className="bg-gray-100 text-gray-700 px-2 py-1 rounded text-xs font-mono border border-gray-300">
{shortcode}
</code>
))}
</div>
</div>
{/* Product Information */}
<div>
<p className="text-xs font-semibold text-gray-700 mb-1">🛍 Product Information</p>
<div className="flex flex-wrap gap-1">
{['{produk}', '{kategori_produk}', '{harga_produk}', '{deskripsi_produk}'].map(shortcode => (
<code key={shortcode} className="bg-gray-100 text-gray-700 px-2 py-1 rounded text-xs font-mono border border-gray-300">
{shortcode}
</code>
))}
</div>
</div>
{/* Access Information */}
<div>
<p className="text-xs font-semibold text-gray-700 mb-1">🔐 Access Information</p>
<div className="flex flex-wrap gap-1">
{['{link_akses}', '{username_akses}', '{password_akses}', '{kadaluarsa_akses}'].map(shortcode => (
<code key={shortcode} className="bg-gray-100 text-gray-700 px-2 py-1 rounded text-xs font-mono border border-gray-300">
{shortcode}
</code>
))}
</div>
</div>
{/* Payment Information */}
<div>
<p className="text-xs font-semibold text-gray-700 mb-1">💳 Payment Information</p>
<div className="flex flex-wrap gap-1">
{['{bank_tujuan}', '{nomor_rekening}', '{atas_nama}', '{jumlah_pembayaran}', '{batas_pembayaran}', '{payment_link}', '{thank_you_page}'].map(shortcode => (
<code key={shortcode} className="bg-gray-100 text-gray-700 px-2 py-1 rounded text-xs font-mono border border-gray-300">
{shortcode}
</code>
))}
</div>
</div>
{/* Consulting Information */}
<div>
<p className="text-xs font-semibold text-gray-700 mb-1">📅 Consulting Information</p>
<div className="flex flex-wrap gap-1">
{['{tanggal_konsultasi}', '{jam_konsultasi}', '{durasi_konsultasi}', '{link_meet}', '{jenis_konsultasi}', '{topik_konsultasi}'].map(shortcode => (
<code key={shortcode} className="bg-gray-100 text-gray-700 px-2 py-1 rounded text-xs font-mono border border-gray-300">
{shortcode}
</code>
))}
</div>
</div>
{/* Event Information */}
<div>
<p className="text-xs font-semibold text-gray-700 mb-1">🎪 Event Information</p>
<div className="flex flex-wrap gap-1">
{['{judul_event}', '{tanggal_event}', '{jam_event}', '{link_event}', '{lokasi_event}', '{kapasitas_event}'].map(shortcode => (
<code key={shortcode} className="bg-gray-100 text-gray-700 px-2 py-1 rounded text-xs font-mono border border-gray-300">
{shortcode}
</code>
))}
</div>
</div>
{/* Bootcamp Information */}
<div>
<p className="text-xs font-semibold text-gray-700 mb-1">🎓 Bootcamp Information</p>
<div className="flex flex-wrap gap-1">
{['{judul_bootcamp}', '{progres_bootcamp}', '{modul_selesai}', '{modul_selanjutnya}', '{link_progress}'].map(shortcode => (
<code key={shortcode} className="bg-gray-100 text-gray-700 px-2 py-1 rounded text-xs font-mono border border-gray-300">
{shortcode}
</code>
))}
</div>
</div>
{/* Company Information */}
<div>
<p className="text-xs font-semibold text-gray-700 mb-1">🏢 Company Information</p>
<div className="flex flex-wrap gap-1">
{['{nama_perusahaan}', '{website_perusahaan}', '{email_support}', '{telepon_support}'].map(shortcode => (
<code key={shortcode} className="bg-gray-100 text-gray-700 px-2 py-1 rounded text-xs font-mono border border-gray-300">
{shortcode}
</code>
))}
</div>
</div>
</div>
</details>
</div> </div>
{/* Template Actions */} {/* Template Actions */}

View File

@@ -24,10 +24,10 @@ interface NotificationTemplate {
} }
const RELEVANT_SHORTCODES = { const RELEVANT_SHORTCODES = {
'payment_success': ['{nama}', '{email}', '{order_id}', '{tanggal_pesanan}', '{total}', '{metode_pembayaran}', '{produk}', '{link_akses}'], 'payment_success': ['{nama}', '{email}', '{order_id}', '{tanggal_pesanan}', '{total}', '{metode_pembayaran}', '{produk}', '{link_akses}', '{thank_you_page}'],
'access_granted': ['{nama}', '{email}', '{produk}', '{link_akses}', '{username_akses}', '{password_akses}', '{kadaluarsa_akses}'], 'access_granted': ['{nama}', '{email}', '{produk}', '{link_akses}', '{username_akses}', '{password_akses}', '{kadaluarsa_akses}'],
'order_created': ['{nama}', '{email}', '{order_id}', '{tanggal_pesanan}', '{total}', '{metode_pembayaran}', '{produk}'], 'order_created': ['{nama}', '{email}', '{order_id}', '{tanggal_pesanan}', '{total}', '{metode_pembayaran}', '{produk}', '{payment_link}'],
'payment_reminder': ['{nama}', '{email}', '{order_id}', '{tanggal_pesanan}', '{total}', '{metode_pembayaran}', '{batas_pembayaran}', '{jumlah_pembayaran}', '{bank_tujuan}', '{nomor_rekening}'], 'payment_reminder': ['{nama}', '{email}', '{order_id}', '{tanggal_pesanan}', '{total}', '{metode_pembayaran}', '{batas_pembayaran}', '{jumlah_pembayaran}', '{bank_tujuan}', '{nomor_rekening}', '{payment_link}'],
'consulting_scheduled': ['{nama}', '{email}', '{tanggal_konsultasi}', '{jam_konsultasi}', '{durasi_konsultasi}', '{link_meet}', '{jenis_konsultasi}', '{topik_konsultasi}'], 'consulting_scheduled': ['{nama}', '{email}', '{tanggal_konsultasi}', '{jam_konsultasi}', '{durasi_konsultasi}', '{link_meet}', '{jenis_konsultasi}', '{topik_konsultasi}'],
'event_reminder': ['{nama}', '{email}', '{judul_event}', '{tanggal_event}', '{jam_event}', '{link_event}', '{lokasi_event}', '{kapasitas_event}'], 'event_reminder': ['{nama}', '{email}', '{judul_event}', '{tanggal_event}', '{jam_event}', '{link_event}', '{lokasi_event}', '{kapasitas_event}'],
'bootcamp_progress': ['{nama}', '{email}', '{judul_bootcamp}', '{progres_bootcamp}', '{modul_selesai}', '{modul_selanjutnya}', '{link_progress}'], 'bootcamp_progress': ['{nama}', '{email}', '{judul_bootcamp}', '{progres_bootcamp}', '{modul_selesai}', '{modul_selanjutnya}', '{link_progress}'],

View File

@@ -405,7 +405,9 @@ export class ShortcodeProcessor {
nomor_rekening: '123-456-7890', nomor_rekening: '123-456-7890',
atas_nama: 'PT Access Hub Indonesia', atas_nama: 'PT Access Hub Indonesia',
jumlah_pembayaran: 'Rp 1.500.000', jumlah_pembayaran: 'Rp 1.500.000',
batas_pembayaran: '22 Desember 2025 23:59' batas_pembayaran: '22 Desember 2025 23:59',
payment_link: 'https://accesshub.example.com/payment/ORD-123456',
thank_you_page: 'https://accesshub.example.com/thank-you/ORD-123456'
}; };
static process(content: string, customData: Record<string, string> = {}): string { static process(content: string, customData: Record<string, string> = {}): string {