Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions apps/site/src/app/(home)/sections/GetInvolved/GetInvolved.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
"use client";

import Image from "next/image";

import Container from "react-bootstrap/Container";
import Button from "react-bootstrap/Button";
import anteater_left from "@/assets/images/involved_anteater_left.png";
Expand Down Expand Up @@ -40,7 +43,7 @@ const GetInvolved = () => {
</div>
</div>
<div className={styles.anteaterContainerLeft}>
<img
<Image
className={styles.anteaterImage}
src={anteater_left.src}
alt="A cartoon anteater sitting on a ring buoy coding"
Expand All @@ -55,7 +58,7 @@ const GetInvolved = () => {
</div>
</div>
<div className={styles.anteaterContainerRight}>
<img
<Image
className={styles.anteaterImage}
src={anteater_right.src}
alt="A cartoon anteater captain sitting on a ring buoy"
Expand Down
5 changes: 5 additions & 0 deletions apps/site/src/app/confirmation/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import ConfirmationPage from "./ConfirmationPage";

export default function Confirmation() {
return <ConfirmationPage />;
}
35 changes: 35 additions & 0 deletions apps/site/src/app/portal/ApplicantPortal.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@use "zothacks-theme" as theme;

.container {
Comment thread
noahk004 marked this conversation as resolved.
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2rem;
Comment thread
noahk004 marked this conversation as resolved.
background: url("~@/assets/background/mountains-background.png");
font-family: var(--next-font-reddit-mono), monospace;
padding: 150px 0 100px 0;

* {
font-weight: 600;
}

h1 {
color: theme.$white;
font-size: 4rem;
}

p {
font-weight: 400;
letter-spacing: 1px;
}

.wrapper {
max-width: 600px;
margin: 0 40px;
display: flex;
flex-direction: column;
gap: 16px;
}
}
23 changes: 18 additions & 5 deletions apps/site/src/app/portal/ApplicantPortal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { redirect } from "next/navigation";

import useUserIdentity from "@/lib/utils/useUserIdentity";
import { Status } from "@/lib/userRecord";
import Message from "./components/Message";
import ActionButton from "./components/ActionButton";
import Timeline from "./components/Timeline";

import ConfirmationPage from "./ConfirmationPage";

const rolesArray = ["Mentor", "Hacker", "Volunteer"];
import styles from "./ApplicantPortal.module.scss";

function Portal() {
const identity = useUserIdentity();
Expand All @@ -16,12 +17,24 @@ function Portal() {
return <div>Loading...</div>;
}

const status = identity.status;
const status = identity.status as Status;

if (status === null) {
redirect("/apply");
} else {
return <ConfirmationPage />;
return (
<div className={styles.container}>
<h1>Portal</h1>

<div className={styles.wrapper}>
<Timeline status={status} />

<Message status={status} />

<ActionButton status={status} />
</div>
</div>
);
}
}

Expand Down
41 changes: 41 additions & 0 deletions apps/site/src/app/portal/components/ActionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Status } from "@/lib/userRecord";
import PrimaryButton from "@/components/PrimaryButton/PrimaryButton";

interface ActionButtonProps {
status: Status;
}

export default function ActionButton({ status }: ActionButtonProps) {
let buttonJSX: JSX.Element;

switch (status) {
case Status.Rejected:
case Status.Void:
case Status.Pending:
case Status.Reviewed:
case Status.Accepted:
case Status.Waitlisted:
case Status.Signed:
case Status.Confirmed:
case Status.Attending: {
buttonJSX = (
<PrimaryButton variant="large" href="/">
Return to Homepage
</PrimaryButton>
);
break;
}

// case Status.Waitlisted: {
// buttonJSX = <button className={styles.actionButton}>I am no longer able to attend ZotHacks 2025</button>;
// break;
// }

default: {
const exhaustiveCheck: never = status;
throw new Error(`Unhandled status: ${exhaustiveCheck}`);
}
}

return buttonJSX;
}
18 changes: 18 additions & 0 deletions apps/site/src/app/portal/components/Message.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@use "zothacks-theme" as theme;

.messageWrapper {
display: flex;
flex-direction: column;
gap: 8px;
color: theme.$white;
margin-top: 32px;

p {
font-size: 1.1rem;
}

h4 {
font-size: 1.5rem;
margin-bottom: 0;
}
}
73 changes: 73 additions & 0 deletions apps/site/src/app/portal/components/Message.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Status } from "@/lib/userRecord";
import styles from "./Message.module.scss";

interface MessageProps {
status: Status;
}

export default function Message({ status }: MessageProps) {
let message: string;
let header: string;

switch (status) {
case Status.Pending:
case Status.Reviewed: {
header = "";
message = `Thank you for submitting your application! We are currently reviewing
Comment thread
IanWearsHat marked this conversation as resolved.
applications on a rolling basis, and you will hear back from us soon!`;
break;
}

case Status.Accepted: {
header = "Congratulations!";
message = `Congratulations! You have been admitted to ZotHacks 2025! Please check
your email to sign your waiver and confirm your attendance!`;
break;
}
case Status.Waitlisted: {
header = "RSVP";
message = `Thank you for applying to ZotHacks this year. We have read through
many applications so far, and are able to offer you a spot on the
event waitlist. Please check your email for more info about the
waitlist and waitlist walk-ins!`;
break;
}
case Status.Rejected: {
header = "Sorry...";
message = `Thank you for applying to ZotHacks this year. We have read through
many applications so far, and unfortunately are unable to offer you a
spot at our event. We highly encourage you to continue developing your
skills and passion for technology. We would love to see you apply
again next year!`;
break;
}

case Status.Signed:
case Status.Confirmed:
case Status.Attending: {
header = "";
message = ``;
break;
}

case Status.Void: {
header = "";
message = `Unfortunately, you are not able to RSVP for IrvineHacks at this time
and will not be able to come to the event. However, we would love to
see you apply again next year!`;
break;
}

default: {
const exhaustiveCheck: never = status;
throw new Error(`Unhandled status: ${exhaustiveCheck}`);
}
}

return (
<div className={styles.messageWrapper}>
<h4>{header}</h4>
<p>{message}</p>
</div>
);
}
30 changes: 30 additions & 0 deletions apps/site/src/app/portal/components/StatusIndicator.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@use "zothacks-theme" as theme;

.dark {
background-color: rgba(theme.$dark-green, 0.69);
}

.light {
background-color: rgba(theme.$light-green, 0.69);
}

.indicator {
border: 5px solid theme.$dark-green;
border-radius: 30px;
padding: 30px 40px;
width: 100%;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 1.3rem;
color: theme.$off-white;

p {
margin: 0;
}
}

.icon {
margin-left: 30px;
}
23 changes: 23 additions & 0 deletions apps/site/src/app/portal/components/StatusIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Image, { StaticImageData } from "next/image";
import styles from "./StatusIndicator.module.scss";

interface StatusIndicatorProps {
icon: StaticImageData;
dark: boolean;
children: React.ReactNode;
}

export default function StatusIndicator({
icon,
dark,
children,
}: StatusIndicatorProps) {
return (
<div
className={styles.indicator + " " + (dark ? styles.dark : styles.light)}
>
<p>{children}</p>
<Image src={icon} className={styles.icon} alt="Status icon" />
</div>
);
}
13 changes: 13 additions & 0 deletions apps/site/src/app/portal/components/Timeline.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@use "zothacks-theme" as theme;

.statusWrapper {
display: flex;
flex-direction: column;
gap: 16px;
width: 100%;

h2 {
font-size: 2.5rem;
color: theme.$white;
}
}
57 changes: 57 additions & 0 deletions apps/site/src/app/portal/components/Timeline.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Status, Decision } from "@/lib/userRecord";
import StatusIndicator from "./StatusIndicator";

import check from "@/assets/icons/check.svg";
import dots from "@/assets/icons/dots.svg";
import x from "@/assets/icons/x.svg";

import styles from "./Timeline.module.scss";

interface TimelineProps {
status: Status;
}

export default function Timeline({ status }: TimelineProps) {
return (
<div className={styles.statusWrapper}>
{(Object.values(Decision).includes(status as Decision) ||
status === Status.Signed ||
status === Status.Confirmed) && (
<StatusIndicator icon={check} dark={true}>
Application Submitted
</StatusIndicator>
)}

{(status === Status.Accepted ||
status === Status.Signed ||
status === Status.Confirmed) && (
<>
<StatusIndicator icon={check} dark={true}>
Application Accepted
</StatusIndicator>
<StatusIndicator
icon={dots}
dark={status === Status.Signed || status === Status.Confirmed}
>
Waiver Signed
</StatusIndicator>
<StatusIndicator icon={dots} dark={status === Status.Confirmed}>
Attendance Confirmed
</StatusIndicator>
</>
)}

{status === Status.Waitlisted && (
<StatusIndicator icon={dots} dark={true}>
Waitlisted
</StatusIndicator>
)}

{status === Status.Rejected && (
<StatusIndicator icon={x} dark={true}>
Application Rejected
</StatusIndicator>
)}
</div>
);
}
3 changes: 3 additions & 0 deletions apps/site/src/assets/icons/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions apps/site/src/assets/icons/dots.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions apps/site/src/assets/icons/x.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading