diff --git a/app/closed/closed.module.scss b/app/closed/closed.module.scss index 32d819dc..0982fc8c 100644 --- a/app/closed/closed.module.scss +++ b/app/closed/closed.module.scss @@ -48,8 +48,10 @@ display: flex; flex-direction: column; justify-content: center; + align-items: center; gap: 20px; flex: 0.9; + width: 400px; @media screen and (max-width: 640px) { flex: 1; } diff --git a/app/closed/page.tsx b/app/closed/page.tsx index be45dd59..d57ffdd6 100644 --- a/app/closed/page.tsx +++ b/app/closed/page.tsx @@ -1,3 +1,5 @@ +"use client"; + import Image from "next/image"; import SNOWGLOBE from "@/public/registration/track_selection/snowglobe.svg"; @@ -7,37 +9,81 @@ import BACKGROUND from "@/public/registration/track_selection/background.svg"; import OlympianButton from "@/components/OlympianButton/OlympianButton"; import styles from "@/app/closed/closed.module.scss"; +import { useContext, useEffect, useState } from "react"; +import GlobalContext from "../context"; +import { + isAuthenticated, + authenticate, + getRegistrationOrDefault +} from "@/util/api"; +import { usePathname, useRouter } from "next/navigation"; +import Loading from "@/components/Loading/Loading"; + +const Closed: React.FC = () => { + const { eventStatus } = useContext(GlobalContext); + const pathname = usePathname(); + const router = useRouter(); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + if (eventStatus === "loading") { + return; + } + + if (!isAuthenticated()) { + authenticate(pathname); + return; + } + + getRegistrationOrDefault().then(registration => { + if (registration.hasSubmitted) { + router.push("/profile"); + return; + } + + if (eventStatus === "registration") { + router.push("/register"); + return; + } + + setIsLoading(false); + }); + }, [eventStatus, pathname, router]); -const closed: React.FC = () => { return ( -
-
- HackOlympus Logo -
+ {isLoading && } +
-
-

Sorry, registration is closed.

-

Check back next year!

- + HackOlympus Logo +
+
+
+

+ Sorry, registration for HackIllinois 2025 is closed. +

+

Check back next year!

+ +
+
-
-
-
+
+ ); }; -export default closed; +export default Closed; diff --git a/app/context.ts b/app/context.ts new file mode 100644 index 00000000..fa209637 --- /dev/null +++ b/app/context.ts @@ -0,0 +1,12 @@ +"use client"; +import { createContext } from "react"; + +export type GlobalContextType = { + eventStatus: "registration" | "admission" | "loading"; +}; + +const GlobalContext = createContext({ + eventStatus: "loading" +}); + +export default GlobalContext; diff --git a/app/layout.tsx b/app/layout.tsx index 36966693..93b16219 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,7 +1,7 @@ import "./globals.scss"; import type { Metadata } from "next"; import { Montserrat } from "next/font/google"; -import Navbar from "@/components/Navbar/Navbar"; +import RootLayout from "@/components/RootLayout"; const montserrat = Montserrat({ subsets: ["latin"] }); @@ -11,16 +11,11 @@ export const metadata: Metadata = { "The official website of the University of Illinois at Urbana-Champaign's Premier Hackathon!" }; -export default function RootLayout({ - children -}: { - children: React.ReactNode; -}) { +export default function Layout({ children }: { children: React.ReactNode }) { return ( - - {children} + {children} ); diff --git a/app/olympians/page.tsx b/app/olympians/page.tsx index 25532113..4adc85b4 100644 --- a/app/olympians/page.tsx +++ b/app/olympians/page.tsx @@ -3,18 +3,12 @@ import styles from "./styles.module.scss"; import Link from "next/link"; import Background from "@/components/Olympians/Background"; -import { useEffect, useState } from "react"; -import { getRegistrationStatus } from "@/util/api"; +import { useContext } from "react"; import Head from "next/head"; +import GlobalContext from "../context"; const AboutProTrack: React.FC = () => { - const [registrationOpen, setRegistrationOpen] = useState(false); - - useEffect(() => { - getRegistrationStatus().then(status => { - setRegistrationOpen(status.alive); - }); - }, []); + const { eventStatus } = useContext(GlobalContext); return ( <> @@ -97,7 +91,7 @@ const AboutProTrack: React.FC = () => {

Admission into HackOlympians requires{" "} - {registrationOpen ? ( + {eventStatus === "registration" ? ( { + const { eventStatus } = useContext(GlobalContext); const [isLoading, setIsLoading] = useState(true); const router = useRouter(); const pathname = usePathname(); - const [isAlive, setIsAlive] = useState(true); useEffect(() => { + if (eventStatus === "loading") { + return; + } + if (!isAuthenticated()) { authenticate(pathname); return; } - getRegistrationOrDefault() - .then(registration => { - if (registration.hasSubmitted) { - router.push("/profile"); - } else if (!isAlive) { - router.push("/closed"); - } - }) - .finally(() => { - setIsLoading(false); - }); - }, []); + getRegistrationOrDefault().then(registration => { + if (registration.hasSubmitted) { + router.push("/profile"); + return; + } - useEffect(() => { - const fetchRegistrationStatus = async () => { - try { - const response = await getRegistrationStatus(); - setIsAlive(response.alive); - } catch (err) { - console.error(err); + if (eventStatus !== "registration") { + router.push("/closed"); + return; } - }; - fetchRegistrationStatus(); - }, []); + setIsLoading(false); + }); + }, [eventStatus, router, pathname]); return ( <> diff --git a/components/FAQ/FAQ.tsx b/components/FAQ/FAQ.tsx index e4a23bae..6dc1aad4 100644 --- a/components/FAQ/FAQ.tsx +++ b/components/FAQ/FAQ.tsx @@ -1,219 +1,122 @@ "use client"; -import React, { useEffect, useMemo, useState } from "react"; +import React, { useContext, useEffect, useMemo, useState } from "react"; import styles from "./FAQ.module.scss"; import Link from "next/link"; import clsx from "clsx"; -import { getRegistrationStatus } from "@/util/api"; +import GlobalContext from "@/app/context"; -const faqDataWithLinks = [ - { - question: What is a Hackathon?, - answer: ( -

- A hackathon is a collaborative event where teams utilize their - skills to create projects that solve problems or identify new - opportunities! They typically run for a short and continuous - period of time. For Hacklllinois, meals will be provided. -

- ) - }, - { - question: Are there any prizes or incentives?, - answer: ( -

- Yes! Cash prizes will be offered for winning teams in several - different categories, including{" "} - - HackOlympians - - . Additionally, there are various mini-games and events that - offer plenty of opportunities to win prizes through our Point - Shop! -

- ) - }, - { - question: ( - - What is HackOlympians? - - ), - answer: ( -

- - HackOlympians - {" "} - is an exclusive path tailored for prospective attendees to dive - into a competitively elevated hackathon atmosphere for an - increased prize value. It's a specialized arena for - experienced hackers who have mastered the fundamentals and are - now looking to test their skills in a more challenging - environment. Admission into HackOlympians requires completing - our application, which includes a{" "} - - coding challenge - - . -

- ) - }, - { - question: ( - What are the benefits of being a HackOlympian? - ), - answer: ( -

- Attendees in this path have the exclusive opportunity to compete - for the grand Olympians prize. Additionally, they will gain - access to special networking opportunities with our event - sponsors and the chance to present their project in a thrilling - Shark-Tank inspired showcase, among other exciting perks - but - spots are limited, so register soon! -

- ) - }, - { - question: ( - - How is HackOlympians different from standard HackIllinois - attendance? - - ), - answer: ( - <> +const FAQ: React.FC = () => { + const { eventStatus } = useContext(GlobalContext); + const [currentPage, setCurrentPage] = useState(0); + const [windowWidth, setWindowWidth] = useState(0); + + const faqData = [ + { + question: What is a Hackathon?, + answer: (

- HackIllinois is a historically welcoming space for coders of - all skill levels, particularly those who are just starting - out. This inclusive environment encourages beginner-level - coders to engage and learn, while HackOlympians caters to - more advanced participants, fostering a competitive and - stimulating atmosphere for seasoned hackers. All attendees - from both paths will enjoy access to Hacklllinois's - vibrant array of events, workshops, company Q&As, and the - Company Expo. Each path will maintain the spirit of - inclusivity and learning to ensure that all attendees, - regardless of their track, experience the full magic of - HackIllinois! Additionally, all HackIllinois attendees are - eligible to compete in all our sponsored tracks.* + A hackathon is a collaborative event where teams utilize + their skills to create projects that solve problems or + identify new opportunities! They typically run for a short + and continuous period of time. For Hacklllinois, meals will + be provided.

-
+ ) + }, + { + question: Are there any prizes or incentives?, + answer: (

- *The Best Beginner and General prizes are reserved for - HackIllinois General attendees, while the Best Olympians - prize is reserved for HackOlympians attendees. + Yes! Cash prizes will be offered for winning teams in + several different categories, including{" "} + + HackOlympians + + . Additionally, there are various mini-games and events that + offer plenty of opportunities to win prizes through our + Point Shop!

- - ) - } -]; - -const faqDataWithoutLinks = [ - { - question: What is a Hackathon?, - answer: ( -

- A hackathon is a collaborative event where teams utilize their - skills to create projects that solve problems or identify new - opportunities! They typically run for a short and continuous - period of time. For Hacklllinois, meals will be provided. -

- ) - }, - { - question: Are there any prizes or incentives?, - answer: ( -

- Yes! Cash prizes will be offered for winning teams in several - different categories, including{" "} - - HackOlympians - - . Additionally, there are various mini-games and events that - offer plenty of opportunities to win prizes through our Point - Shop! -

- ) - }, - { - question: ( - - What is HackOlympians? - - ), - answer: ( -

- - HackOlympians - {" "} - is an exclusive path tailored for prospective attendees to dive - into a competitively elevated hackathon atmosphere for an - increased prize value. It's a specialized arena for - experienced hackers who have mastered the fundamentals and are - now looking to test their skills in a more challenging - environment. Admission into HackOlympians requires completing - our application, which includes a coding challenge . -

- ) - }, - { - question: ( - What are the benefits of being a HackOlympian? - ), - answer: ( -

- Attendees in this path have the exclusive opportunity to compete - for the grand Olympians prize. Additionally, they will gain - access to special networking opportunities with our event - sponsors and the chance to present their project in a thrilling - Shark-Tank inspired showcase, among other exciting perks - but - spots are limited, so register soon! -

- ) - }, - { - question: ( - - How is HackOlympians different from standard HackIllinois - attendance? - - ), - answer: ( - <> + ) + }, + { + question: ( + + What is HackOlympians? + + ), + answer: (

- HackIllinois is a historically welcoming space for coders of - all skill levels, particularly those who are just starting - out. This inclusive environment encourages beginner-level - coders to engage and learn, while HackOlympians caters to - more advanced participants, fostering a competitive and - stimulating atmosphere for seasoned hackers. All attendees - from both paths will enjoy access to Hacklllinois's - vibrant array of events, workshops, company Q&As, and the - Company Expo. Each path will maintain the spirit of - inclusivity and learning to ensure that all attendees, - regardless of their track, experience the full magic of - HackIllinois! Additionally, all HackIllinois attendees are - eligible to compete in all our sponsored tracks.* + + HackOlympians + {" "} + is an exclusive path tailored for prospective attendees to + dive into a competitively elevated hackathon atmosphere for + an increased prize value. It's a specialized arena for + experienced hackers who have mastered the fundamentals and + are now looking to test their skills in a more challenging + environment. Admission into HackOlympians requires + completing our application, which includes a{" "} + {eventStatus === "registration" ? ( + + coding challenge + + ) : ( + "coding challenge" + )} + .

-
+ ) + }, + { + question: ( + What are the benefits of being a HackOlympian? + ), + answer: (

- *The Best Beginner and General prizes are reserved for - HackIllinois General attendees, while the Best Olympians - prize is reserved for HackOlympians attendees. + Attendees in this path have the exclusive opportunity to + compete for the grand Olympians prize. Additionally, they + will gain access to special networking opportunities with + our event sponsors and the chance to present their project + in a thrilling Shark-Tank inspired showcase, among other + exciting perks - but spots are limited, so register soon!

- - ) - } -]; - -const FAQ: React.FC = () => { - const [currentPage, setCurrentPage] = useState(0); - const [windowWidth, setWindowWidth] = useState(0); - const [registrationOpen, setRegistrationOpen] = useState(false); - useEffect(() => { - getRegistrationStatus().then(status => { - setRegistrationOpen(status.alive); - }); - }, []); + ) + }, + { + question: ( + + How is HackOlympians different from standard HackIllinois + attendance? + + ), + answer: ( + <> +

+ HackIllinois is a historically welcoming space for + coders of all skill levels, particularly those who are + just starting out. This inclusive environment encourages + beginner-level coders to engage and learn, while + HackOlympians caters to more advanced participants, + fostering a competitive and stimulating atmosphere for + seasoned hackers. All attendees from both paths will + enjoy access to Hacklllinois's vibrant array of + events, workshops, company Q&As, and the Company Expo. + Each path will maintain the spirit of inclusivity and + learning to ensure that all attendees, regardless of + their track, experience the full magic of HackIllinois! + Additionally, all HackIllinois attendees are eligible to + compete in all our sponsored tracks.* +

+
+

+ *The Best Beginner and General prizes are reserved for + HackIllinois General attendees, while the Best Olympians + prize is reserved for HackOlympians attendees. +

+ + ) + } + ]; useEffect(() => { const handleResize = () => { @@ -235,10 +138,10 @@ const FAQ: React.FC = () => { } else if (windowWidth < 1350) { return 3; } else { - return faqDataWithLinks.length; + return faqData.length; } - }, [windowWidth, faqDataWithLinks]); - const totalPages = Math.ceil(faqDataWithLinks.length / faqsPerPage); + }, [windowWidth, faqData]); + const totalPages = Math.ceil(faqData.length / faqsPerPage); const showArrows = totalPages > 1; const navigatePage = (direction: number) => { @@ -247,15 +150,10 @@ const FAQ: React.FC = () => { ); }; - const currentFAQs = registrationOpen - ? faqDataWithLinks.slice( - currentPage * faqsPerPage, - (currentPage + 1) * faqsPerPage - ) - : faqDataWithoutLinks.slice( - currentPage * faqsPerPage, - (currentPage + 1) * faqsPerPage - ); + const currentFAQs = faqData.slice( + currentPage * faqsPerPage, + (currentPage + 1) * faqsPerPage + ); return (
diff --git a/components/Home/Olympian/Olympian.tsx b/components/Home/Olympian/Olympian.tsx index 961f7e45..f991b083 100644 --- a/components/Home/Olympian/Olympian.tsx +++ b/components/Home/Olympian/Olympian.tsx @@ -1,21 +1,28 @@ "use client"; import styles from "./Olympian.module.scss"; -import { useEffect, useState } from "react"; -import { getRegistrationStatus } from "@/util/api"; +import { useContext } from "react"; import Image from "next/image"; import LOGO from "@/public/home/olympian/logo.svg"; import BACKGROUND from "@/public/home/olympian/background.svg"; import OlympianButton from "@/components/OlympianButton/OlympianButton"; import Description from "../Description/Description"; +import GlobalContext from "@/app/context"; const Olympian: React.FC = () => { - const [registrationOpen, setRegistrationOpen] = useState(true); - useEffect(() => { - getRegistrationStatus().then(status => { - setRegistrationOpen(status.alive); - }); - }, []); + const { eventStatus } = useContext(GlobalContext); + + const getButtonData = () => { + switch (eventStatus) { + case "registration": + return { text: "Register Now", link: "/register" }; + case "admission": + return { text: "Profile", link: "/profile" }; + case "loading": + return { text: "Loading", link: "#" }; + } + }; + return (
@@ -24,11 +31,7 @@ const Olympian: React.FC = () => { src={LOGO} className={styles.logo} /> - +
background { + const { eventStatus } = useContext(GlobalContext); const [showMobileNavbar, setShowMobileNavbar] = useState(false); const menuRef = useRef(null); const buttonRef = useRef(null); @@ -36,6 +27,25 @@ const Navbar = () => { const isDark = DARK_PAGES.includes(pathname); + const getDynamicNavItems = () => { + switch (eventStatus) { + case "registration": + return [{ title: "Register", link: "/register" }]; + case "admission": + return [{ title: "Profile", link: "/profile" }]; + default: + return []; + } + }; + + const navbarItems: NavbarItem[] = [ + ...getDynamicNavItems(), + { + title: "Legal", + link: "/legal" + } + ]; + useEffect(() => { function handleClickOutside(event: MouseEvent) { if ( @@ -69,7 +79,7 @@ const Navbar = () => { />
    - {NAVBAR_ITEMS.map(item => ( + {navbarItems.map(item => (
  • { )} ref={menuRef} > - {NAVBAR_ITEMS.map(item => ( + {navbarItems.map(item => ( (false); + const [isLoading, setIsLoading] = useState(true); + + function getValue(): GlobalContextType { + if (isLoading) { + return { eventStatus: "loading" }; + } + + if (isRegistrationOpen) { + return { eventStatus: "registration" }; + } + + return { eventStatus: "admission" }; + } + + useEffect(() => { + getRegistrationStatus().then(({ alive }) => { + setIsRegistrationOpen(alive); + setIsLoading(false); + }); + }, []); + + return ( + + + {children} + + ); +}