diff --git a/app/components/WeekCalendar.vue b/app/components/WeekCalendar.vue new file mode 100644 index 0000000..a70024c --- /dev/null +++ b/app/components/WeekCalendar.vue @@ -0,0 +1,150 @@ + + + \ No newline at end of file diff --git a/app/components/event/UpcomingEventCard.vue b/app/components/event/UpcomingEventCard.vue new file mode 100644 index 0000000..8d4978c --- /dev/null +++ b/app/components/event/UpcomingEventCard.vue @@ -0,0 +1,66 @@ + + \ No newline at end of file diff --git a/app/pages/events/index.vue b/app/pages/events/index.vue index 0b946e0..ef362ff 100644 --- a/app/pages/events/index.vue +++ b/app/pages/events/index.vue @@ -1,177 +1,308 @@ + \ No newline at end of file diff --git a/server/api/events/by-day.get.ts b/server/api/events/by-day.get.ts new file mode 100644 index 0000000..c73a366 --- /dev/null +++ b/server/api/events/by-day.get.ts @@ -0,0 +1,54 @@ +export default defineEventHandler(async (event) => { + const query = getQuery(event) + const dateParam = typeof query.date === 'string' ? query.date : undefined + + // Expects YYYY-MM-DD. Falls back to today (server local time) if missing + // or malformed, so the endpoint never 500s on a bad/absent query param. + const isValidDateString = dateParam ? /^\d{4}-\d{2}-\d{2}$/.test(dateParam) : false + + let dayStart: Date + if (isValidDateString) { + dayStart = new Date(`${dateParam}T00:00:00`) + } else { + const now = new Date() + dayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + } + + if (Number.isNaN(dayStart.getTime())) { + throw createError({ statusCode: 400, statusMessage: 'Invalid date' }) + } + + const dayEnd = new Date(dayStart) + dayEnd.setDate(dayEnd.getDate() + 1) + + const events = await prisma.event.findMany({ + where: { + // Overlaps the day rather than strictly starting in it, so a + // multi-day event still shows up on every day it spans. + startTime: { lt: dayEnd }, + endTime: { gte: dayStart }, + allowAttendees: true, + isTraining: false, + }, + orderBy: { startTime: 'asc' }, + include: { + location: true, + eventAssets: true, + }, + }) + + return events.map((e) => { + const asset = e.eventAssets[0] + const image = asset + ? `/api/events/${e.id}/images/${asset.imageUrl.split('/').pop()}` + : '/images/default-event.jpg' + return { + id: e.id, + title: e.title, + url: `/events/${e.id}`, + image, + startTime: e.startTime, + location: e.location.address, + } + }) +}) \ No newline at end of file diff --git a/server/api/events/today.get.ts b/server/api/events/today.get.ts new file mode 100644 index 0000000..59262fb --- /dev/null +++ b/server/api/events/today.get.ts @@ -0,0 +1,43 @@ +export default defineEventHandler(async (event) => { + const query = getQuery(event) + const limit = Number(query.limit) || 20 + const now = new Date() + + const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0) + const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999) + + const events = await prisma.event.findMany({ + where: { + startTime: { gte: startOfDay, lte: endOfDay }, + allowAttendees: true, + isTraining: false, + }, + orderBy: { startTime: 'asc' }, + take: limit, + include: { + location: true, + eventAssets: true, + participants: true, + guestRSVPs: true, + }, + }) + + return events.map((e) => { + const start = new Date(e.startTime) + const asset = e.eventAssets[0] + const image = asset + ? `/api/events/${e.id}/images/${asset.imageUrl.split('/').pop()}` + : '/images/default-event.jpg' + return { + id: e.id, + title: e.title, + url: `/events/${e.id}`, + image, + day: start.getDate().toString().padStart(2, '0'), + month: start.toLocaleString('en-US', { month: 'short' }), + location: e.location.address, + going: e.participants.length + e.guestRSVPs.length, + startTime: e.startTime, + } + }) +}) \ No newline at end of file diff --git a/server/api/events/week.get.ts b/server/api/events/week.get.ts new file mode 100644 index 0000000..3f487dc --- /dev/null +++ b/server/api/events/week.get.ts @@ -0,0 +1,49 @@ +export default defineEventHandler(async (event) => { + const query = getQuery(event) + const limit = Number(query.limit) || 20 + const now = new Date() + + // Start of this week (Sunday, local time) + const startOfWeek = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0) + startOfWeek.setDate(startOfWeek.getDate() - startOfWeek.getDay()) + + // End of this week (Saturday, local time, end of day) + const endOfWeek = new Date(startOfWeek) + endOfWeek.setDate(endOfWeek.getDate() + 6) + endOfWeek.setHours(23, 59, 59, 999) + + const events = await prisma.event.findMany({ + where: { + startTime: { gte: startOfWeek, lte: endOfWeek }, + allowAttendees: true, + isTraining: false, + }, + orderBy: { startTime: 'asc' }, + take: limit, + include: { + location: true, + eventAssets: true, + participants: true, + guestRSVPs: true, + }, + }) + + return events.map((e) => { + const start = new Date(e.startTime) + const asset = e.eventAssets[0] + const image = asset + ? `/api/events/${e.id}/images/${asset.imageUrl.split('/').pop()}` + : '/images/default-event.jpg' + return { + id: e.id, + title: e.title, + url: `/events/${e.id}`, + image, + day: start.getDate().toString().padStart(2, '0'), + month: start.toLocaleString('en-US', { month: 'short' }), + location: e.location.address, + going: e.participants.length + e.guestRSVPs.length, + startTime: e.startTime, + } + }) +}) \ No newline at end of file diff --git a/~/Documents/abide-images/eba30399-870f-4185-9b9d-1aabb5d2a867/IMG_6401.jpg b/~/Documents/abide-images/eba30399-870f-4185-9b9d-1aabb5d2a867/IMG_6401.jpg new file mode 100644 index 0000000..b38c4c1 Binary files /dev/null and b/~/Documents/abide-images/eba30399-870f-4185-9b9d-1aabb5d2a867/IMG_6401.jpg differ