diff --git a/src/components/dashboard/EventsSection.astro b/src/components/dashboard/EventsSection.astro index ebeca42..f6ed2cf 100644 --- a/src/components/dashboard/EventsSection.astro +++ b/src/components/dashboard/EventsSection.astro @@ -1,8 +1,9 @@ --- -import { Icon } from "astro-icon/components"; +import { Icon } from "@iconify/react"; import JSZip from "jszip"; import FilePreview from "./universal/FilePreview"; import EventCheckIn from "./EventsSection/EventCheckIn"; +import EventLoad from "./EventsSection/EventLoad"; --- - -
-
-

Ongoing Events

-
- -
-
-
- - -
-
-

Upcoming Events

-
- -
-
-
- - -
-
-

Past Events

-
- -
-
-
+ @@ -106,17 +64,10 @@ import EventCheckIn from "./EventsSection/EventCheckIn"; class="btn btn-primary btn-sm gap-1" onclick="window.downloadAllFiles()" > - - - + Download All @@ -124,19 +75,7 @@ import EventCheckIn from "./EventsSection/EventCheckIn"; class="btn btn-circle btn-ghost" onclick="window.closeEventDetailsModal()" > - - - + @@ -180,10 +119,6 @@ import EventCheckIn from "./EventsSection/EventCheckIn"; diff --git a/src/components/dashboard/EventsSection/EventLoad.tsx b/src/components/dashboard/EventsSection/EventLoad.tsx new file mode 100644 index 0000000..bf148e3 --- /dev/null +++ b/src/components/dashboard/EventsSection/EventLoad.tsx @@ -0,0 +1,296 @@ +import { useEffect, useState } from "react"; +import { Icon } from "@iconify/react"; +import { Get } from "../../../scripts/pocketbase/Get"; + +interface Event { + id: string; + event_name: string; + event_code: string; + location: string; + points_to_reward: number; + attendees: AttendeeEntry[]; + start_date: string; + end_date: string; + has_food: boolean; + description: string; + files: string[]; +} + +interface AttendeeEntry { + user_id: string; + time_checked_in: string; + food: string; +} + +declare global { + interface Window { + openDetailsModal: (event: Event) => void; + downloadAllFiles: () => Promise; + currentEventId: string; + [key: string]: any; + } +} + +const EventLoad = () => { + const [events, setEvents] = useState<{ + upcoming: Event[]; + ongoing: Event[]; + past: Event[]; + }>({ + upcoming: [], + ongoing: [], + past: [], + }); + const [loading, setLoading] = useState(true); + + useEffect(() => { + loadEvents(); + }, []); + + const createSkeletonCard = () => ( +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+ ); + + const renderEventCard = (event: Event) => { + const startDate = new Date(event.start_date); + const endDate = new Date(event.end_date); + const now = new Date(); + const isPastEvent = endDate < now; + + // Store event data in window object with unique ID + const eventDataId = `event_${event.id}`; + window[eventDataId] = event; + + return ( +
+
+
+
+
+

{event.event_name}

+
+
{event.points_to_reward} pts
+
+
+
+
+ {startDate.toLocaleDateString("en-US", { + weekday: "short", + month: "short", + day: "numeric", + })} +
+
+ {startDate.toLocaleTimeString("en-US", { + hour: "numeric", + minute: "2-digit", + })} +
+
+
+ +
+ {event.description || "No description available"} +
+ +
+
+ + {event.location} +
+ {isPastEvent && event.files && event.files.length > 0 && ( + + )} +
+
+
+
+ ); + }; + + const loadEvents = async () => { + try { + const get = Get.getInstance(); + const allEvents = await get.getAll( + "events", + "published = true", + "-start_date" + ); + + // Split events into upcoming, ongoing, and past based on start and end dates + const now = new Date(); + const { upcoming, ongoing, past } = allEvents.reduce( + (acc, event) => { + // Convert UTC dates to local time + const startDate = new Date(event.start_date); + const endDate = new Date(event.end_date); + + // Set both dates and now to midnight for date-only comparison + const startLocal = new Date( + startDate.getFullYear(), + startDate.getMonth(), + startDate.getDate(), + startDate.getHours(), + startDate.getMinutes() + ); + const endLocal = new Date( + endDate.getFullYear(), + endDate.getMonth(), + endDate.getDate(), + endDate.getHours(), + endDate.getMinutes() + ); + const nowLocal = new Date( + now.getFullYear(), + now.getMonth(), + now.getDate(), + now.getHours(), + now.getMinutes() + ); + + if (startLocal > nowLocal) { + acc.upcoming.push(event); + } else if (endLocal < nowLocal) { + acc.past.push(event); + } else { + acc.ongoing.push(event); + } + return acc; + }, + { + upcoming: [] as Event[], + ongoing: [] as Event[], + past: [] as Event[], + } + ); + + // Sort events + upcoming.sort((a, b) => new Date(a.start_date).getTime() - new Date(b.start_date).getTime()); + ongoing.sort((a, b) => new Date(a.end_date).getTime() - new Date(b.end_date).getTime()); + past.sort((a, b) => new Date(b.end_date).getTime() - new Date(a.end_date).getTime()); + + setEvents({ upcoming, ongoing, past }); + setLoading(false); + } catch (error) { + console.error("Failed to load events:", error); + setLoading(false); + } + }; + + if (loading) { + return ( + <> + {/* Ongoing Events */} +
+
+

Ongoing Events

+
+ {[...Array(3)].map((_, i) => ( +
{createSkeletonCard()}
+ ))} +
+
+
+ + {/* Upcoming Events */} +
+
+

Upcoming Events

+
+ {[...Array(3)].map((_, i) => ( +
{createSkeletonCard()}
+ ))} +
+
+
+ + {/* Past Events */} +
+
+

Past Events

+
+ {[...Array(3)].map((_, i) => ( +
{createSkeletonCard()}
+ ))} +
+
+
+ + ); + } + + return ( + <> + {/* Ongoing Events */} + {events.ongoing.length > 0 && ( +
+
+

Ongoing Events

+
+ {events.ongoing.map(renderEventCard)} +
+
+
+ )} + + {/* Upcoming Events */} + {events.upcoming.length > 0 && ( +
+
+

Upcoming Events

+
+ {events.upcoming.map(renderEventCard)} +
+
+
+ )} + + {/* Past Events */} + {events.past.length > 0 && ( +
+
+

Past Events

+
+ {events.past.map(renderEventCard)} +
+
+
+ )} + + ); +}; + +export default EventLoad;