Six site improvements picked from a "what could be better" review, plus a Jest test suite covering the two areas with the trickiest money-handling history in this project (early-bird pricing tranches, donation-leg accounting): - "Add to calendar" .ics download on event pages and in confirmation emails - sitemap.xml, robots.txt, and Open Graph/Twitter metadata for public pages - Sentry error monitoring (backend + frontend), a no-op until SENTRY_DSN is set - Nightly local pg_dump backups with a Site Settings tab to browse/trigger/download - Admin audit trail for refunds, donations, manual registrations, event and settings changes, and staff-initiated cancellations - Jest tests reproducing and guarding against the 1.8.0 tranche-pricing bug and the 1.4.2 donation-balance-inflation bug Wallet passes (Google/Apple) were scoped out of this round — Apple Wallet needs a paid Apple Developer account the project doesn't have yet, and the user preferred shipping both together later rather than Google alone now. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
37 lines
1.3 KiB
JavaScript
37 lines
1.3 KiB
JavaScript
const { createEvent } = require('ics');
|
|
|
|
// Event.startDate/endDate are stored as true UTC instants (the admin event form's
|
|
// datetime-local input is parsed in the browser's local time before being sent as an
|
|
// ISO string), so serializing them as UTC here requires no timezone math and lets every
|
|
// viewer's calendar app localize correctly to *their own* timezone.
|
|
function toUtcArray(date) {
|
|
const d = new Date(date);
|
|
return [d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes()];
|
|
}
|
|
|
|
/**
|
|
* Build an RFC 5545 .ics file (as a string) for a single event.
|
|
*
|
|
* @param {object} event - Prisma Event row: title, description?, startDate, endDate, location?
|
|
* @param {string} eventUrl - absolute URL to the event's public page
|
|
* @returns {string}
|
|
*/
|
|
function buildEventIcs(event, eventUrl) {
|
|
const { error, value } = createEvent({
|
|
title: event.title,
|
|
start: toUtcArray(event.startDate),
|
|
end: toUtcArray(event.endDate),
|
|
startInputType: 'utc',
|
|
endInputType: 'utc',
|
|
startOutputType: 'utc',
|
|
endOutputType: 'utc',
|
|
location: event.location || undefined,
|
|
description: event.description || undefined,
|
|
url: eventUrl,
|
|
});
|
|
if (error) throw error;
|
|
return value;
|
|
}
|
|
|
|
module.exports = { buildEventIcs };
|