Files
contact.allucanget.biz/templates/admin_newsletter_create.html
zwitschi 4cefd4e3ab
Some checks failed
CI / test (3.11) (push) Failing after 5m36s
CI / build-image (push) Has been skipped
v1
2025-10-22 16:48:55 +02:00

460 lines
13 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Create Newsletter</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
h1 {
color: #333;
margin-bottom: 20px;
}
.nav {
margin-bottom: 20px;
padding: 10px;
background-color: #f8f9fa;
border-radius: 5px;
}
.nav a {
margin-right: 15px;
color: #007bff;
text-decoration: none;
}
.nav a:hover {
text-decoration: underline;
}
.form-section {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
background-color: #f9f9f9;
}
.form-section h2 {
margin-top: 0;
color: #555;
border-bottom: 1px solid #ddd;
padding-bottom: 10px;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
color: #333;
}
.form-group input,
.form-group textarea,
.form-group select {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
box-sizing: border-box;
}
.form-group textarea {
min-height: 200px;
resize: vertical;
}
.form-row {
display: flex;
gap: 15px;
margin-bottom: 15px;
}
.form-row .form-group {
flex: 1;
margin-bottom: 0;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin-right: 10px;
}
.btn-primary {
background-color: #007bff;
color: white;
}
.btn-primary:hover {
background-color: #0056b3;
}
.btn-secondary {
background-color: #6c757d;
color: white;
}
.btn-secondary:hover {
background-color: #545b62;
}
.btn-success {
background-color: #28a745;
color: white;
}
.btn-success:hover {
background-color: #1e7e34;
}
.btn-danger {
background-color: #dc3545;
color: white;
}
.btn-danger:hover {
background-color: #c82333;
}
.message {
padding: 10px;
margin-bottom: 20px;
border-radius: 4px;
}
.message.success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.message.error {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.message.info {
background-color: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
.newsletter-preview {
margin-top: 20px;
padding: 20px;
background-color: white;
border: 1px solid #ddd;
border-radius: 4px;
}
.newsletter-preview h3 {
margin-top: 0;
color: #555;
}
.newsletter-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.stat-card {
background-color: white;
padding: 15px;
border-radius: 8px;
border: 1px solid #ddd;
text-align: center;
}
.stat-card h4 {
margin: 0 0 10px 0;
color: #666;
font-size: 14px;
}
.stat-card .number {
font-size: 24px;
font-weight: bold;
color: #333;
}
.loading {
text-align: center;
padding: 20px;
color: #666;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="nav">
<a href="/admin/">Dashboard</a>
<a href="/admin/newsletter">Subscribers</a>
<a href="/admin/settings">Settings</a>
<a href="/auth/logout">Logout</a>
</div>
<h1>Create Newsletter</h1>
<div id="message"></div>
<div class="newsletter-stats">
<div class="stat-card">
<h4>Total Subscribers</h4>
<div class="number" id="totalSubscribers">--</div>
</div>
<div class="stat-card">
<h4>Active Subscribers</h4>
<div class="number" id="activeSubscribers">--</div>
</div>
<div class="stat-card">
<h4>Last Sent</h4>
<div class="number" id="lastSent">--</div>
</div>
</div>
<form id="newsletterForm">
<div class="form-section">
<h2>Newsletter Details</h2>
<div class="form-row">
<div class="form-group">
<label for="subject">Subject Line *</label>
<input
type="text"
id="subject"
name="subject"
required
placeholder="Enter newsletter subject"
/>
</div>
<div class="form-group">
<label for="senderName">Sender Name</label>
<input
type="text"
id="senderName"
name="sender_name"
placeholder="Your Name"
/>
</div>
</div>
<div class="form-group">
<label for="content">Content *</label>
<textarea
id="content"
name="content"
required
placeholder="Write your newsletter content here..."
></textarea>
</div>
<div class="form-row">
<div class="form-group">
<label for="sendDate">Send Date (optional)</label>
<input type="datetime-local" id="sendDate" name="send_date" />
</div>
<div class="form-group">
<label for="status">Status</label>
<select id="status" name="status">
<option value="draft">Draft</option>
<option value="scheduled">Scheduled</option>
<option value="sent">Sent</option>
</select>
</div>
</div>
</div>
<div class="form-section">
<h2>Actions</h2>
<button
type="button"
class="btn btn-secondary"
onclick="previewNewsletter()"
>
Preview
</button>
<button type="button" class="btn btn-primary" onclick="saveDraft()">
Save Draft
</button>
<button
type="button"
class="btn btn-success"
onclick="sendNewsletter()"
>
Send Newsletter
</button>
<button type="button" class="btn btn-danger" onclick="clearForm()">
Clear
</button>
</div>
</form>
<div id="previewSection" class="newsletter-preview hidden">
<h3>Newsletter Preview</h3>
<div id="previewContent"></div>
</div>
<script>
let newsletterStats = {};
// Load newsletter stats on page load
document.addEventListener("DOMContentLoaded", function () {
loadNewsletterStats();
});
function loadNewsletterStats() {
// Load subscriber count
fetch("/admin/api/newsletter?page=1&per_page=1")
.then((response) => response.json())
.then((data) => {
if (data.status === "ok") {
document.getElementById("totalSubscribers").textContent =
data.pagination.total;
document.getElementById("activeSubscribers").textContent =
data.pagination.total; // For now, assume all are active
newsletterStats.totalSubscribers = data.pagination.total;
}
})
.catch((error) => {
console.error("Error loading subscriber stats:", error);
});
// For now, set last sent as N/A
document.getElementById("lastSent").textContent = "N/A";
}
function previewNewsletter() {
const subject = document.getElementById("subject").value.trim();
const content = document.getElementById("content").value.trim();
const senderName = document.getElementById("senderName").value.trim();
if (!subject || !content) {
showMessage("Subject and content are required for preview.", "error");
return;
}
const previewContent = document.getElementById("previewContent");
previewContent.innerHTML = `
<h2>${escapeHtml(subject)}</h2>
${
senderName
? `<p><strong>From:</strong> ${escapeHtml(senderName)}</p>`
: ""
}
<div style="margin-top: 20px; line-height: 1.6;">
${content.replace(/\n/g, "<br>")}
</div>
`;
document.getElementById("previewSection").classList.remove("hidden");
showMessage("Newsletter preview generated.", "info");
}
function saveDraft() {
const formData = new FormData(document.getElementById('newsletterForm'));
const newsletterData = {
subject: formData.get('subject'),
content: formData.get('content'),
sender_name: formData.get('sender_name'),
send_date: formData.get('send_date'),
status: 'draft'
};
if (!newsletterData.subject || !newsletterData.content) {
showMessage('Subject and content are required.', 'error');
return;
}
fetch('/admin/api/newsletters', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newsletterData)
})
.then(response => response.json())
.then(data => {
if (data.status === 'ok') {
showMessage('Newsletter draft saved successfully!', 'success');
} else {
showMessage(data.message || 'Failed to save draft.', 'error');
}
})
.catch(error => {
console.error('Error saving draft:', error);
showMessage('Failed to save draft.', 'error');
});
}
function sendNewsletter() {
const formData = new FormData(document.getElementById('newsletterForm'));
const newsletterData = {
subject: formData.get('subject'),
content: formData.get('content'),
sender_name: formData.get('sender_name'),
send_date: formData.get('send_date'),
status: 'sent'
};
if (!newsletterData.subject || !newsletterData.content) {
showMessage('Subject and content are required.', 'error');
return;
}
if (!confirm(`Are you sure you want to send this newsletter to ${newsletterStats.totalSubscribers || 0} subscribers?`)) {
return;
}
// First save the newsletter
fetch('/admin/api/newsletters', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newsletterData)
})
.then(response => response.json())
.then(data => {
if (data.status === 'ok') {
const newsletterId = data.newsletter_id;
// Now send it
return fetch(`/admin/api/newsletters/${newsletterId}/send`, {
method: 'POST'
});
} else {
throw new Error(data.message || 'Failed to save newsletter.');
}
})
.then(response => response.json())
.then(data => {
if (data.status === 'ok') {
showMessage(`Newsletter sent successfully to ${data.sent_count} subscribers!`, 'success');
} else {
showMessage(data.message || 'Failed to send newsletter.', 'error');
}
})
.catch(error => {
console.error('Error sending newsletter:', error);
showMessage('Failed to send newsletter.', 'error');
});
}
function clearForm() {
if (
confirm(
"Are you sure you want to clear the form? All unsaved changes will be lost."
)
) {
document.getElementById("newsletterForm").reset();
document.getElementById("previewSection").classList.add("hidden");
showMessage("Form cleared.", "info");
}
}
function showMessage(text, type) {
const messageDiv = document.getElementById("message");
messageDiv.className = `message ${type}`;
messageDiv.textContent = text;
messageDiv.style.display = "block";
setTimeout(() => {
messageDiv.style.display = "none";
}, 5000);
}
function escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
</script>
</body>
</html>