source: Klonkt/src/views/pages/shows.ejs@ 36afccd

main
Last change on this file since 36afccd was 8d32dcf, checked in by roboburr <roboburr@โ€ฆ>, 3 months ago

Show agenda + notify-me (premium feature #8) โ€” last of the 8

  • DB: shows (site_id, date, time, city, venue, country, ticket_url, notes).
  • routes/shows.js (public, premium-gated): GET /shows (upcoming shows + notify form), POST /shows/notify (subscribers source 'notify', double opt-in if SMTP; confirm/unsub via the generic /nieuwsbrief links).
  • routes/admin-shows.js (site admin + premium): GET /admin/shows (list + add form + subscriber count), POST / (add; optional notify email to 'notify' subscribers if SMTP is available), POST /:id/delete.
  • SubscriberService.confirmedFor(siteId, source?) โ€” optional source filter ('notify').
  • views: pages/shows.ejs + pages/admin-shows.ejs. Dashboard ๐Ÿ“… Agenda link.

Notify email requires SMTP (like #1/#2 sending); without SMTP the show is saved
and sign-ups still work. node --check passed.

Co-Authored-By: Claude <noreply@โ€ฆ>

  • Property mode set to 100644
File size: 3.8 KB
Lineย 
1<%
2 var ss = (typeof shows !== 'undefined') ? shows : [];
3 var st = (typeof notifyState !== 'undefined') ? notifyState : null;
4%>
5<section class="sh">
6 <h1 class="sh-h1">Agenda</h1>
7
8 <% if (st === 'done') { %><div class="sh-msg">โœ“ Je staat op de lijst โ€” je hoort het zodra er een show wordt aangekondigd.</div>
9 <% } else if (st === 'check') { %><div class="sh-msg">โœ‰ Check je mail om je aanmelding te bevestigen.</div>
10 <% } else if (st === 'error') { %><div class="sh-msg sh-bad"><%= (typeof notifyMsg!=='undefined')?notifyMsg:'Er ging iets mis.' %></div><% } %>
11
12 <% if (!ss.length) { %>
13 <p class="sh-empty">Geen aangekondigde shows op dit moment.</p>
14 <% } else { %>
15 <ul class="sh-list">
16 <% ss.forEach(function(s){ %>
17 <li class="sh-item">
18 <span class="sh-date">
19 <span class="sh-day"><%= (s.date||'').slice(8) %></span>
20 <span class="sh-mon"><%= (s.date||'').slice(5,7) %>/<%= (s.date||'').slice(0,4) %></span>
21 </span>
22 <span class="sh-meta">
23 <span class="sh-city"><%= s.city %><% if (s.country) { %>, <%= s.country %><% } %></span>
24 <% if (s.venue) { %><span class="sh-venue"><%= s.venue %><% if (s.time) { %> ยท <%= s.time %><% } %></span><% } else if (s.time) { %><span class="sh-venue"><%= s.time %></span><% } %>
25 <% if (s.notes) { %><span class="sh-notes"><%= s.notes %></span><% } %>
26 </span>
27 <% if (s.ticket_url) { %><a class="sh-tix" href="<%= s.ticket_url %>" target="_blank" rel="noopener">Tickets</a><% } %>
28 </li>
29 <% }); %>
30 </ul>
31 <% } %>
32
33 <div class="sh-notify">
34 <h2 class="sh-h2">Mis geen show</h2>
35 <p class="sh-sub">Laat je e-mail achter en je krijgt een seintje bij een nieuwe show. Uitschrijven kan altijd.</p>
36 <form method="POST" action="<%= siteUrlBase %>/shows/notify" class="sh-form">
37 <input type="email" name="email" required placeholder="jouw@email.nl" autocomplete="email">
38 <button type="submit" class="sh-btn">Houd me op de hoogte</button>
39 </form>
40 </div>
41</section>
42
43<style>
44 .sh { max-width: 640px; margin: 0 auto; padding: 32px 18px 64px; }
45 .sh-h1 { font-size: clamp(26px,5vw,38px); margin: 0 0 18px; }
46 .sh-msg { padding: 11px 14px; border-radius: 10px; background: rgba(60,160,90,.15); margin-bottom: 16px; }
47 .sh-bad { background: rgba(200,60,60,.15); }
48 .sh-list { list-style: none; margin: 0 0 36px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
49 .sh-item { display: flex; align-items: center; gap: 16px; padding: 12px 14px; border: 1px solid rgba(128,128,128,.2); border-radius: 12px; }
50 .sh-date { flex: 0 0 auto; text-align: center; min-width: 54px; }
51 .sh-day { display: block; font-size: 22px; font-weight: 700; line-height: 1; }
52 .sh-mon { font-size: 11px; opacity: .6; }
53 .sh-meta { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
54 .sh-city { font-weight: 600; }
55 .sh-venue { font-size: 13px; opacity: .7; }
56 .sh-notes { font-size: 12.5px; opacity: .6; margin-top: 2px; }
57 .sh-tix { flex: 0 0 auto; padding: 8px 14px; border-radius: 999px; background: var(--accent,#6b8f71); color: #fff; text-decoration: none; font-weight: 600; font-size: 13px; }
58 .sh-empty { opacity: .7; margin-bottom: 36px; }
59 .sh-notify { border-top: 1px solid rgba(128,128,128,.2); padding-top: 24px; }
60 .sh-h2 { margin: 0 0 6px; font-size: 18px; }
61 .sh-sub { opacity: .8; margin: 0 0 14px; }
62 .sh-form { display: flex; gap: 10px; flex-wrap: wrap; }
63 .sh-form input { flex: 1 1 200px; padding: 12px 14px; border-radius: 10px; border: 1px solid rgba(128,128,128,.4); background: transparent; color: inherit; font-size: 15px; }
64 .sh-btn { padding: 12px 18px; border-radius: 10px; border: none; background: var(--accent,#6b8f71); color: #fff; font-weight: 600; cursor: pointer; }
65</style>
Note: See TracBrowser for help on using the repository browser.