260 lines
14 KiB
PHP
260 lines
14 KiB
PHP
|
|
<?php
|
|||
|
|
$pageTitle = 'Newsletter';
|
|||
|
|
$campaigns = $campaigns ?? [];
|
|||
|
|
ob_start();
|
|||
|
|
?>
|
|||
|
|
<section class="admin-card">
|
|||
|
|
<div class="badge">Newsletter</div>
|
|||
|
|
<div style="display:flex; align-items:center; justify-content:space-between; gap:16px; margin-top:16px;">
|
|||
|
|
<div>
|
|||
|
|
<h1 style="font-size:28px; margin:0;">Campaigns</h1>
|
|||
|
|
<p style="color: var(--muted); margin-top:6px;">Build and send HTML newsletters.</p>
|
|||
|
|
</div>
|
|||
|
|
<div style="display:flex; gap:10px;">
|
|||
|
|
<a href="/admin/newsletter/subscribers" class="btn outline small">Subscribers</a>
|
|||
|
|
<form method="post" action="/admin/newsletter/campaigns/process" style="display:inline;">
|
|||
|
|
<button type="submit" class="btn outline small">Process Queue</button>
|
|||
|
|
</form>
|
|||
|
|
<a href="/admin/newsletter/campaigns/new" class="btn small">New Campaign</a>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="margin-top:18px; display:grid; gap:10px;">
|
|||
|
|
<div style="display:grid; grid-template-columns: 2fr 1.4fr 120px 140px 140px 140px; gap:12px; font-size:11px; color:var(--muted); text-transform:uppercase; letter-spacing:0.2em;">
|
|||
|
|
<div>Title</div>
|
|||
|
|
<div>Subject</div>
|
|||
|
|
<div>Status</div>
|
|||
|
|
<div>Scheduled</div>
|
|||
|
|
<div>Sent At</div>
|
|||
|
|
<div>Actions</div>
|
|||
|
|
</div>
|
|||
|
|
<?php if (!$campaigns): ?>
|
|||
|
|
<div style="color: var(--muted); font-size:13px;">No campaigns yet.</div>
|
|||
|
|
<?php else: ?>
|
|||
|
|
<?php foreach ($campaigns as $campaign): ?>
|
|||
|
|
<div style="display:grid; grid-template-columns: 2fr 1.4fr 120px 140px 140px 140px; gap:12px; align-items:center; padding:10px 12px; border-radius:16px; border:1px solid var(--stroke); background: rgba(14,14,16,0.9);">
|
|||
|
|
<div style="font-weight:600;"><?= htmlspecialchars((string)($campaign['title'] ?? ''), ENT_QUOTES, 'UTF-8') ?></div>
|
|||
|
|
<div style="font-size:12px; color:var(--muted);"><?= htmlspecialchars((string)($campaign['subject'] ?? ''), ENT_QUOTES, 'UTF-8') ?></div>
|
|||
|
|
<div style="font-size:12px; color:<?= ((string)($campaign['status'] ?? '') === 'sent') ? 'var(--accent-2)' : 'var(--muted)' ?>;">
|
|||
|
|
<?= htmlspecialchars((string)($campaign['status'] ?? 'draft'), ENT_QUOTES, 'UTF-8') ?>
|
|||
|
|
</div>
|
|||
|
|
<div style="font-size:12px; color:var(--muted);"><?= htmlspecialchars((string)($campaign['scheduled_at'] ?? ''), ENT_QUOTES, 'UTF-8') ?></div>
|
|||
|
|
<div style="font-size:12px; color:var(--muted);"><?= htmlspecialchars((string)($campaign['sent_at'] ?? ''), ENT_QUOTES, 'UTF-8') ?></div>
|
|||
|
|
<div style="display:flex; gap:8px;">
|
|||
|
|
<a href="/admin/newsletter/campaigns/edit?id=<?= (int)$campaign['id'] ?>" class="btn outline small">Edit</a>
|
|||
|
|
<form method="post" action="/admin/newsletter/campaigns/send" onsubmit="return confirm('Send this campaign now?');">
|
|||
|
|
<input type="hidden" name="id" value="<?= (int)$campaign['id'] ?>">
|
|||
|
|
<button type="submit" class="btn small">Send</button>
|
|||
|
|
</form>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<?php endforeach; ?>
|
|||
|
|
<?php endif; ?>
|
|||
|
|
</div>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<section class="admin-card" style="margin-top:16px;">
|
|||
|
|
<div class="badge">Signup Form</div>
|
|||
|
|
<p style="color: var(--muted); margin-top:10px;">Choose a signup form template to paste into any custom page.</p>
|
|||
|
|
<div style="margin-top:12px; display:grid; gap:12px;">
|
|||
|
|
<select id="signupTemplateSelect" class="input" style="text-transform:none;">
|
|||
|
|
<option value="">Select template</option>
|
|||
|
|
<option value="signup-compact">Compact Inline</option>
|
|||
|
|
<option value="signup-card">Card Form</option>
|
|||
|
|
<option value="signup-minimal">Minimal</option>
|
|||
|
|
<option value="signup-banner">Banner CTA</option>
|
|||
|
|
</select>
|
|||
|
|
<div id="signupTemplatePreview" style="border:1px solid rgba(255,255,255,0.12); border-radius:14px; padding:12px; background: rgba(0,0,0,0.2); min-height:120px;"></div>
|
|||
|
|
<div style="display:flex; gap:10px; justify-content:flex-end;">
|
|||
|
|
<button type="button" id="copySignupTemplate" class="btn outline small">Copy HTML</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<section class="admin-card" style="margin-top:16px;">
|
|||
|
|
<div class="badge">Template Starter</div>
|
|||
|
|
<p style="color: var(--muted); margin-top:10px;">Pick a campaign template, preview it, then copy HTML.</p>
|
|||
|
|
<div style="margin-top:12px; display:grid; gap:12px;">
|
|||
|
|
<select id="newsletterTemplateSelect" class="input" style="text-transform:none;">
|
|||
|
|
<option value="">Select template</option>
|
|||
|
|
<option value="email-minimal">Minimal Update</option>
|
|||
|
|
<option value="email-feature">Feature Promo</option>
|
|||
|
|
<option value="email-digest">Weekly Digest</option>
|
|||
|
|
<option value="email-event">Event Invite</option>
|
|||
|
|
</select>
|
|||
|
|
<div id="newsletterTemplatePreview" style="border:1px solid rgba(255,255,255,0.12); border-radius:14px; padding:12px; background: rgba(0,0,0,0.2); min-height:140px;"></div>
|
|||
|
|
<div style="display:flex; gap:10px; justify-content:flex-end;">
|
|||
|
|
<button type="button" id="copyNewsletterTemplate" class="btn outline small">Copy HTML</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
(function () {
|
|||
|
|
const signupTemplates = {
|
|||
|
|
'signup-compact': {
|
|||
|
|
html: `<form method="post" action="/newsletter/subscribe" style="display:flex; gap:8px; flex-wrap:wrap;">
|
|||
|
|
<input type="text" name="name" placeholder="Name" style="padding:10px 12px; border-radius:10px; border:1px solid #e5e7eb;">
|
|||
|
|
<input type="email" name="email" placeholder="Email" required style="padding:10px 12px; border-radius:10px; border:1px solid #e5e7eb;">
|
|||
|
|
<button type="submit" style="padding:10px 16px; border-radius:999px; border:none; background:#22f2a5; color:#071016;">Subscribe</button>
|
|||
|
|
</form>`,
|
|||
|
|
preview: `<div style="background:#0f1117; padding:12px; border-radius:12px;">
|
|||
|
|
<div style="color:#c9cbd4; font-size:12px; margin-bottom:8px;">Compact Inline</div>
|
|||
|
|
<div style="display:flex; gap:8px; flex-wrap:wrap;">
|
|||
|
|
<div style="flex:1; min-width:120px; height:34px; border-radius:8px; background:#1b1e26;"></div>
|
|||
|
|
<div style="flex:1; min-width:120px; height:34px; border-radius:8px; background:#1b1e26;"></div>
|
|||
|
|
<div style="width:110px; height:34px; border-radius:999px; background:#22f2a5;"></div>
|
|||
|
|
</div>
|
|||
|
|
</div>`
|
|||
|
|
},
|
|||
|
|
'signup-card': {
|
|||
|
|
html: `<div style="padding:18px; border:1px solid #e5e7eb; border-radius:12px;">
|
|||
|
|
<h3 style="margin:0 0 8px;">Join the newsletter</h3>
|
|||
|
|
<p style="margin:0 0 12px;">Monthly updates and releases.</p>
|
|||
|
|
<form method="post" action="/newsletter/subscribe" style="display:grid; gap:8px;">
|
|||
|
|
<input type="text" name="name" placeholder="Name" style="padding:10px 12px; border-radius:10px; border:1px solid #e5e7eb;">
|
|||
|
|
<input type="email" name="email" placeholder="Email" required style="padding:10px 12px; border-radius:10px; border:1px solid #e5e7eb;">
|
|||
|
|
<button type="submit" style="padding:10px 16px; border-radius:999px; border:none; background:#22f2a5; color:#071016;">Subscribe</button>
|
|||
|
|
</form>
|
|||
|
|
</div>`,
|
|||
|
|
preview: `<div style="background:#0f1117; padding:12px; border-radius:12px;">
|
|||
|
|
<div style="height:10px; width:120px; background:#2a2e3a; border-radius:6px; margin-bottom:10px;"></div>
|
|||
|
|
<div style="height:8px; width:180px; background:#1b1e26; border-radius:6px; margin-bottom:12px;"></div>
|
|||
|
|
<div style="display:grid; gap:8px;">
|
|||
|
|
<div style="height:34px; border-radius:8px; background:#1b1e26;"></div>
|
|||
|
|
<div style="height:34px; border-radius:8px; background:#1b1e26;"></div>
|
|||
|
|
<div style="height:34px; width:120px; border-radius:999px; background:#22f2a5;"></div>
|
|||
|
|
</div>
|
|||
|
|
</div>`
|
|||
|
|
},
|
|||
|
|
'signup-minimal': {
|
|||
|
|
html: `<form method="post" action="/newsletter/subscribe">
|
|||
|
|
<input type="email" name="email" placeholder="Email" required style="padding:10px 12px; border-radius:10px; border:1px solid #e5e7eb; width:100%; max-width:320px;">
|
|||
|
|
<button type="submit" style="margin-top:8px; padding:8px 14px; border-radius:999px; border:1px solid #111; background:#111; color:#fff;">Subscribe</button>
|
|||
|
|
</form>`,
|
|||
|
|
preview: `<div style="background:#0f1117; padding:12px; border-radius:12px;">
|
|||
|
|
<div style="height:34px; width:240px; border-radius:8px; background:#1b1e26;"></div>
|
|||
|
|
<div style="height:30px; width:110px; border-radius:999px; background:#2a2e3a; margin-top:8px;"></div>
|
|||
|
|
</div>`
|
|||
|
|
},
|
|||
|
|
'signup-banner': {
|
|||
|
|
html: `<div style="padding:16px; border-radius:12px; background:#0f172a; color:#fff; display:flex; flex-wrap:wrap; gap:12px; align-items:center;">
|
|||
|
|
<div style="flex:1; min-width:180px;">
|
|||
|
|
<strong>Get updates</strong><br>
|
|||
|
|
New releases, events, and drops.
|
|||
|
|
</div>
|
|||
|
|
<form method="post" action="/newsletter/subscribe" style="display:flex; gap:8px; flex-wrap:wrap;">
|
|||
|
|
<input type="email" name="email" placeholder="Email" required style="padding:10px 12px; border-radius:10px; border:1px solid #1f2937;">
|
|||
|
|
<button type="submit" style="padding:10px 16px; border-radius:999px; border:none; background:#22f2a5; color:#071016;">Subscribe</button>
|
|||
|
|
</form>
|
|||
|
|
</div>`,
|
|||
|
|
preview: `<div style="background:#0f1117; padding:12px; border-radius:12px;">
|
|||
|
|
<div style="height:16px; width:160px; background:#1b1e26; border-radius:6px; margin-bottom:8px;"></div>
|
|||
|
|
<div style="display:flex; gap:8px; flex-wrap:wrap;">
|
|||
|
|
<div style="height:34px; width:160px; border-radius:8px; background:#1b1e26;"></div>
|
|||
|
|
<div style="height:34px; width:110px; border-radius:999px; background:#22f2a5;"></div>
|
|||
|
|
</div>
|
|||
|
|
</div>`
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const emailTemplates = {
|
|||
|
|
'email-minimal': {
|
|||
|
|
html: `<div style="font-family:Arial, sans-serif; color:#111; line-height:1.6;">
|
|||
|
|
<h1 style="margin:0 0 8px;">AudioCore Update</h1>
|
|||
|
|
<p style="margin:0 0 16px;">Latest releases, news, and announcements.</p>
|
|||
|
|
<p style="margin:0;">Thanks for listening.</p>
|
|||
|
|
</div>`,
|
|||
|
|
preview: `<div style="background:#fff; color:#111; padding:12px; border-radius:8px;">
|
|||
|
|
<div style="height:16px; width:180px; background:#e5e7eb; border-radius:6px; margin-bottom:8px;"></div>
|
|||
|
|
<div style="height:10px; width:240px; background:#f3f4f6; border-radius:6px; margin-bottom:10px;"></div>
|
|||
|
|
<div style="height:10px; width:120px; background:#f3f4f6; border-radius:6px;"></div>
|
|||
|
|
</div>`
|
|||
|
|
},
|
|||
|
|
'email-feature': {
|
|||
|
|
html: `<div style="font-family:Arial, sans-serif; color:#111; line-height:1.6;">
|
|||
|
|
<h1 style="margin:0 0 8px;">Featured Release</h1>
|
|||
|
|
<img src="https://placehold.co/600x360/111827/ffffff?text=Cover" alt="" style="width:100%; border-radius:10px; margin:8px 0;">
|
|||
|
|
<p style="margin:0 0 12px;">REC008 – Night Drive EP now available.</p>
|
|||
|
|
<a href="#" style="display:inline-block; padding:10px 16px; border-radius:999px; background:#22f2a5; color:#071016; text-decoration:none;">Listen now</a>
|
|||
|
|
</div>`,
|
|||
|
|
preview: `<div style="background:#fff; color:#111; padding:12px; border-radius:8px;">
|
|||
|
|
<div style="height:16px; width:160px; background:#e5e7eb; border-radius:6px; margin-bottom:8px;"></div>
|
|||
|
|
<div style="height:120px; background:#e5e7eb; border-radius:8px; margin-bottom:10px;"></div>
|
|||
|
|
<div style="height:10px; width:200px; background:#f3f4f6; border-radius:6px; margin-bottom:12px;"></div>
|
|||
|
|
<div style="height:30px; width:120px; background:#22f2a5; border-radius:999px;"></div>
|
|||
|
|
</div>`
|
|||
|
|
},
|
|||
|
|
'email-digest': {
|
|||
|
|
html: `<div style="font-family:Arial, sans-serif; color:#111; line-height:1.6;">
|
|||
|
|
<h1 style="margin:0 0 12px;">Weekly Digest</h1>
|
|||
|
|
<ul style="padding-left:18px; margin:0 0 12px;">
|
|||
|
|
<li>New release: REC009 – Twilight Runner</li>
|
|||
|
|
<li>Label spotlight: Neon District</li>
|
|||
|
|
<li>Playlist update: Midnight Circuit</li>
|
|||
|
|
</ul>
|
|||
|
|
<p style="margin:0;">See the full catalog for more.</p>
|
|||
|
|
</div>`,
|
|||
|
|
preview: `<div style="background:#fff; color:#111; padding:12px; border-radius:8px;">
|
|||
|
|
<div style="height:16px; width:160px; background:#e5e7eb; border-radius:6px; margin-bottom:10px;"></div>
|
|||
|
|
<div style="height:10px; width:240px; background:#f3f4f6; border-radius:6px; margin-bottom:6px;"></div>
|
|||
|
|
<div style="height:10px; width:200px; background:#f3f4f6; border-radius:6px; margin-bottom:6px;"></div>
|
|||
|
|
<div style="height:10px; width:180px; background:#f3f4f6; border-radius:6px; margin-bottom:12px;"></div>
|
|||
|
|
<div style="height:10px; width:200px; background:#f3f4f6; border-radius:6px;"></div>
|
|||
|
|
</div>`
|
|||
|
|
},
|
|||
|
|
'email-event': {
|
|||
|
|
html: `<div style="font-family:Arial, sans-serif; color:#111; line-height:1.6;">
|
|||
|
|
<h1 style="margin:0 0 8px;">Live Showcase</h1>
|
|||
|
|
<p style="margin:0 0 12px;">Friday, 8PM · Warehouse 12</p>
|
|||
|
|
<a href="#" style="display:inline-block; padding:10px 16px; border-radius:999px; background:#111; color:#fff; text-decoration:none;">RSVP</a>
|
|||
|
|
</div>`,
|
|||
|
|
preview: `<div style="background:#fff; color:#111; padding:12px; border-radius:8px;">
|
|||
|
|
<div style="height:16px; width:140px; background:#e5e7eb; border-radius:6px; margin-bottom:8px;"></div>
|
|||
|
|
<div style="height:10px; width:160px; background:#f3f4f6; border-radius:6px; margin-bottom:12px;"></div>
|
|||
|
|
<div style="height:30px; width:80px; background:#111; border-radius:999px;"></div>
|
|||
|
|
</div>`
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
function wirePicker(selectId, previewId, copyId, templates) {
|
|||
|
|
const select = document.getElementById(selectId);
|
|||
|
|
const preview = document.getElementById(previewId);
|
|||
|
|
const copyBtn = document.getElementById(copyId);
|
|||
|
|
if (!select || !preview || !copyBtn) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function renderPreview() {
|
|||
|
|
const key = select.value;
|
|||
|
|
preview.innerHTML = key && templates[key] ? templates[key].preview : '';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
select.addEventListener('change', renderPreview);
|
|||
|
|
copyBtn.addEventListener('click', async function () {
|
|||
|
|
const key = select.value;
|
|||
|
|
if (!key || !templates[key]) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
const html = templates[key].html;
|
|||
|
|
try {
|
|||
|
|
await navigator.clipboard.writeText(html);
|
|||
|
|
copyBtn.textContent = 'Copied';
|
|||
|
|
setTimeout(() => (copyBtn.textContent = 'Copy HTML'), 1200);
|
|||
|
|
} catch (err) {
|
|||
|
|
copyBtn.textContent = 'Copy failed';
|
|||
|
|
setTimeout(() => (copyBtn.textContent = 'Copy HTML'), 1200);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
renderPreview();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
wirePicker('signupTemplateSelect', 'signupTemplatePreview', 'copySignupTemplate', signupTemplates);
|
|||
|
|
wirePicker('newsletterTemplateSelect', 'newsletterTemplatePreview', 'copyNewsletterTemplate', emailTemplates);
|
|||
|
|
})();
|
|||
|
|
</script>
|
|||
|
|
<?php
|
|||
|
|
$content = ob_get_clean();
|
|||
|
|
require __DIR__ . '/../../../admin/views/layout.php';
|