Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

805-frontend-display-all-events-to-admin #814

Merged
merged 11 commits into from
Oct 31, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { Meta, StoryObj } from "@storybook/react"
import AdminAllEvents from "./AdminAllEvents"
import { Timestamp } from "firebase/firestore"

const meta: Meta<typeof AdminAllEvents> = {
component: AdminAllEvents
}

export default meta
type Story = StoryObj<typeof meta>

const earlierStartDate = Timestamp.fromDate(new Date(2023, 1, 1))
const startDate = Timestamp.fromDate(new Date(2024, 1, 1))

export const DefaultEventsPage: Story = {
args: {
rawEvents: [
{
id: "1",
title: "UASC New event 1",
location: "UASC",
physical_start_date: earlierStartDate,
sign_up_start_date: earlierStartDate,
sign_up_end_date: earlierStartDate,
google_forms_link: "https://google.com",
description:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Reprehenderit adipisci repellat perferendis. Quia ipsum laborum est, veniam accusamus voluptas praesentium, odio perspiciatis blanditiis sequi dignissimos unde. Natus delectus nihil cum."
},
{
id: "2",
title: "UASC New event 2",
location: "UASC",
physical_start_date: earlierStartDate,
sign_up_start_date: startDate,
sign_up_end_date: earlierStartDate,
description:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Reprehenderit adipisci repellat perferendis. Quia ipsum laborum est, veniam accusamus voluptas praesentium, odio perspiciatis blanditiis sequi dignissimos unde. Natus delectus nihil cum."
},
{
id: "3",
title: "UASC New Event 3",
location: "UASC",
physical_start_date: earlierStartDate,
sign_up_start_date: startDate,
sign_up_end_date: earlierStartDate,
description:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Reprehenderit adipisci repellat perferendis. Quia ipsum laborum est, veniam accusamus voluptas praesentium, odio perspiciatis blanditiis sequi dignissimos unde. Natus delectus nihil cum."
}
]
},
tags: ["autodocs"]
}

export const EmptyEventsPage: Story = {
args: {
rawEvents: []
},
tags: ["autodocs"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import EventsCardPreview, {
IEventsCardPreview
} from "@/components/generic/Event/EventPreview/EventPreview"
import { DateUtils } from "@/components/utils/DateUtils"
import { Event } from "@/models/Events"
import { useCallback, useMemo, useState } from "react"
import {
EventDateComparisons,
EventRenderingUtils
} from "@/components/generic/Event/EventUtils"
import Button from "@/components/generic/FigmaButtons/FigmaButton"
import Loader from "@/components/generic/SuspenseComponent/Loader"

/**
* Interface representing the properties of the Events Page.
*/
interface IAdminAllEvents {
/**
* A list of _all_ {@link Event}s which should either be mocked
* or fetched from the backend. **NO** pre-processing should be
* performed on this list as it will be further mutated in the
* {@link EventsPage} component.
*/
rawEvents?: Event[]

/**
* Indicates whether the events are currently being loaded.
*/
isLoading?: boolean

/**
* Indicates whether there are more events to be fetched.
*/
hasMoreEvents?: boolean

/**
* Function to fetch more events.
*/
fetchMoreEvents?: () => void

/**
* The ID of the preselected event.
*/
preselectedEventId?: string

/**
* Callback function to handle changes to the selected event ID.
* @param id - The new selected event ID.
*/
onSelectedEventIdChange?: (id?: string) => void
}

/**
* Helper type to split the raw events into upcoming and past ones,
* this is important as they need to be sorted differently
*/
interface EventList {
upcomingAndCurrentEvents: Event[]
pastEvents: Event[]
}
choden-dev marked this conversation as resolved.
Show resolved Hide resolved

/**
* Used to handle all _presentation_ logic conerning the evnts
*
* - **Do not make any network requests in this component, the data should
* be fetched seperately and passed in as {@link rawEvents}**
* - String operations are ideally done in {@link EventMessages}
* - Complex date comparisons should also be abstracted away into {@link EventDateComparisons}
*/
const AdminAllEvents = ({
rawEvents = [],
hasMoreEvents,
isLoading,
fetchMoreEvents,
preselectedEventId,
onSelectedEventIdChange
}: IAdminAllEvents) => {
const [selectedEventId, setSelectedEventId] = useState<string | undefined>(
preselectedEventId
)

const eventSelectionHandler = useCallback(
(id?: string) => {
setSelectedEventId(id)
onSelectedEventIdChange?.(id)
},
[setSelectedEventId, onSelectedEventIdChange]
)

/**
* Partitions of the array that allow us to individually process the ongoing events
*/
const eventList = useMemo(() => {
return rawEvents.reduce(
(buf: EventList, event) => {
const { physical_start_date, physical_end_date } = event
if (
EventDateComparisons.isPastEvent(
new Date(DateUtils.timestampMilliseconds(physical_start_date)),
physical_end_date &&
new Date(DateUtils.timestampMilliseconds(physical_end_date))
)
) {
buf.pastEvents.push(event)
} else {
buf.upcomingAndCurrentEvents.push(event)
}

/**
* Start dates ascending for upcoming and current events
*/
buf.upcomingAndCurrentEvents.sort(
(
{ physical_start_date: startDate1 },
{ physical_start_date: startDate2 }
) =>
DateUtils.timestampMilliseconds(startDate1) -
DateUtils.timestampMilliseconds(startDate2)
)

return buf
},
{ upcomingAndCurrentEvents: [], pastEvents: [] }
)
}, [rawEvents])

/**
* Detailed view of the event
*/
const previewCurrentEvents: IEventsCardPreview[] =
eventList.upcomingAndCurrentEvents?.map((event) => {
return EventRenderingUtils.previewTransformer(
event,
eventSelectionHandler,
"edit event",
"admin"
)
}) || []

const previewPastEvents: IEventsCardPreview[] =
eventList.pastEvents?.map((event) => {
return EventRenderingUtils.previewTransformer(
event,
eventSelectionHandler,
"edit event",
"admin"
)
}) || []

return (
<>
<div className={`flex w-full max-w-[1000px] flex-col gap-2`}>
{selectedEventId ? null : (
<>
{isLoading ? (
<Loader />
) : (
<h5 className="text-dark-blue-100 font-bold uppercase">
{rawEvents.length > 0 ? (
<>Upcoming Events</>
) : (
<>No events found!</>
)}
</h5>
)}
{previewCurrentEvents.map((event) => (
<EventsCardPreview key={event.title} {...event} />
))}

{previewPastEvents.map((event) => (
<EventsCardPreview key={event.title} {...event} />
))}
</>
)}

{hasMoreEvents && !selectedEventId && (
<Button
variant="default"
onClick={fetchMoreEvents}
disabled={isLoading}
>
Load More
</Button>
)}
</div>
</>
)
}

export default AdminAllEvents
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Meta, StoryObj } from "@storybook/react"

import AdminEventView from "./AdminEventView"
import { Timestamp } from "firebase/firestore"

const meta: Meta<typeof AdminEventView> = {
component: AdminEventView
Expand All @@ -9,11 +10,57 @@ const meta: Meta<typeof AdminEventView> = {
export default meta
type Story = StoryObj<typeof meta>

const earlierStartDate = Timestamp.fromDate(new Date(2023, 1, 1))
const startDate = Timestamp.fromDate(new Date(2024, 1, 1))

export const DefaultAdminEventView: Story = {
args: {
handlePostEvent: () => {},
generateImageLink: async () => {
return undefined
}
},
rawEvents: []
}
}

export const AdminEventViewWithEvents: Story = {
args: {
handlePostEvent: () => {},
generateImageLink: async () => {
return undefined
},
rawEvents: [
{
id: "1",
title: "UASC New event 1",
location: "UASC",
physical_start_date: earlierStartDate,
sign_up_start_date: earlierStartDate,
sign_up_end_date: earlierStartDate,
google_forms_link: "https://google.com",
description:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Reprehenderit adipisci repellat perferendis. Quia ipsum laborum est, veniam accusamus voluptas praesentium, odio perspiciatis blanditiis sequi dignissimos unde. Natus delectus nihil cum."
},
{
id: "2",
title: "UASC New event 2",
location: "UASC",
physical_start_date: earlierStartDate,
sign_up_start_date: startDate,
sign_up_end_date: earlierStartDate,
description:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Reprehenderit adipisci repellat perferendis. Quia ipsum laborum est, veniam accusamus voluptas praesentium, odio perspiciatis blanditiis sequi dignissimos unde. Natus delectus nihil cum."
},
{
id: "3",
title: "UASC New Event 3",
location: "UASC",
physical_start_date: earlierStartDate,
sign_up_start_date: startDate,
sign_up_end_date: earlierStartDate,
description:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Reprehenderit adipisci repellat perferendis. Quia ipsum laborum est, veniam accusamus voluptas praesentium, odio perspiciatis blanditiis sequi dignissimos unde. Natus delectus nihil cum."
}
]
}
}
Loading
Loading