From 511917851f70fbc51ee92e7a34fdce62da7c54a1 Mon Sep 17 00:00:00 2001 From: Sean Date: Sun, 29 Sep 2024 07:51:20 -0700 Subject: [PATCH] un-component EventList so the diff is cleaner --- src/components/events/EventList/index.tsx | 149 ---------------------- src/components/events/index.tsx | 1 - src/pages/events.tsx | 135 +++++++++++++++++++- 3 files changed, 129 insertions(+), 156 deletions(-) delete mode 100644 src/components/events/EventList/index.tsx diff --git a/src/components/events/EventList/index.tsx b/src/components/events/EventList/index.tsx deleted file mode 100644 index 5b872fc0..00000000 --- a/src/components/events/EventList/index.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import { LoginAppeal, PaginationControls, Typography } from '@/components/common'; -import EventDisplay from '@/components/events/EventDisplay'; -import EventFilter, { DEFAULT_FILTER_STATE } from '@/components/events/EventFilter'; -import { config } from '@/lib'; -import useQueryState from '@/lib/hooks/useQueryState'; -import { PublicAttendance, PublicEvent } from '@/lib/types/apiResponses'; -import { - FilterEventOptions, - isValidAttendanceFilter, - isValidCommunityFilter, - isValidDateFilter, -} from '@/lib/types/client'; -import { formatSearch, getDateRange, getYears } from '@/lib/utils'; -import { useMemo, useState } from 'react'; - -interface EventListProps { - events: PublicEvent[]; - attendances: PublicAttendance[]; - initialFilters: FilterEventOptions; - loggedOut: boolean; -} - -interface FilterOptions { - search: string; - communityFilter: string; - dateFilter: string | number; - attendanceFilter: string; -} - -const filterEvent = ( - event: PublicEvent, - attendances: PublicAttendance[], - { search, communityFilter, dateFilter, attendanceFilter }: FilterOptions -): boolean => { - // Filter search query - if (search !== '' && !formatSearch(event.title).includes(formatSearch(search))) { - return false; - } - // Filter by community - if (communityFilter !== 'all' && event.committee.toLowerCase() !== communityFilter) { - return false; - } - // Filter by date - const { from, to } = getDateRange(dateFilter); - if (from !== undefined && new Date(event.start) < new Date(from * 1000)) { - return false; - } - if (to !== undefined && new Date(event.end) > new Date(to * 1000)) { - return false; - } - // Filter by attendance - if (attendanceFilter === 'any') { - return true; - } - const attended = attendances.some(a => a.event.uuid === event.uuid); - if (attendanceFilter === 'attended' && !attended) { - return false; - } - if (attendanceFilter === 'not-attended' && attended) { - return false; - } - return true; -}; - -const ROWS_PER_PAGE = 25; - -const EventList = ({ events, attendances, initialFilters, loggedOut }: EventListProps) => { - const [page, setPage] = useState(0); - const years = useMemo(getYears, []); - - const validDate = (value: string): boolean => { - return isValidDateFilter(value) || years.some(o => o.value === value); - }; - - const [states, setStates] = useQueryState({ - pathName: config.eventsRoute, - initialFilters, - queryStates: { - community: { - defaultValue: DEFAULT_FILTER_STATE.community, - valid: isValidCommunityFilter, - }, - date: { - defaultValue: DEFAULT_FILTER_STATE.date, - valid: validDate, - }, - attendance: { - defaultValue: DEFAULT_FILTER_STATE.attendance, - valid: isValidAttendanceFilter, - }, - search: { - defaultValue: DEFAULT_FILTER_STATE.search, - // Any string is a valid search, so just return true. - valid: () => true, - }, - }, - }); - - const communityFilter = states.community?.value || DEFAULT_FILTER_STATE.community; - const dateFilter = states.date?.value || DEFAULT_FILTER_STATE.date; - const attendanceFilter = states.attendance?.value || DEFAULT_FILTER_STATE.attendance; - const search = states.search?.value || DEFAULT_FILTER_STATE.search; - - const filteredEvents = events.filter(e => - filterEvent(e, attendances, { search, communityFilter, dateFilter, attendanceFilter }) - ); - - filteredEvents.sort((a, b) => { - if (dateFilter === 'upcoming') { - // For upcoming events, sort from soonest to latest - return new Date(a.start).getTime() - new Date(b.start).getTime(); - } - // For all other events, sort from most recent to least recent - return new Date(b.start).getTime() - new Date(a.start).getTime(); - }); - - const displayedEvents = filteredEvents.slice(page * ROWS_PER_PAGE, (page + 1) * ROWS_PER_PAGE); - - return ( - <> - Events - {loggedOut ? ( - - Create an account to check into events, give feedback, earn points, and join a community - of thousands. - - ) : null} - { - setStates(param, value); - setPage(0); - }} - loggedOut={loggedOut} - /> - - - {filteredEvents.length > 0 ? ( - setPage(page)} - pages={Math.ceil(filteredEvents.length / ROWS_PER_PAGE)} - /> - ) : null} - - ); -}; - -export default EventList; diff --git a/src/components/events/index.tsx b/src/components/events/index.tsx index e35d4732..448bcffd 100644 --- a/src/components/events/index.tsx +++ b/src/components/events/index.tsx @@ -4,5 +4,4 @@ export { default as EventCard } from './EventCard'; export { default as EventCarousel } from './EventCarousel'; export { default as EventDisplay } from './EventDisplay'; export { DEFAULT_FILTER_STATE, default as EventFilter } from './EventFilter'; -export { default as EventList } from './EventList'; export { default as EventModal } from './EventModal'; diff --git a/src/pages/events.tsx b/src/pages/events.tsx index 05382e4a..b80866e6 100644 --- a/src/pages/events.tsx +++ b/src/pages/events.tsx @@ -1,12 +1,66 @@ -import { DEFAULT_FILTER_STATE, EventList } from '@/components/events'; +import { LoginAppeal, PaginationControls, Typography } from '@/components/common'; +import { DEFAULT_FILTER_STATE, EventDisplay, EventFilter } from '@/components/events'; +import { config } from '@/lib'; import { EventAPI, UserAPI } from '@/lib/api'; import { getCurrentUser } from '@/lib/hoc/withAccessType'; +import useQueryState from '@/lib/hooks/useQueryState'; import { CookieService } from '@/lib/services'; import type { PublicAttendance, PublicEvent } from '@/lib/types/apiResponses'; -import { FilterEventOptions } from '@/lib/types/client'; +import { + FilterEventOptions, + isValidAttendanceFilter, + isValidCommunityFilter, + isValidDateFilter, +} from '@/lib/types/client'; import { CookieType } from '@/lib/types/enums'; +import { formatSearch, getDateRange, getYears } from '@/lib/utils'; import styles from '@/styles/pages/events.module.scss'; import { GetServerSideProps } from 'next'; +import { useMemo, useState } from 'react'; + +interface FilterOptions { + search: string; + communityFilter: string; + dateFilter: string | number; + attendanceFilter: string; +} + +const filterEvent = ( + event: PublicEvent, + attendances: PublicAttendance[], + { search, communityFilter, dateFilter, attendanceFilter }: FilterOptions +): boolean => { + // Filter search query + if (search !== '' && !formatSearch(event.title).includes(formatSearch(search))) { + return false; + } + // Filter by community + if (communityFilter !== 'all' && event.committee.toLowerCase() !== communityFilter) { + return false; + } + // Filter by date + const { from, to } = getDateRange(dateFilter); + if (from !== undefined && new Date(event.start) < new Date(from * 1000)) { + return false; + } + if (to !== undefined && new Date(event.end) > new Date(to * 1000)) { + return false; + } + // Filter by attendance + if (attendanceFilter === 'any') { + return true; + } + const attended = attendances.some(a => a.event.uuid === event.uuid); + if (attendanceFilter === 'attended' && !attended) { + return false; + } + if (attendanceFilter === 'not-attended' && attended) { + return false; + } + return true; +}; + +const ROWS_PER_PAGE = 25; interface EventsPageProps { events: PublicEvent[]; @@ -16,14 +70,83 @@ interface EventsPageProps { } const EventsPage = ({ events, attendances, initialFilters, loggedOut }: EventsPageProps) => { + const [page, setPage] = useState(0); + const years = useMemo(getYears, []); + + const validDate = (value: string): boolean => { + return isValidDateFilter(value) || years.some(o => o.value === value); + }; + + const [states, setStates] = useQueryState({ + pathName: config.eventsRoute, + initialFilters, + queryStates: { + community: { + defaultValue: DEFAULT_FILTER_STATE.community, + valid: isValidCommunityFilter, + }, + date: { + defaultValue: DEFAULT_FILTER_STATE.date, + valid: validDate, + }, + attendance: { + defaultValue: DEFAULT_FILTER_STATE.attendance, + valid: isValidAttendanceFilter, + }, + search: { + defaultValue: DEFAULT_FILTER_STATE.search, + // Any string is a valid search, so just return true. + valid: () => true, + }, + }, + }); + + const communityFilter = states.community?.value || DEFAULT_FILTER_STATE.community; + const dateFilter = states.date?.value || DEFAULT_FILTER_STATE.date; + const attendanceFilter = states.attendance?.value || DEFAULT_FILTER_STATE.attendance; + const search = states.search?.value || DEFAULT_FILTER_STATE.search; + + const filteredEvents = events.filter(e => + filterEvent(e, attendances, { search, communityFilter, dateFilter, attendanceFilter }) + ); + + filteredEvents.sort((a, b) => { + if (dateFilter === 'upcoming') { + // For upcoming events, sort from soonest to latest + return new Date(a.start).getTime() - new Date(b.start).getTime(); + } + // For all other events, sort from most recent to least recent + return new Date(b.start).getTime() - new Date(a.start).getTime(); + }); + + const displayedEvents = filteredEvents.slice(page * ROWS_PER_PAGE, (page + 1) * ROWS_PER_PAGE); + return (
- Events + {loggedOut ? ( + + Create an account to check into events, give feedback, earn points, and join a community + of thousands. + + ) : null} + { + setStates(param, value); + setPage(0); + }} loggedOut={loggedOut} /> + + + {filteredEvents.length > 0 ? ( + setPage(page)} + pages={Math.ceil(filteredEvents.length / ROWS_PER_PAGE)} + /> + ) : null}
); };