This commit is contained in:
2025-09-27 17:07:58 +01:00
commit bfdcee8602
2663 changed files with 517832 additions and 0 deletions

142
static/js/supporters.js Normal file
View File

@@ -0,0 +1,142 @@
// Supporter Wall Functionality
class SupporterWall {
constructor() {
this.supportersList = document.getElementById('supporters-list');
this.supporterWall = document.getElementById('supporter-wall');
this.supporters = [];
if (this.supportersList) {
this.init();
}
}
init() {
this.loadSupporters();
// Refresh supporters every 30 seconds
setInterval(() => this.loadSupporters(), 30000);
}
async loadSupporters() {
try {
const response = await fetch('/supporters');
const data = await response.json();
if (data.supporters && data.supporters.length > 0) {
this.updateSupportersList(data.supporters);
} else {
this.showEmptyState();
}
} catch (error) {
console.error('Error loading supporters:', error);
this.showEmptyState();
}
}
updateSupportersList(newSupporters) {
// Clear loading message
this.supportersList.innerHTML = '';
// Check for new supporters since last update
const newSupporterIds = newSupporters.map(s => s.timestamp);
const currentSupporterIds = this.supporters.map(s => s.timestamp);
const hasNewSupporters = newSupporterIds.some(id => !currentSupporterIds.includes(id));
this.supporters = newSupporters;
// Create supporter elements
newSupporters.forEach((supporter, index) => {
const supporterElement = this.createSupporterElement(supporter);
// Add 'new' class to recent supporters
if (hasNewSupporters && index === 0 && supporter.time_ago === 'just now') {
supporterElement.classList.add('new');
setTimeout(() => supporterElement.classList.remove('new'), 2000);
}
this.supportersList.appendChild(supporterElement);
});
}
createSupporterElement(supporter) {
const element = document.createElement('div');
element.className = 'supporter-item';
const currencySymbols = {
'GBP': '£',
'EUR': '€',
'USD': '$'
};
const symbol = currencySymbols[supporter.currency] || supporter.currency;
const amount = (supporter.amount / 100).toFixed(2);
element.innerHTML = `
<span class="name">${this.escapeHtml(supporter.name)}</span>
<span class="time">${supporter.time_ago}</span>
<div style="clear: both; margin-top: 2px; font-size: 11px; color: var(--text-secondary);">
${symbol}${amount}
</div>
`;
return element;
}
showEmptyState() {
this.supportersList.innerHTML = `
<div class="supporter-item" style="text-align: center; color: var(--text-secondary);">
Be the first to support! 💜
</div>
`;
}
async addSupporter(name, amount, currency) {
if (!name || name.trim() === '') return;
try {
const response = await fetch('/add-supporter', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: name.trim(),
amount: amount,
currency: currency
})
});
const result = await response.json();
if (result.success) {
// Reload supporters to show the new one
setTimeout(() => this.loadSupporters(), 1000);
return true;
}
} catch (error) {
console.error('Error adding supporter:', error);
}
return false;
}
escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
// Method to hide/show supporter wall
toggle() {
if (this.supporterWall) {
this.supporterWall.style.display =
this.supporterWall.style.display === 'none' ? 'block' : 'none';
}
}
}
// Initialize supporter wall when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
window.supporterWall = new SupporterWall();
});