f73ea41a6c
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013gwc3aCiyQxmCWQke8RvEz
64 lines
2.1 KiB
JavaScript
64 lines
2.1 KiB
JavaScript
function escapeHtml(str) {
|
|
return String(str).replace(/[&<>"']/g, (c) => ({
|
|
'&': '&', '<': '<', '>': '>', '"': '"', "'": ''',
|
|
}[c]));
|
|
}
|
|
|
|
function formatPrice(price) {
|
|
return price == null ? '—' : `€${Number(price).toFixed(2).replace('.', ',')}`;
|
|
}
|
|
|
|
function renderProductRow(product) {
|
|
return `
|
|
<tr>
|
|
<td>${escapeHtml(product.name)}</td>
|
|
<td><a href="${escapeHtml(product.url)}" target="_blank" rel="noopener">bekijken</a></td>
|
|
<td>${formatPrice(product.last_price)}</td>
|
|
<td>${product.last_checked_at ? escapeHtml(product.last_checked_at) : '—'}</td>
|
|
<td>${escapeHtml(product.last_check_status || '—')}</td>
|
|
<td>
|
|
<form method="post" action="/products/${product.id}/delete" onsubmit="return confirm('Product verwijderen?');">
|
|
<button type="submit">Verwijder</button>
|
|
</form>
|
|
</td>
|
|
</tr>`;
|
|
}
|
|
|
|
function renderIndex({ products, message }) {
|
|
return `<!doctype html>
|
|
<html lang="nl">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Korting — prijstracker</title>
|
|
<style>
|
|
body { font-family: system-ui, sans-serif; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
|
|
table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
|
|
th, td { text-align: left; padding: 0.5rem; border-bottom: 1px solid #ddd; }
|
|
.message { background: #eef; padding: 0.5rem 1rem; border-radius: 4px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Korting — prijstracker</h1>
|
|
${message ? `<p class="message">${escapeHtml(message)}</p>` : ''}
|
|
<form method="post" action="/products">
|
|
<input name="name" placeholder="Naam" required>
|
|
<input name="url" type="url" placeholder="https://..." required>
|
|
<button type="submit">Toevoegen</button>
|
|
</form>
|
|
<form method="post" action="/check-now">
|
|
<button type="submit">Nu controleren</button>
|
|
</form>
|
|
<table>
|
|
<thead>
|
|
<tr><th>Naam</th><th>URL</th><th>Prijs</th><th>Laatst gecontroleerd</th><th>Status</th><th></th></tr>
|
|
</thead>
|
|
<tbody>
|
|
${products.map(renderProductRow).join('')}
|
|
</tbody>
|
|
</table>
|
|
</body>
|
|
</html>`;
|
|
}
|
|
|
|
module.exports = { renderIndex, escapeHtml, formatPrice };
|