From adf5ecbee89c3912cd87b426bf64d0baf27f5344 Mon Sep 17 00:00:00 2001 From: "matthew.jones" Date: Tue, 4 Feb 2025 23:39:23 -0500 Subject: [PATCH 01/12] Remove senior-project-2 builds for release --- .env.production | 2 +- .github/workflows/ci.yml | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/.env.production b/.env.production index 7b679b313a..adf7e4f84f 100644 --- a/.env.production +++ b/.env.production @@ -5,4 +5,4 @@ VITE_ANALYTICS_ID=G-2FE78G0CBN # @TRAIN -VITE_API_URL=https://360ApiSP2.gordon.edu/ +VITE_API_URL=https://360ApiTrain.gordon.edu/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c244603f8f..d3ea5954fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,6 @@ on: branches: - develop - master - - senior-project-2 jobs: build: @@ -56,10 +55,3 @@ jobs: with: name: build-prod path: dist - - - name: Upload master build artifacts for deployment - if: ${{ github.ref == 'refs/heads/senior-project-2' }} - uses: actions/upload-artifact@v4 - with: - name: build-senior-project-2 - path: dist From 3c48f1eb8f425e8626a3d4df1d34789253a09aa3 Mon Sep 17 00:00:00 2001 From: Evan Platzer Date: Mon, 10 Feb 2025 09:07:05 -0500 Subject: [PATCH 02/12] Replace luxon w/ date-fns as react-big-calendar localizer --- .../components/ScheduleCalendar/index.tsx | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/Profile/components/SchedulePanel/components/ScheduleCalendar/index.tsx b/src/components/Profile/components/SchedulePanel/components/ScheduleCalendar/index.tsx index 88145d0976..4c46823bf1 100644 --- a/src/components/Profile/components/SchedulePanel/components/ScheduleCalendar/index.tsx +++ b/src/components/Profile/components/SchedulePanel/components/ScheduleCalendar/index.tsx @@ -1,9 +1,19 @@ -import { Calendar, luxonLocalizer } from 'react-big-calendar'; +import { Calendar, dateFnsLocalizer } from 'react-big-calendar'; import { CourseEvent, Schedule, scheduleCalendarResources } from 'services/schedule'; import './ScheduleCalendar.css'; -import { DateTime } from 'luxon'; +import { format, getDay, startOfWeek } from 'date-fns'; +import { enUS } from 'date-fns/locale'; -const localizer = luxonLocalizer(DateTime, { firstDayOfWeek: 1 }); +const locales = { + 'en-US': enUS, +}; + +const localizer = dateFnsLocalizer({ + format, + startOfWeek, + getDay, + locales, +}); type Props = { schedule: Schedule; From a806eae0cebb5f6eccce0b4d3e9f3c3902366ad9 Mon Sep 17 00:00:00 2001 From: Evan Platzer Date: Mon, 10 Feb 2025 15:39:41 -0500 Subject: [PATCH 03/12] Remove lingering luxon uses --- src/services/event.ts | 12 +++++++----- src/services/news.ts | 18 +++++++----------- .../components/StaffMenu/index.jsx | 6 +++--- .../components/ApplicationDataTable/index.jsx | 5 ++--- .../components/MissingItemReportData/index.tsx | 8 ++++---- 5 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/services/event.ts b/src/services/event.ts index ecab2aff00..da60d3e043 100644 --- a/src/services/event.ts +++ b/src/services/event.ts @@ -1,4 +1,3 @@ -import { DateTime } from 'luxon'; import http from './http'; import session from './session'; import { compareByProperty, filter } from './utils'; @@ -37,13 +36,16 @@ type EventDisplayProperties = { type Event = UnformattedEvent & EventDisplayProperties; type AttendedEvent = UnformattedAttendedEvent & EventDisplayProperties; +const shortTimeFormatter = new Intl.DateTimeFormat('en-US', { timeStyle: 'short' }); +const shortDateFormatter = new Intl.DateTimeFormat('en-US', { dateStyle: 'short' }); + function formatEvent(event: T): T & EventDisplayProperties { + const startDate = new Date(event.StartDate); + const endDate = new Date(event.EndDate); return { ...event, - timeRange: `${DateTime.fromISO(event.StartDate).toFormat('t')} - ${DateTime.fromISO( - event.EndDate, - ).toFormat('t')}`, - date: DateTime.fromISO(event.StartDate).toFormat('LLL d, yyyy'), + timeRange: shortTimeFormatter.formatRange(startDate, endDate), + date: shortDateFormatter.format(startDate), title: event.Event_Title || event.Event_Name, location: event.Location || 'No Location Listed', Description: diff --git a/src/services/news.ts b/src/services/news.ts index cac7ba1e05..da87c185d0 100644 --- a/src/services/news.ts +++ b/src/services/news.ts @@ -1,4 +1,3 @@ -import { DateTime } from 'luxon'; import http from './http'; import { filter, map } from './utils'; @@ -35,8 +34,6 @@ const getPostingByID = (id: number): Promise => http.get(`news/${id} type FormattedNewsObject = NewsObject & { dayPosted: string; - yearPosted: number; - datePosted: string; author: string; }; @@ -47,17 +44,16 @@ type StudentNewsUpload = { image: string; }; -function formatPosting(posting: NewsObject): FormattedNewsObject { - const timestamp = DateTime.fromISO(posting.Entered); - const dayPosted = timestamp.weekdayShort + ', ' + timestamp.monthLong + ' ' + timestamp.day; - const yearPosted = timestamp.year; - const datePosted = timestamp.month + '/' + timestamp.day; +const dayPostedFormatter = new Intl.DateTimeFormat('en-US', { + weekday: 'short', + month: 'long', + day: 'numeric', +}); +function formatPosting(posting: NewsObject): FormattedNewsObject { return { ...posting, - dayPosted, - yearPosted, - datePosted, + dayPosted: dayPostedFormatter.format(new Date(posting.Entered)), author: posting.ADUN.replace('.', ' '), }; } diff --git a/src/views/ApartmentApp/components/StaffMenu/index.jsx b/src/views/ApartmentApp/components/StaffMenu/index.jsx index c5b395354e..09357235a7 100644 --- a/src/views/ApartmentApp/components/StaffMenu/index.jsx +++ b/src/views/ApartmentApp/components/StaffMenu/index.jsx @@ -1,14 +1,14 @@ -import { Button, Card, CardContent, CardHeader, Grid, Typography } from '@mui/material/'; import GetAppIcon from '@mui/icons-material/GetApp'; import RefreshIcon from '@mui/icons-material/Refresh'; +import { Button, Card, CardContent, CardHeader, Grid, Typography } from '@mui/material/'; import GordonLoader from 'components/Loader'; import { sortBy } from 'lodash'; -import { DateTime } from 'luxon'; import { forwardRef, useCallback, useEffect, useState } from 'react'; import { CSVLink } from 'react-csv'; import { NotFoundError } from 'services/error'; import housing from 'services/housing'; // @TODO CSSMODULES - outside directory +import { format } from 'date-fns'; import styles from '../../ApartmentApp.module.css'; import ApplicationsTable from './components/ApplicationTable'; @@ -81,7 +81,7 @@ const StaffMenu = ({ userProfile }) => { loadAllCurrentApplications(); // Generate string of today's date in ISO format for use in CSV filename - setDateStr(DateTime.now().toISODate({ includeOffset: false })); + setDateStr(format(new Date(), 'yyyy-MM-dd')); }, [userProfile, loadAllCurrentApplications]); useEffect(() => { diff --git a/src/views/ApartmentApp/components/StudentApplication/components/ApplicationDataTable/index.jsx b/src/views/ApartmentApp/components/StudentApplication/components/ApplicationDataTable/index.jsx index 9363890924..2900709dea 100644 --- a/src/views/ApartmentApp/components/StudentApplication/components/ApplicationDataTable/index.jsx +++ b/src/views/ApartmentApp/components/StudentApplication/components/ApplicationDataTable/index.jsx @@ -10,7 +10,6 @@ import { Typography, } from '@mui/material/'; import EmailIcon from '@mui/icons-material/Email'; -import { DateTime } from 'luxon'; // @TODO CSSMODULES - outside directory import styles from '../../../../ApartmentApp.module.css'; @@ -35,11 +34,11 @@ const ApplicationDataTable = ({ applicationDetails }) => { let rows = [ createData( 'Last Submitted: ', - dateSubmitted ? DateTime.fromISO(dateSubmitted).toLocaleString() : 'Not yet submitted', + dateSubmitted ? new Date(dateSubmitted).toLocaleString() : 'Not yet submitted', ), createData( 'Last Modified: ', - dateModified ? DateTime.fromISO(dateModified).toLocaleString() : 'Not yet saved', + dateModified ? new Date(dateModified).toLocaleString() : 'Not yet saved', ), createData('Application Editor: ', editorUsername ?? 'None'), ]; diff --git a/src/views/CampusSafety/views/LostAndFoundAdmin/views/MissingItemList/components/MissingItemReportData/index.tsx b/src/views/CampusSafety/views/LostAndFoundAdmin/views/MissingItemList/components/MissingItemReportData/index.tsx index a8d5def84f..1d8b28a2f8 100644 --- a/src/views/CampusSafety/views/LostAndFoundAdmin/views/MissingItemList/components/MissingItemReportData/index.tsx +++ b/src/views/CampusSafety/views/LostAndFoundAdmin/views/MissingItemList/components/MissingItemReportData/index.tsx @@ -22,12 +22,12 @@ import styles from './MissingItemReportData.module.scss'; import { useEffect, useRef, useState } from 'react'; import lostAndFoundService from 'services/lostAndFound'; import type { MissingItemReport, MissingAdminAction } from 'services/lostAndFound'; -import { DateTime } from 'luxon'; import Header from 'views/CampusSafety/components/Header'; import GordonLoader from 'components/Loader'; import GordonDialogBox from 'components/GordonDialogBox'; import userService from 'services/user'; import SimpleSnackbar from 'components/Snackbar'; +import { format } from 'date-fns'; const MissingItemReportData = () => { const navigate = useNavigate(); @@ -327,7 +327,7 @@ const MissingItemReportData = () => { let requestData = { ...newActionFormData, missingID: parseInt(itemId || ''), - actionDate: DateTime.now().toISO(), + actionDate: new Date().toISOString(), username: username.AD_Username, isPublic: newActionFormData.action === 'Checked' && !checkedItemNotFound ? true : false, }; @@ -348,11 +348,11 @@ const MissingItemReportData = () => { }, [checkedActionFormData]); // Format date strings for display - const formatDate = (date: string) => DateTime.fromISO(date).toFormat('M/d/yy'); + const formatDate = (date: string) => format(date, 'M/d/yy'); if (!item) return null; - const formattedDateLost = DateTime.fromISO(item.dateLost).toFormat('MM-dd-yy'); + const formattedDateLost = format(new Date(item.dateLost), 'MM-dd-yy'); const statusChip = ( Date: Mon, 10 Feb 2025 15:40:06 -0500 Subject: [PATCH 04/12] Remove unused luxon dep --- package-lock.json | 10 +--------- package.json | 2 -- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3e678ab58a..58dfecce15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,12 +16,12 @@ "@mui/material": "^5.15.10", "@mui/x-date-pickers": "^6.19.4", "add-to-calendar-button": "^2.5.10", + "caniuse-lite": "^1.0.30001589", "chart.js": "^4.4.3", "cropperjs": "^1.6.1", "date-fns": "^3.3.1", "history": "^5.3.0", "lodash": "^4.17.21", - "luxon": "^3.4.4", "prop-types": ">=15.7.2", "react": "^18.3.1", "react-big-calendar": "^1.10.3", @@ -45,7 +45,6 @@ }, "devDependencies": { "@types/lodash": "^4.14.202", - "@types/luxon": "^3.4.2", "@types/react-big-calendar": "^1.8.8", "@types/react-dom": "^18.3.0", "@types/react-router-dom": "^5.3.3", @@ -3810,12 +3809,6 @@ "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", "dev": true }, - "node_modules/@types/luxon": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", - "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==", - "dev": true - }, "node_modules/@types/markdown-it": { "version": "12.2.3", "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", @@ -4772,7 +4765,6 @@ "version": "1.0.30001669", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", - "dev": true, "funding": [ { "type": "opencollective", diff --git a/package.json b/package.json index 85fe02d826..6ca1d560be 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "date-fns": "^3.3.1", "history": "^5.3.0", "lodash": "^4.17.21", - "luxon": "^3.4.4", "prop-types": ">=15.7.2", "react": "^18.3.1", "react-big-calendar": "^1.10.3", @@ -42,7 +41,6 @@ }, "devDependencies": { "@types/lodash": "^4.14.202", - "@types/luxon": "^3.4.2", "@types/react-big-calendar": "^1.8.8", "@types/react-dom": "^18.3.0", "@types/react-router-dom": "^5.3.3", From de1e1661ef13427b7338d5ab2b12ba4f68da2341 Mon Sep 17 00:00:00 2001 From: Evan Platzer Date: Mon, 10 Feb 2025 16:40:30 -0500 Subject: [PATCH 05/12] Remove obsolete attended events view --- src/routes.jsx | 8 --- src/services/event.ts | 48 +++----------- .../EventList/EventList.module.scss | 2 +- .../EventItem/EventItem.module.scss | 7 +- .../EventList/components/EventItem/index.tsx | 14 +--- .../Events}/components/EventList/index.tsx | 7 +- src/views/Events/index.jsx | 5 +- .../EventsAttended/EventsAttended.module.scss | 3 - src/views/EventsAttended/index.jsx | 66 ------------------- 9 files changed, 23 insertions(+), 137 deletions(-) rename src/{ => views/Events}/components/EventList/EventList.module.scss (98%) rename src/{ => views/Events}/components/EventList/components/EventItem/EventItem.module.scss (85%) rename src/{ => views/Events}/components/EventList/components/EventItem/index.tsx (92%) rename src/{ => views/Events}/components/EventList/index.tsx (89%) delete mode 100644 src/views/EventsAttended/EventsAttended.module.scss delete mode 100644 src/views/EventsAttended/index.jsx diff --git a/src/routes.jsx b/src/routes.jsx index 88990e95da..07bda7a3fd 100644 --- a/src/routes.jsx +++ b/src/routes.jsx @@ -5,7 +5,6 @@ import BannerSubmission from './views/BannerSubmission'; import CoCurricularTranscript from './views/CoCurricularTranscript'; import EnrollmentCheckIn from './views/EnrollmentCheckIn'; import Events from './views/Events'; -import EventsAttended from './views/EventsAttended'; import Feedback from './views/Feedback'; import Help from './views/Help'; import Home from './views/Home'; @@ -23,8 +22,6 @@ import PublicProfile from './views/PublicProfile'; import Timesheets from './views/Timesheets'; import RecIM from './views/RecIM'; import RoomRanges from 'views/ResLife/components/RDView/components/RoomRanges'; -import { element } from 'prop-types'; -import { Room } from '@mui/icons-material'; import CampusSafety from './views/CampusSafety'; // Route order must be from most specific to least specific (i.e. `/user/:username` before `/user`) @@ -69,11 +66,6 @@ const routes = [ path: '/events', element: , }, - { - name: 'Attended', - path: '/attended', - element: , - }, { name: 'Feedback', path: '/feedback', diff --git a/src/services/event.ts b/src/services/event.ts index da60d3e043..5a410a45c2 100644 --- a/src/services/event.ts +++ b/src/services/event.ts @@ -1,8 +1,7 @@ import http from './http'; -import session from './session'; -import { compareByProperty, filter } from './utils'; +import { compareByProperty } from './utils'; -type BaseEvent = { +type UnformattedEvent = { Event_Name: string; Event_Title: string; Description: string; @@ -10,36 +9,23 @@ type BaseEvent = { EndDate: string; Location: string; Organization: string; -}; - -type UnformattedEvent = BaseEvent & { Event_ID: string; Event_Type_Name: string; HasCLAWCredit: boolean; IsPublic: boolean; }; -type UnformattedAttendedEvent = BaseEvent & { - LiveID: string; - CHDate?: Date; - CHTermCD: string; - Required?: number; -}; - -type EventDisplayProperties = { +export type Event = UnformattedEvent & { timeRange: string; date: string; title: string; location: string; }; -type Event = UnformattedEvent & EventDisplayProperties; -type AttendedEvent = UnformattedAttendedEvent & EventDisplayProperties; - const shortTimeFormatter = new Intl.DateTimeFormat('en-US', { timeStyle: 'short' }); const shortDateFormatter = new Intl.DateTimeFormat('en-US', { dateStyle: 'short' }); -function formatEvent(event: T): T & EventDisplayProperties { +function formatEvent(event: UnformattedEvent): Event { const startDate = new Date(event.StartDate); const endDate = new Date(event.EndDate); return { @@ -54,29 +40,15 @@ function formatEvent(event: T): T & EventDisplayProperties }; } -const formatAndSort = (events: T[]): (T & EventDisplayProperties)[] => +const formatAndSort = (events: UnformattedEvent[]): Event[] => events.map(formatEvent).sort(compareByProperty('StartDate')); const getAllEvents = (): Promise => http.get('events').then(formatAndSort); -// TODO: Unused. Consider removing -const getCLWEvents = (): Promise => { - const now = Date.now(); - return http - .get('events/claw') - .then(filter((e) => new Date(e.StartDate).getTime() > now)) - .then(formatAndSort); -}; - const getAllGuestEvents = (): Promise => http.get('events/public').then(formatAndSort); -const getAttendedChapelEvents = (): Promise => - http - .get(`events/attended/${session.getTermCode()}`) - .then(formatAndSort); - const getFutureEvents = (allEvents: Event[]): Event[] => { const now = Date.now(); return allEvents @@ -135,13 +107,13 @@ const getFilteredEvents = ( const makeMatchesTimeFilter = (timeFilter: string) => (event: Event): boolean => { - if (timeFilter == '1 Week') { + if (timeFilter === '1 Week') { return new Date(event.StartDate) <= new Date(new Date().setDate(new Date().getDate() + 7)); - } else if (timeFilter == '2 Weeks') { + } else if (timeFilter === '2 Weeks') { return new Date(event.StartDate) <= new Date(new Date().setDate(new Date().getDate() + 14)); - } else if (timeFilter == '1 Month') { + } else if (timeFilter === '1 Month') { return new Date(event.StartDate) <= new Date(new Date().setMonth(new Date().getMonth() + 1)); - } else if (timeFilter == '4 Months') { + } else if (timeFilter === '4 Months') { return new Date(event.StartDate) <= new Date(new Date().setMonth(new Date().getMonth() + 4)); } else { return false; @@ -234,10 +206,8 @@ const makeMatchesFilters = const eventService = { getAllEvents, getFutureEvents, - getCLWEvents, getFilteredEvents, getAllGuestEvents, - getAttendedChapelEvents, }; export default eventService; diff --git a/src/components/EventList/EventList.module.scss b/src/views/Events/components/EventList/EventList.module.scss similarity index 98% rename from src/components/EventList/EventList.module.scss rename to src/views/Events/components/EventList/EventList.module.scss index 8f8c5e40b6..a0e6109502 100644 --- a/src/components/EventList/EventList.module.scss +++ b/src/views/Events/components/EventList/EventList.module.scss @@ -6,4 +6,4 @@ .header_text { padding-block: 0.3rem; padding-inline: 10px; -} \ No newline at end of file +} diff --git a/src/components/EventList/components/EventItem/EventItem.module.scss b/src/views/Events/components/EventList/components/EventItem/EventItem.module.scss similarity index 85% rename from src/components/EventList/components/EventItem/EventItem.module.scss rename to src/views/Events/components/EventList/components/EventItem/EventItem.module.scss index 59547b1550..16b488e217 100644 --- a/src/components/EventList/components/EventItem/EventItem.module.scss +++ b/src/views/Events/components/EventList/components/EventItem/EventItem.module.scss @@ -7,14 +7,13 @@ } .event_item:hover { - .event_column, .descriptionText { color: var(--mui-palette-primary-contrastText); } } -:global(.gc360_event_list)>section { +:global(.gc360_event_list) > section { background-color: var(--mui-palette-neutral-light); transition: background-color 200ms ease; @@ -25,10 +24,10 @@ } // Make even-numbered rows gray -:global(.gc360_event_list)>section:nth-child(even) { +:global(.gc360_event_list) > section:nth-child(even) { background-color: var(--mui-palette-neutral-200); &:hover { background-color: var(--mui-palette-secondary-main); } -} \ No newline at end of file +} diff --git a/src/components/EventList/components/EventItem/index.tsx b/src/views/Events/components/EventList/components/EventItem/index.tsx similarity index 92% rename from src/components/EventList/components/EventItem/index.tsx rename to src/views/Events/components/EventList/components/EventItem/index.tsx index a8804a5cad..7081065eb6 100644 --- a/src/components/EventList/components/EventItem/index.tsx +++ b/src/views/Events/components/EventList/components/EventItem/index.tsx @@ -4,17 +4,7 @@ import styles from './EventItem.module.css'; import 'add-to-calendar-button'; import { format } from 'date-fns'; import { STORAGE_COLOR_PREFERENCE_KEY } from 'theme'; - -export interface GordonEvent { - title: string; - Description?: string; - location?: string; - date?: JSX.Element | string | number; - StartDate: string | Date | number; - EndDate: string | Date | number; - timeRange?: string; - Event_ID?: string; -} +import { Event } from 'services/event'; const checkLightMode = (mode: string | null) => { if (mode === 'system') { @@ -31,7 +21,7 @@ const checkLightMode = (mode: string | null) => { }; type Props = { - event: GordonEvent; + event: Event; }; const EventItem = ({ event }: Props) => { diff --git a/src/components/EventList/index.tsx b/src/views/Events/components/EventList/index.tsx similarity index 89% rename from src/components/EventList/index.tsx rename to src/views/Events/components/EventList/index.tsx index 610689baad..8b3a4aeac5 100644 --- a/src/components/EventList/index.tsx +++ b/src/views/Events/components/EventList/index.tsx @@ -1,13 +1,14 @@ -import EventItem, { GordonEvent } from './components/EventItem'; import { windowBreakWidths } from 'theme'; +import EventItem from './components/EventItem'; import useWindowSize from 'hooks/useWindowSize'; -import { List, Grid, Typography, Card, CardHeader } from '@mui/material'; +import { Card, CardHeader, Grid, List, Typography } from '@mui/material'; +import { Event } from 'services/event'; import styles from './EventList.module.css'; type Props = { - events: GordonEvent[]; + events: Event[]; }; const smallHeader = ( diff --git a/src/views/Events/index.jsx b/src/views/Events/index.jsx index d46d5cb3fa..fce5bbef99 100644 --- a/src/views/Events/index.jsx +++ b/src/views/Events/index.jsx @@ -404,7 +404,10 @@ const Events = () => { diff --git a/src/views/EventsAttended/EventsAttended.module.scss b/src/views/EventsAttended/EventsAttended.module.scss deleted file mode 100644 index 1bfae92415..0000000000 --- a/src/views/EventsAttended/EventsAttended.module.scss +++ /dev/null @@ -1,3 +0,0 @@ -.title { - color: var(--mui-palette-neutral-contrastText); -} diff --git a/src/views/EventsAttended/index.jsx b/src/views/EventsAttended/index.jsx deleted file mode 100644 index cb8f431910..0000000000 --- a/src/views/EventsAttended/index.jsx +++ /dev/null @@ -1,66 +0,0 @@ -import { useIsAuthenticated } from '@azure/msal-react'; -import { Button, Grid, List, Typography } from '@mui/material'; -import EventList from 'components/EventList'; -import GordonUnauthenticated from 'components/GordonUnauthenticated'; -import GordonLoader from 'components/Loader'; -import { useEffect, useState } from 'react'; -import { Link } from 'react-router-dom'; -import event from 'services/event'; -import styles from './EventsAttended.module.css'; - -const EventsAttended = () => { - const [events, setEvents] = useState([]); - const [loading, setLoading] = useState(true); - const isAuthenticated = useIsAuthenticated(); - - useEffect(() => { - if (isAuthenticated) { - event.getAttendedChapelEvents().then(setEvents); - } - setLoading(false); - }, [isAuthenticated]); - - let content; - - if (loading === true) { - content = ; - } else if (!isAuthenticated) { - content = ; - } else if (events.length > 0) { - content = ( - - - - - - - - - ); - } else { - content = ( - -

- - No Events To Show - -
- -
- ); - } - - return ( - - - {content} - - - ); -}; - -export default EventsAttended; From 8f015547e10330403d35d4b3b9dcd8ae1db21df5 Mon Sep 17 00:00:00 2001 From: Evan Platzer Date: Mon, 10 Feb 2025 16:41:00 -0500 Subject: [PATCH 06/12] Convert Events to typescript --- package-lock.json | 12 ++++++++ package.json | 1 + src/theme.ts | 1 + src/views/Events/{index.jsx => index.tsx} | 36 +++++++++++------------ 4 files changed, 32 insertions(+), 18 deletions(-) rename src/views/Events/{index.jsx => index.tsx} (94%) diff --git a/package-lock.json b/package-lock.json index 58dfecce15..3df7037f6c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "@types/react-big-calendar": "^1.8.8", "@types/react-dom": "^18.3.0", "@types/react-router-dom": "^5.3.3", + "@types/react-router-hash-link": "^2.4.9", "@vitejs/plugin-react": "^4.2.0", "eslint-config-react-app": "^7.0.1", "eslint-plugin-import": "^2.29.1", @@ -3894,6 +3895,17 @@ "@types/react-router": "*" } }, + "node_modules/@types/react-router-hash-link": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/@types/react-router-hash-link/-/react-router-hash-link-2.4.9.tgz", + "integrity": "sha512-zl/VMj+lfJZhvjOAQXIlBVPNKSK+/fRG8AUHhlP9++LhlA2ziLeTmbRxIMJI3PCiCTS+W/FosEoDRoNOGH0OzA==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-dom": "^5.3.0" + } + }, "node_modules/@types/react-transition-group": { "version": "4.4.10", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", diff --git a/package.json b/package.json index 6ca1d560be..0f2ba2fc95 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@types/react-big-calendar": "^1.8.8", "@types/react-dom": "^18.3.0", "@types/react-router-dom": "^5.3.3", + "@types/react-router-hash-link": "^2.4.9", "@vitejs/plugin-react": "^4.2.0", "eslint-config-react-app": "^7.0.1", "eslint-plugin-import": "^2.29.1", diff --git a/src/theme.ts b/src/theme.ts index 5e6359ce6a..ed3de36ef5 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -18,6 +18,7 @@ declare module '@mui/material/styles' { declare module '@mui/material' { interface ButtonPropsColorOverrides { neutral: any; + link: any; } } diff --git a/src/views/Events/index.jsx b/src/views/Events/index.tsx similarity index 94% rename from src/views/Events/index.jsx rename to src/views/Events/index.tsx index fce5bbef99..afb4ce8ae8 100644 --- a/src/views/Events/index.jsx +++ b/src/views/Events/index.tsx @@ -22,23 +22,23 @@ import EventIcon from '@mui/icons-material/Event'; import FilterListIcon from '@mui/icons-material/FilterList'; import ClockIcon from '@mui/icons-material/AccessTime'; import Autocomplete from '@mui/material/Autocomplete'; -import EventList from 'components/EventList'; +import EventList from './components/EventList'; import GordonLoader from 'components/Loader'; import { useWindowSize } from 'hooks'; import { useEffect, useMemo, useState } from 'react'; -import gordonEvent, { EVENT_FILTERS } from 'services/event'; +import gordonEvent, { Event, EVENT_FILTERS } from 'services/event'; import { useLocation, useNavigate } from 'react-router-dom'; import styles from './Events.module.css'; const Events = () => { const [open, setOpen] = useState(false); const [search, setSearch] = useState(''); - const [allEvents, setAllEvents] = useState([]); - const [events, setEvents] = useState([]); - const [filteredEvents, setFilteredEvents] = useState([]); + const [allEvents, setAllEvents] = useState([]); + const [events, setEvents] = useState([]); + const [filteredEvents, setFilteredEvents] = useState([]); const [includePast, setIncludePast] = useState(false); const [loading, setLoading] = useState(true); - const [filters, setFilters] = useState([]); + const [filters, setFilters] = useState([]); const [timeFilter, setTimeFilter] = useState('2 Weeks'); const [hasInitializedEvents, setHasInitializedEvents] = useState(false); const futureEvents = useMemo(() => gordonEvent.getFutureEvents(allEvents), [allEvents]); @@ -95,7 +95,7 @@ const Events = () => { setFilteredEvents(gordonEvent.getFilteredEvents(events, filters, search, timeFilter)); }, [events, filters, search, timeFilter]); - const handleChangeFilters = async (value) => { + const handleChangeFilters = async (value: string[]) => { setFilters(value); setURLParams(includePast, value); }; @@ -118,7 +118,7 @@ const Events = () => { setURLParams(!includePast, filters); }; - const setURLParams = (includePast, filters) => { + const setURLParams = (includePast: boolean, filters: string[]) => { if (includePast || filters.length > 0) { let url = '?'; if (includePast) url += '&Past'; @@ -126,7 +126,7 @@ const Events = () => { navigate(url); } else if (location.search) { // If no params but current url has params, then push url with no params - navigate(); + navigate(''); } }; @@ -135,11 +135,11 @@ const Events = () => { if (loading || !hasInitializedEvents) { content = ; } else { - content = ; + content = ; } const searchPageTitle = ( -
+
Search Gordon Events @@ -151,11 +151,11 @@ const Events = () => { if (timeFilter != '') { filterReminder = ( <> -
+
Your search is limited to {timeFilter}. Check out the top of the page if you want to change your filters.
-
+
+ + + + + ); +}; +export default EventFilters; diff --git a/src/views/Events/components/EventList/index.tsx b/src/views/Events/components/EventList/index.tsx index 8b3a4aeac5..57d942764a 100644 --- a/src/views/Events/components/EventList/index.tsx +++ b/src/views/Events/components/EventList/index.tsx @@ -6,9 +6,11 @@ import useWindowSize from 'hooks/useWindowSize'; import { Card, CardHeader, Grid, List, Typography } from '@mui/material'; import { Event } from 'services/event'; import styles from './EventList.module.css'; +import GordonLoader from 'components/Loader'; type Props = { events: Event[]; + loading: boolean; }; const smallHeader = ( @@ -60,21 +62,24 @@ const noEvents = ( const breakpointWidth = windowBreakWidths.breakSM; -const EventList = ({ events }: Props) => { +const EventList = ({ events, loading }: Props) => { const [width] = useWindowSize(); - const header = width < breakpointWidth ? smallHeader : fullHeader; - return ( - - + + {loading ? ( + + ) : ( {events?.length < 1 ? noEvents : events.map((event) => )} - + )} ); }; diff --git a/src/views/Events/index.tsx b/src/views/Events/index.tsx index afb4ce8ae8..882ba33c0b 100644 --- a/src/views/Events/index.tsx +++ b/src/views/Events/index.tsx @@ -1,512 +1,74 @@ import { useIsAuthenticated } from '@azure/msal-react'; -import { - Button, - Card, - CardContent, - CardHeader, - Checkbox, - Chip, - Collapse, - FormControl, - FormControlLabel, - Grid, - InputLabel, - Link, - MenuItem, - Select, - TextField, -} from '@mui/material'; -import { HashLink } from 'react-router-hash-link'; -import AddIcon from '@mui/icons-material/Add'; -import EventIcon from '@mui/icons-material/Event'; -import FilterListIcon from '@mui/icons-material/FilterList'; -import ClockIcon from '@mui/icons-material/AccessTime'; -import Autocomplete from '@mui/material/Autocomplete'; +import { Button, CardHeader, Grid } from '@mui/material'; import EventList from './components/EventList'; import GordonLoader from 'components/Loader'; -import { useWindowSize } from 'hooks'; -import { useEffect, useMemo, useState } from 'react'; -import gordonEvent, { Event, EVENT_FILTERS } from 'services/event'; -import { useLocation, useNavigate } from 'react-router-dom'; -import styles from './Events.module.css'; +import { useEffect, useState } from 'react'; +import gordonEvent, { Event } from 'services/event'; +import EventFilters from './components/EventFilters'; +import { HashLink } from 'react-router-hash-link'; const Events = () => { - const [open, setOpen] = useState(false); - const [search, setSearch] = useState(''); - const [allEvents, setAllEvents] = useState([]); - const [events, setEvents] = useState([]); + const [unfilteredEvents, setUnfilteredEvents] = useState([]); const [filteredEvents, setFilteredEvents] = useState([]); - const [includePast, setIncludePast] = useState(false); const [loading, setLoading] = useState(true); - const [filters, setFilters] = useState([]); - const [timeFilter, setTimeFilter] = useState('2 Weeks'); - const [hasInitializedEvents, setHasInitializedEvents] = useState(false); - const futureEvents = useMemo(() => gordonEvent.getFutureEvents(allEvents), [allEvents]); - const [width] = useWindowSize(); const isAuthenticated = useIsAuthenticated(); - const navigate = useNavigate(); - const location = useLocation(); - const timeFilters = ['1 Week', '2 Weeks', '1 Month', '4 Months']; useEffect(() => { const loadEvents = async () => { setLoading(true); - let allEvents; - if (isAuthenticated) { - allEvents = await gordonEvent.getAllEvents(); - } else { - allEvents = await gordonEvent.getAllGuestEvents(); - } - setAllEvents(allEvents); - setHasInitializedEvents(true); - - // Load filters from UrlParams if they exist - if (location.search) { - const urlParams = new URLSearchParams(location.search); - let willIncludePast = false; - const filtersFromURL = []; - - for (const key of urlParams.keys()) { - if (key === 'Past') { - willIncludePast = true; - } else { - filtersFromURL.push(key); - } - } - setFilters(filtersFromURL); - setIncludePast(willIncludePast); - setOpen(willIncludePast || filtersFromURL.length > 0); - } + const allEvents = isAuthenticated + ? await gordonEvent.getAllEvents() + : await gordonEvent.getAllGuestEvents(); + setUnfilteredEvents(allEvents); setLoading(false); }; loadEvents(); - }, [isAuthenticated, location.search]); - - useEffect(() => { - setLoading(true); - setEvents(includePast ? allEvents : futureEvents); - setLoading(false); - }, [includePast, allEvents, futureEvents]); - - useEffect(() => { - setFilteredEvents(gordonEvent.getFilteredEvents(events, filters, search, timeFilter)); - }, [events, filters, search, timeFilter]); - - const handleChangeFilters = async (value: string[]) => { - setFilters(value); - setURLParams(includePast, value); - }; - - const handleExpandClick = () => { - setOpen(!open); - }; - - const clearAll = () => { - setIncludePast(false); - setFilters([]); - setURLParams(false, []); - setSearch(''); - setOpen(false); - setTimeFilter(''); - }; - - const handleChangeIncludePast = () => { - setIncludePast(!includePast); - setURLParams(!includePast, filters); - }; - - const setURLParams = (includePast: boolean, filters: string[]) => { - if (includePast || filters.length > 0) { - let url = '?'; - if (includePast) url += '&Past'; - url = filters.reduce((url, filter) => (url += `&${encodeURIComponent(filter)}`), url); - navigate(url); - } else if (location.search) { - // If no params but current url has params, then push url with no params - navigate(''); - } - }; - - let content; - - if (loading || !hasInitializedEvents) { - content = ; - } else { - content = ; - } - - const searchPageTitle = ( -
- Search - Gordon - Events -
- ); - - let filterReminder; - - if (timeFilter != '') { - filterReminder = ( - <> -
- Your search is limited to {timeFilter}. Check out the top of the page if you want to - change your filters. -
-
- -
- - ); - } else { - filterReminder = ( - <> -
- You have reached the end of Gordon's events. Check out the top of the page if you want to - add filters. -
-
- -
- - ); - } - - if (width >= 920) { - return ( - - - - - - {/* Search Bar and Filters */} - - - - - - - - setSearch(event.target.value)} - /> - - - - - - - - - - - - {isAuthenticated && ( - - )} - - - - - - - - - - - - - { - handleChangeFilters(value); - }} - filterSelectedOptions - renderTags={(value, getTagProps) => - value.map((option, index) => ( - - )) - } - value={filters} - renderInput={(param) => ( - - )} - /> - - - - } - label="Include Past" - /> - - - - - - - - - Time Window - - - - - - - - - - - - - -
- - {/* List of Events */} - - {content} - - -
-
- ); - } else if (width < 920) { - return ( - - - - - - {/* Search Bar and Filters */} - - - {width > 600 && ( - - - - )} - - setSearch(event.target.value)} - /> - - - - - - - - - - - - - {isAuthenticated && ( - - )} - - - - - - - - - } - label="Include Past" - /> - - - {width > 600 && ( - - - - )} - - { - handleChangeFilters(value); - }} - filterSelectedOptions - renderTags={(value, getTagProps) => - value.map((option, index) => ( - - )) - } - renderInput={(param) => ( - - )} - /> - - {width > 600 && ( - - - - )} - - - Time Window - - - - - - - - - - - -
- {/* List of Events */} - - {content} - - + }, [isAuthenticated]); + + const content = ; + + return ( + + + +
+ + + {content} + +
+ You have reached the end of Gordon's events. Check out the top of the page if you + want to add filters. +
+ +
+ } + id="bottom" + /> - ); - } + + ); }; export default Events; From c88a477fecc9879695aa26c53273384a62507916 Mon Sep 17 00:00:00 2001 From: Evan Platzer Date: Tue, 11 Feb 2025 11:00:57 -0500 Subject: [PATCH 08/12] Catch potential datetime formatting issues --- src/services/event.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/services/event.ts b/src/services/event.ts index d75a41e206..f2166d29fb 100644 --- a/src/services/event.ts +++ b/src/services/event.ts @@ -29,10 +29,28 @@ const shortDateFormatter = new Intl.DateTimeFormat('en-US', { dateStyle: 'short' function formatEvent(event: UnformattedEvent): Event { const startDate = new Date(event.StartDate); const endDate = new Date(event.EndDate); + + let timeRange = 'No time listed'; + let date = 'No date listed'; + + try { + timeRange = shortTimeFormatter.formatRange(startDate, endDate); + } catch { + // `Intl.DateTimeFormat#format` throws for invalid dates. We will just catch potential errors and + // Catch any potential error and fallback to the default specified above + } + + try { + date = shortDateFormatter.format(startDate); + } catch { + // `Intl.DateTimeFormat#formatRange` throws if it finds an invalid date + // Catch any potential error and fallback to the default specified above + } + return { ...event, - timeRange: shortTimeFormatter.formatRange(startDate, endDate), - date: shortDateFormatter.format(startDate), + timeRange, + date, title: event.Event_Title || event.Event_Name, location: event.Location || 'No Location Listed', Description: From 264ae88f19838595266b471d4960c6fc5f46a48b Mon Sep 17 00:00:00 2001 From: Evan Platzer Date: Tue, 11 Feb 2025 11:07:49 -0500 Subject: [PATCH 09/12] Imporve events header --- src/views/Events/components/EventList/index.tsx | 13 +++---------- src/views/Events/index.tsx | 1 - 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/views/Events/components/EventList/index.tsx b/src/views/Events/components/EventList/index.tsx index 57d942764a..71c037df1b 100644 --- a/src/views/Events/components/EventList/index.tsx +++ b/src/views/Events/components/EventList/index.tsx @@ -13,15 +13,9 @@ type Props = { loading: boolean; }; -const smallHeader = ( - - Events - -); - const headings = [ { - name: 'Event', + name: 'Name', size: 4, }, { @@ -60,15 +54,14 @@ const noEvents = ( ); -const breakpointWidth = windowBreakWidths.breakSM; - const EventList = ({ events, loading }: Props) => { const [width] = useWindowSize(); return ( {loading ? ( diff --git a/src/views/Events/index.tsx b/src/views/Events/index.tsx index 882ba33c0b..38c39509c8 100644 --- a/src/views/Events/index.tsx +++ b/src/views/Events/index.tsx @@ -1,7 +1,6 @@ import { useIsAuthenticated } from '@azure/msal-react'; import { Button, CardHeader, Grid } from '@mui/material'; import EventList from './components/EventList'; -import GordonLoader from 'components/Loader'; import { useEffect, useState } from 'react'; import gordonEvent, { Event } from 'services/event'; import EventFilters from './components/EventFilters'; From ce26a4ad25fcb4ce8d9921a23ac2e2b30110bbb2 Mon Sep 17 00:00:00 2001 From: Evan Platzer Date: Tue, 11 Feb 2025 11:43:18 -0500 Subject: [PATCH 10/12] Simplify Events styling --- .../EventList/EventList.module.scss | 3 +- .../EventItem/EventItem.module.scss | 27 ++----- .../EventList/components/EventItem/index.tsx | 72 ++++++++----------- .../Events/components/EventList/index.tsx | 50 ++++++------- src/views/Events/index.tsx | 6 +- 5 files changed, 57 insertions(+), 101 deletions(-) diff --git a/src/views/Events/components/EventList/EventList.module.scss b/src/views/Events/components/EventList/EventList.module.scss index a0e6109502..14b3fe1aaa 100644 --- a/src/views/Events/components/EventList/EventList.module.scss +++ b/src/views/Events/components/EventList/EventList.module.scss @@ -4,6 +4,5 @@ } .header_text { - padding-block: 0.3rem; - padding-inline: 10px; + color: var(--mui-palette-primary-contrastText); } diff --git a/src/views/Events/components/EventList/components/EventItem/EventItem.module.scss b/src/views/Events/components/EventList/components/EventItem/EventItem.module.scss index 16b488e217..29de6dac1b 100644 --- a/src/views/Events/components/EventList/components/EventItem/EventItem.module.scss +++ b/src/views/Events/components/EventList/components/EventItem/EventItem.module.scss @@ -1,33 +1,16 @@ .event_item { padding: 10px; -} - -.event_column { - padding-inline: 10px; -} - -.event_item:hover { - .event_column, - .descriptionText { - color: var(--mui-palette-primary-contrastText); - } -} -:global(.gc360_event_list) > section { - background-color: var(--mui-palette-neutral-light); transition: background-color 200ms ease; + cursor: pointer; - &:hover { - background-color: var(--mui-palette-secondary-main); - cursor: pointer; + background-color: var(--mui-palette-neutral-light); + &:nth-of-type(even) { + background-color: var(--mui-palette-neutral-200); } -} - -// Make even-numbered rows gray -:global(.gc360_event_list) > section:nth-child(even) { - background-color: var(--mui-palette-neutral-200); &:hover { background-color: var(--mui-palette-secondary-main); + color: var(--mui-palette-primary-contrastText); } } diff --git a/src/views/Events/components/EventList/components/EventItem/index.tsx b/src/views/Events/components/EventList/components/EventItem/index.tsx index 7081065eb6..02160f9022 100644 --- a/src/views/Events/components/EventList/components/EventItem/index.tsx +++ b/src/views/Events/components/EventList/components/EventItem/index.tsx @@ -1,4 +1,4 @@ -import { Button, CardContent, Collapse, Grid, Typography } from '@mui/material'; +import { Collapse, Grid, Typography } from '@mui/material'; import { useState } from 'react'; import styles from './EventItem.module.css'; import 'add-to-calendar-button'; @@ -7,9 +7,7 @@ import { STORAGE_COLOR_PREFERENCE_KEY } from 'theme'; import { Event } from 'services/event'; const checkLightMode = (mode: string | null) => { - if (mode === 'system') { - return 'system'; - } else if (mode === 'dark') { + if (mode === 'dark') { return 'dark'; } else if (mode === 'light') { return 'light'; @@ -42,52 +40,38 @@ const EventItem = ({ event }: Props) => { }} > - - {event.title} - + {event.title} - - - {event.date === 'Invalid DateTime' ? 'No Date Listed' : event.date} - + + {event.date} - - - {event.timeRange === 'Invalid DateTime - Invalid DateTime' - ? 'No Time Listed' - : event.timeRange} - + + {event.timeRange} - {event.location} + {event.location} - - - {event.Description || 'No description available'} - - {event.StartDate !== '' && event.EndDate !== '' && ( - - )} - + + {event.Description || 'No description available'} + + {event.StartDate !== '' && event.EndDate !== '' && ( + + )} ); diff --git a/src/views/Events/components/EventList/index.tsx b/src/views/Events/components/EventList/index.tsx index 71c037df1b..f3c85dbd2d 100644 --- a/src/views/Events/components/EventList/index.tsx +++ b/src/views/Events/components/EventList/index.tsx @@ -13,34 +13,28 @@ type Props = { loading: boolean; }; -const headings = [ - { - name: 'Name', - size: 4, - }, - { - name: 'Date', - size: 2, - }, - { - name: 'Time', - size: 2, - }, - { - name: 'Location', - size: 4, - }, -]; - -const fullHeader = ( +const tableHeader = ( - {headings.map(({ name, size }) => ( - - - {name} - - - ))} + + + Name + + + + + Date + + + + + Time + + + + + Location + + ); @@ -61,7 +55,7 @@ const EventList = ({ events, loading }: Props) => { windowBreakWidths.breakSM ? tableHeader : undefined} className={styles.header} /> {loading ? ( diff --git a/src/views/Events/index.tsx b/src/views/Events/index.tsx index 38c39509c8..24074d62c0 100644 --- a/src/views/Events/index.tsx +++ b/src/views/Events/index.tsx @@ -43,15 +43,11 @@ const Events = () => { {content} -
- You have reached the end of Gordon's events. Check out the top of the page if you - want to add filters. -
+

To find other events, adjust your filters above.