From 228d75db7258ed4d1d7a40df2225ecbf1be4ad18 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Wed, 5 Mar 2025 22:15:46 +0100 Subject: [PATCH] Generate a demo schedule if no schedule exists --- server/database.ts | 11 ++- server/generate-demo-schedule.ts | 140 +++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 server/generate-demo-schedule.ts diff --git a/server/database.ts b/server/database.ts index f730cdd..3133c9c 100644 --- a/server/database.ts +++ b/server/database.ts @@ -1,5 +1,6 @@ import { readFile, writeFile } from "node:fs/promises"; import { Schedule } from "~/shared/types/schedule"; +import { generateDemoSchedule } from "./generate-demo-schedule"; // For this demo I'm just storing the runtime data in JSON files. When making // this into proper application this should be replaced with an actual database. @@ -14,10 +15,12 @@ export async function readSchedule() { } catch (err: any) { if (err.code !== "ENOENT") throw err; - // Use an empty schedule if nothing is stored yet. - schedule = { - locations: [], - events: [], + // Use the demo schedule if nothing is stored yet. + try { + schedule = generateDemoSchedule(); + } catch (err) { + console.error(err); + throw err; } } return schedule;; diff --git a/server/generate-demo-schedule.ts b/server/generate-demo-schedule.ts new file mode 100644 index 0000000..b7f42db --- /dev/null +++ b/server/generate-demo-schedule.ts @@ -0,0 +1,140 @@ +import { Schedule, TimeSlot } from "~/shared/types/schedule"; + +const locations = [ + { + name: "Stage", + description: "Inside the main building." + }, + { + name: "Clubhouse", + description: "That big red building in the middle of the park." + }, + { + name: "Summerhouse", + description: "Next to the campfire by the lake" + }, + { + name: "Campfire", + description: "Next to the big tree by the lake." + }, + { + name: "Outside", + description: "Takes place somewhere outside." + } +] + +const events = [ + { + name: "Arcade", + description: "Play retro games!", + slots: [ + "d1 12:00 4h clubhouse", + "d2 12:00 4h clubhouse", + "d3 12:00 4h clubhouse", + ] + }, + { + name: "Bonfire Stories", + description: "Share your stories as we sit cosily around the campfire.", + slots: ["d2 18:00 2h campfire"] + }, + { name: "DJ Alpha", slots: ["d2 20:00 2h stage"] }, + { name: "DJ Bravo", slots: ["d3 20:00 2h stage"] }, + { name: "DJ Charlie", slots: ["d3 22:00 2h stage"] }, + { + name: "Fursuit Games", + description: "Playful time for the suiters.", + slots: ["d4 18:00 2h clubhouse"], + }, + { name: "Fishing Trip", slots: ["d3 12:00 3h30m outside"]}, + { name: "Opening", slots: ["d1 18:30 1h30m stage"]}, + { name: "Closing", slots: ["d5 16:00 1h stage"]}, + { + name: "Board Games", + slots: [ + "d1 12:00 4h summerhouse", + "d2 12:00 4h summerhouse", + "d3 12:00 4h summerhouse", + "d4 12:00 4h summerhouse", + ] + }, + { name: "📷meet", slots: ["d3 19:00 1h10m summerhouse"]}, + { + name: "Karaoke", + slots: [ + "d3 21:00 2h clubhouse", + "d4 21:00 2h clubhouse", + ], + }, + { name: "Dance", slots: ["d1 20:00 3h stage"]}, + { name: "Charity Auction", slots: ["d4 13:00 2h stage"]}, + { name: "Tournament", slots: ["d2 17:00 2h stage"]}, + { name: "Canoe Trip", slots: ["d4 11:00 4h30m outside"]}, + { + name: "Dinner", + slots: [ + "d1 16:00 1h campfire", + "d2 16:00 1h campfire", + "d3 16:00 1h campfire", + "d4 16:00 1h campfire", + ], + }, + { name: "Film Night", slots: ["d4 21:00 2h stage"]}, + { name: "Photo", slots: ["d3 18:00 45m stage"]}, + { name: "Artist Alley", slots: ["d4 12:00 4h clubhouse"]}, + { name: "Feedback Panel", slots: ["d5 18:00 4h clubhouse"]}, +]; + +function toId(name: string) { + return name.toLowerCase().replace(/ /g, "-"); +} + +function toIso(date: Date) { + return date.toISOString().replace(":00:000Z", "Z"); +} + +function toSlot(origin: Date, id: string, shorthand: string, index: number): TimeSlot { + const [day, start, duration, location] = shorthand.split(" "); + const [startHours, startMinutes] = start.split(":").map(time => parseInt(time, 10)); + const dayNumber = parseInt(day.slice(1)); + + const startDate = new Date(origin); + startDate.setUTCDate(startDate.getUTCDate() + dayNumber); + startDate.setUTCHours(startDate.getUTCHours() + startHours); + startDate.setUTCMinutes(startDate.getUTCMinutes() + startMinutes); + + const [_, durationHours, durationMinutes] = /(?:(\d+)h)?(?:(\d+)m)?/.exec(duration)!; + const durationTotal = parseInt(durationHours ?? "0") * 60 + parseInt(durationMinutes ?? "0") + const endDate = new Date(startDate.getTime() + durationTotal * 60e3); + + return { + id: `${id}-${index}`, + start: toIso(startDate), + end: toIso(endDate), + locations: [location], + } +} + +export function generateDemoSchedule(): Schedule { + const origin = new Date(); + const utcOffset = 1; + origin.setUTCDate(origin.getUTCDate() - origin.getUTCDay() - 1); // Go to Monday + origin.setUTCHours(utcOffset); + origin.setUTCMinutes(0); + origin.setUTCSeconds(0); + origin.setMilliseconds(0); + + return { + events: events.map( + ({ name, description, slots }) => ({ + id: toId(name), + name, + description, + slots: slots.map((shorthand, index) => toSlot(origin, toId(name), shorthand, index)) + }) + ), + locations: locations.map( + ({ name, description }) => ({ id: toId(name), name, description }) + ), + } +}