From 3c2b7e275167928f5b3d9a61fc26d37a211dbfc8 Mon Sep 17 00:00:00 2001 From: jacoblurie29 Date: Sat, 28 Oct 2023 15:53:17 -0500 Subject: [PATCH 1/7] Event display completed --- components/Organizer/OrganizerDash.tsx | 18 +- pages/api/leaderboard.ts | 2 +- pages/event.tsx | 229 +++++++++++++++++++++++++ styles/Event.module.css | 60 +++++++ 4 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 pages/event.tsx create mode 100644 styles/Event.module.css diff --git a/components/Organizer/OrganizerDash.tsx b/components/Organizer/OrganizerDash.tsx index b3081570..9722b7cf 100644 --- a/components/Organizer/OrganizerDash.tsx +++ b/components/Organizer/OrganizerDash.tsx @@ -13,10 +13,13 @@ import SettingsTab from './SettingsTab/SettingsTab'; import { RequestType, useCustomSWR } from '../../utils/request-utils'; import { UserData } from '../../types/database'; import BugReportsTab from './BugReportsTab/BugReportsTab'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; export default function OrganizerDash() { // Get session data const { data: session, status } = useSession(); + const router = useRouter(); const { accentColor, baseTheme, setAccentColor, setBaseTheme } = useContext(ThemeContext); // User data @@ -26,6 +29,10 @@ export default function OrganizerDash() { errorMessage: 'Failed to get user object.', }); + const redirectToEventPage = () => { + router.push('/event'); + }; + // Set theme useEffect(() => { if (userData && userData.settings && userData.settings.accentColor && userData.settings.baseTheme) { @@ -45,6 +52,7 @@ export default function OrganizerDash() {

Organizer Dashboard

+
{session?.user?.email} @@ -53,10 +61,18 @@ export default function OrganizerDash() { +
+ + -
+
diff --git a/pages/api/leaderboard.ts b/pages/api/leaderboard.ts index 0b3295e3..20ab7b3f 100644 --- a/pages/api/leaderboard.ts +++ b/pages/api/leaderboard.ts @@ -6,7 +6,7 @@ import Team from '../../models/team'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const session = await getSession({ req }); - if (session?.userType !== 'HACKER') return res.status(403).send('Forbidden'); + if (session?.userType !== 'HACKER' && session?.userType !== 'ORGANIZER') return res.status(403).send('Forbidden'); Team; // Don't remove or the import will get optimized out and the populate will fail await dbConnect(); diff --git a/pages/event.tsx b/pages/event.tsx new file mode 100644 index 00000000..86f7ed4e --- /dev/null +++ b/pages/event.tsx @@ -0,0 +1,229 @@ +import React, { useEffect, useState } from 'react'; +import { Button, Layout } from 'antd'; +import { useSession } from 'next-auth/react'; +import Head from 'next/head'; +import Leaderboard from '../components/hacker/Leaderboard'; +import { HackathonSettingsData, UserData } from '../types/database'; +import Image from 'next/image'; +import useSWR from 'swr'; +import styles from '../styles/Event.module.css'; +import { ArrowLeftOutlined } from '@ant-design/icons'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; + +const DEV_DEPLOY = + process.env.NODE_ENV === 'development' || ['preview', 'development'].includes(process.env.NEXT_PUBLIC_VERCEL_ENV!); // frontend env variable + +interface EventParams { + eventName: string; + eventImage: string; + countDown?: Date; +} + +const hackingBeginSoon: EventParams = { + eventName: 'Hacking Begins Soon', + eventImage: '/hacking-begin-soon.svg', +}; +const hackingCountDown: EventParams = { + eventName: 'Hacking Begins', + eventImage: '/hacking-countdown.svg', +}; +const judging: EventParams = { + eventName: 'Judging', + eventImage: '/judging.svg', +}; +const hackingEnded: EventParams = { + eventName: 'Hacking Ended', + eventImage: '/hacking-ended.svg', +}; + +const EventScreen = () => { + const { data: session, status } = useSession(); + const router = useRouter(); + const [curEvent, setCurEvent] = useState(hackingBeginSoon); + const [timeLeft, setTimeLeft] = useState(''); + const [hackathonStarted, setHackathonStarted] = useState(false); + + const { data: user } = useSWR( + '/api/user-data', + async url => { + const res = await fetch(url, { method: 'GET' }); + return (await res.json()) as UserData; + }, + { revalidateOnFocus: false, revalidateOnMount: true } + ); + + const { data: setting } = useSWR( + '/api/hackathon-settings', + async url => { + const res = await fetch(url, { method: 'GET' }); + + const hackathongSetting = (await res.json()) as HackathonSettingsData; + const hackathonStartDate = new Date(Date.parse(hackathongSetting.HACKATHON_START)); + const hackathonEndDate = new Date(Date.parse(hackathongSetting.HACKATHON_END)); + const curDate = new Date(); + + // DEV_DEPLOY is true if we are in development or preview mode + if (DEV_DEPLOY) { + setHackathonStarted(true); + } else { + setHackathonStarted(curDate >= hackathonStartDate && curDate <= hackathonEndDate); + } + + return hackathongSetting; + }, + { revalidateOnFocus: false, revalidateOnMount: true } + ); + + const redirectToHome = () => { + router.push('/'); + }; + + useEffect(() => { + if (setting) { + // Dates from setting + const hackingStartDate = new Date(Date.parse(setting.HACKATHON_START)); + const hackingEndDate = new Date(Date.parse(setting.HACKATHON_END)); + const judgingDateEnd = new Date(Date.parse(setting.JUDGING_END)); + const curDate = new Date(); + + // Check if hacking has started + if (curDate < hackingStartDate) { + setCurEvent(hackingBeginSoon); + } else if (curDate < hackingEndDate) { + setCurEvent(hackingCountDown); + } else if (curDate <= judgingDateEnd) { + setCurEvent(judging); + } else { + setCurEvent(hackingEnded); + } + } + }, [setting]); + + useEffect(() => { + if (setting) { + if (curEvent === hackingBeginSoon) { + const interval = setInterval(() => { + // check every second if hacking should start + const hackingStartDate = new Date(Date.parse(setting.HACKATHON_START)); + + const curDate = new Date(); + + if (curDate >= hackingStartDate) { + setCurEvent(hackingCountDown); + return () => clearInterval(interval); + } + }, 1000); + + return () => clearInterval(interval); + } else if (curEvent === hackingCountDown) { + const interval = setInterval(() => { + const hackingEndDate = new Date(Date.parse(setting.HACKATHON_END)); + const curDate = new Date(); + + // convert time to 00:00:00 format + const timeLeft = Math.floor((hackingEndDate.getTime() - curDate.getTime()) / 1000); + + if (timeLeft < 0) { + setTimeLeft('00:00:00'); + setCurEvent(judging); + return; + } + + const hours = Math.floor(timeLeft / 3600); + const minutes = Math.floor((timeLeft % 3600) / 60); + const seconds = timeLeft % 60; + const timeString = `${hours < 10 ? '0' : ''}${hours}:${minutes < 10 ? '0' : ''}${minutes}:${ + seconds < 10 ? '0' : '' + }${seconds}`; + + // set time left + setTimeLeft(timeString); + }, 1000); + return () => clearInterval(interval); + } else if (curEvent === judging) { + const interval = setInterval(() => { + const judgingDateEnd = new Date(Date.parse(setting.JUDGING_END)); + const curDate = new Date(); + + if (curDate > judgingDateEnd) { + setCurEvent(hackingEnded); + return () => clearInterval(interval); + } + }, 1000); + } + } + }, [curEvent, setting]); + + return ( + <> + + Report a bug! + + + + + + + + + + + + + + {!session ? null : session.userType === 'ORGANIZER' ? ( +
+
+ {'VandyHacks + +
+ {curEvent.eventName} + {curEvent === hackingCountDown &&
{timeLeft}
} +
+
+ Current Event: + {curEvent.eventName} +
+
+
+
+ +
+
+ ) : ( + redirectToHome() + )} + +
+ + ); +}; + +export default EventScreen; diff --git a/styles/Event.module.css b/styles/Event.module.css new file mode 100644 index 00000000..3a3cac2b --- /dev/null +++ b/styles/Event.module.css @@ -0,0 +1,60 @@ +.CurEvent { + width: 300px; + display: flex; + flex-direction: column; +} + +.CurEventText { + color: #fff; + text-align: center; + font-family: Inter; + font-size: 20px; + font-weight: 700; + padding-top: 20px; +} + +.CurEventThinText { + color: #fff; + text-align: center; + font-family: Inter; + font-size: 20px; + font-weight: 300; + padding-top: 20px; +} + +.IconContainer { + position: relative; + width: 300px; + height: 300px; + margin: 0 auto; +} + +.Timer { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: #fff; + text-align: center; + width: 100%; + font-size: 50px; + font-weight: 700; +} + +.leaderboard { + padding-left: 5rem; + padding-right: 5rem; +} + +.eventContainer { + display: flex; + flex-direction: row; + align-items: center; + padding-left: 5rem; +} + +.goHomeButton { + background-color: rgba(0, 0, 0, 0); + border: none; + color: #999999; +} From 5a3337c30007ccce2788eaccfa27c1bd25fb9906 Mon Sep 17 00:00:00 2001 From: jacoblurie29 Date: Sat, 28 Oct 2023 15:55:59 -0500 Subject: [PATCH 2/7] Remove unneccessary stuff --- components/Organizer/OrganizerDash.tsx | 2 +- pages/event.tsx | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/components/Organizer/OrganizerDash.tsx b/components/Organizer/OrganizerDash.tsx index 9722b7cf..b3ca725d 100644 --- a/components/Organizer/OrganizerDash.tsx +++ b/components/Organizer/OrganizerDash.tsx @@ -18,7 +18,7 @@ import { useRouter } from 'next/router'; export default function OrganizerDash() { // Get session data - const { data: session, status } = useSession(); + const { data: session } = useSession(); const router = useRouter(); const { accentColor, baseTheme, setAccentColor, setBaseTheme } = useContext(ThemeContext); diff --git a/pages/event.tsx b/pages/event.tsx index 86f7ed4e..8a9b5f22 100644 --- a/pages/event.tsx +++ b/pages/event.tsx @@ -42,7 +42,6 @@ const EventScreen = () => { const router = useRouter(); const [curEvent, setCurEvent] = useState(hackingBeginSoon); const [timeLeft, setTimeLeft] = useState(''); - const [hackathonStarted, setHackathonStarted] = useState(false); const { data: user } = useSWR( '/api/user-data', @@ -63,13 +62,6 @@ const EventScreen = () => { const hackathonEndDate = new Date(Date.parse(hackathongSetting.HACKATHON_END)); const curDate = new Date(); - // DEV_DEPLOY is true if we are in development or preview mode - if (DEV_DEPLOY) { - setHackathonStarted(true); - } else { - setHackathonStarted(curDate >= hackathonStartDate && curDate <= hackathonEndDate); - } - return hackathongSetting; }, { revalidateOnFocus: false, revalidateOnMount: true } From 744689dea1727f5f0bc4808071cd93955259e4d0 Mon Sep 17 00:00:00 2001 From: jacoblurie29 Date: Sat, 28 Oct 2023 15:58:31 -0500 Subject: [PATCH 3/7] Remove more things --- pages/event.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/pages/event.tsx b/pages/event.tsx index 8a9b5f22..8fb5e6c5 100644 --- a/pages/event.tsx +++ b/pages/event.tsx @@ -11,9 +11,6 @@ import { ArrowLeftOutlined } from '@ant-design/icons'; import Link from 'next/link'; import { useRouter } from 'next/router'; -const DEV_DEPLOY = - process.env.NODE_ENV === 'development' || ['preview', 'development'].includes(process.env.NEXT_PUBLIC_VERCEL_ENV!); // frontend env variable - interface EventParams { eventName: string; eventImage: string; From f1292ae39a9c08e31788158b60a3fe4af7d2a98c Mon Sep 17 00:00:00 2001 From: jacoblurie29 Date: Sat, 28 Oct 2023 16:06:13 -0500 Subject: [PATCH 4/7] Move button --- components/Organizer/EventsTab/EventsTab.tsx | 20 +++++++++++++++- components/Organizer/OrganizerDash.tsx | 12 ---------- pages/event.tsx | 24 +++++--------------- 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/components/Organizer/EventsTab/EventsTab.tsx b/components/Organizer/EventsTab/EventsTab.tsx index 6c8a9102..9043089e 100644 --- a/components/Organizer/EventsTab/EventsTab.tsx +++ b/components/Organizer/EventsTab/EventsTab.tsx @@ -1,23 +1,33 @@ import { Button, Input, InputRef, Modal, notification, Table, InputNumber } from 'antd'; import { ColumnsType } from 'antd/es/table'; -import { useEffect, useRef, useState } from 'react'; +import { useContext, useEffect, useRef, useState } from 'react'; import { EventCountData, EventData } from '../../../types/database'; import { RequestType, useCustomSWR } from '../../../utils/request-utils'; import { mutate } from 'swr'; import { ObjectId } from 'mongoose'; import { handleSubmitFailure, handleSubmitSuccess } from '../../../lib/helpers'; +import { useRouter } from 'next/router'; +import { ThemeContext, getAccentColor, getThemedClass } from '../../../theme/themeProvider'; +import styles from '../../../styles/Organizer.module.css'; interface EventDisplay extends EventData { setCurEvent: (open: EventDisplay) => void; } export default function Events() { + const router = useRouter(); const [curEvent, setCurEvent] = useState(null); const [events, setEvents] = useState([]); const [nfcId, setNfcId] = useState(''); const [loading, setLoading] = useState(false); const [showSaveButton, setShowSaveButton] = useState(false); + const { accentColor, baseTheme } = useContext(ThemeContext); + + const redirectToEventPage = () => { + router.push('/event'); + }; + const columns: ColumnsType = [ { title: 'Day', @@ -240,6 +250,14 @@ export default function Events() { Save Changes )} +
+ +

diff --git a/components/Organizer/OrganizerDash.tsx b/components/Organizer/OrganizerDash.tsx index b3ca725d..febdcb28 100644 --- a/components/Organizer/OrganizerDash.tsx +++ b/components/Organizer/OrganizerDash.tsx @@ -29,10 +29,6 @@ export default function OrganizerDash() { errorMessage: 'Failed to get user object.', }); - const redirectToEventPage = () => { - router.push('/event'); - }; - // Set theme useEffect(() => { if (userData && userData.settings && userData.settings.accentColor && userData.settings.baseTheme) { @@ -57,14 +53,6 @@ export default function OrganizerDash() {
{session?.user?.email}
-
- -