Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"use client";

import { useState } from "react";
import Link from "next/link";

import { Button } from "@forge/ui/button";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@forge/ui/dialog";

import { TacoTuesday } from "../discord-modal";

interface DashboardHackathon {
applicationsOpen: boolean;
displayName: string;
isLive: boolean;
name: string;
}
Comment on lines +19 to +24

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we redefining this


export function DashboardEntryDialogs({
currentHackathon,
hasHacker,
hasMember,
showDiscordPrompt,
}: {
currentHackathon: DashboardHackathon | null;
hasHacker: boolean;
hasMember: boolean;
showDiscordPrompt: boolean;
}) {
const [routingOpen, setRoutingOpen] = useState(currentHackathon != null);

const hackathonAction = hasHacker
? `Open ${currentHackathon?.displayName ?? "Hackathon"} Dashboard`
: currentHackathon?.applicationsOpen
? `Register for ${currentHackathon.displayName}`
: `View ${currentHackathon?.displayName ?? "Hackathon"}`;
const memberAction = hasMember
? "Continue to Member Dashboard"
: "Explore Knight Hacks Membership";

return (
<>
{currentHackathon && (
<Dialog open={routingOpen} onOpenChange={setRoutingOpen}>
<DialogContent className="max-h-[calc(100svh-2rem)] w-[calc(100%-2rem)] overflow-x-hidden sm:max-w-lg">
<DialogHeader className="min-w-0 pr-6">
<DialogTitle>
{currentHackathon.displayName} is{" "}
{currentHackathon.isLive ? "live" : "coming up"}
</DialogTitle>
<DialogDescription className="break-words">
{hasHacker
? `You have a ${currentHackathon.displayName} application. Choose which dashboard you want to open.`
: `Choose whether you are here for ${currentHackathon.displayName} or year-round Knight Hacks membership.`}
</DialogDescription>
</DialogHeader>
<DialogFooter className="gap-2 sm:items-stretch sm:space-x-0">
<DialogClose asChild>
<Button
variant="outline"
className="h-auto min-h-9 w-full whitespace-normal px-3 py-2 text-center leading-snug sm:min-w-0 sm:flex-1"
>
{memberAction}
</Button>
</DialogClose>
<Button
asChild
className="h-auto min-h-9 w-full whitespace-normal px-3 py-2 text-center leading-snug sm:min-w-0 sm:flex-1"
>
<Link href={`/hackathon/${currentHackathon.name}`}>
{hackathonAction}
</Link>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)}

{!routingOpen && showDiscordPrompt && <TacoTuesday initialState={true} />}
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,57 @@ export default async function HackerDashboard({
hackathon: SelectHackathon;
hacker: Awaited<ReturnType<(typeof serverCall.hackerQuery)["getHacker"]>>;
}) {
const [resume, pastHackathons] = await Promise.allSettled([
api.resume.getResume(),
api.hackathon.getPastHackathons(),
]);

if (!hacker) {
const now = new Date();

if (now < hackathon.applicationOpen) {
const applicationOpen = new Intl.DateTimeFormat("en-US", {
dateStyle: "long",
timeZone: "America/New_York",
}).format(hackathon.applicationOpen);

return (
<div className="flex flex-col items-center justify-center gap-y-3 text-center">
<p className="text-2xl font-semibold">
Applications for {hackathon.displayName} open on {applicationOpen}.
</p>
<p className="text-muted-foreground">
Check back then to submit your hacker application.
</p>
</div>
);
}

if (now > hackathon.applicationDeadline) {
return (
<div className="flex flex-col items-center justify-center gap-y-3 text-center">
<p className="text-2xl font-semibold">
Applications for {hackathon.displayName} are closed.
</p>
<p className="text-muted-foreground">
Existing applicants can still view their application status here.
</p>
</div>
);
}

return (
<div className="flex flex-col items-center justify-center gap-y-6 text-xl font-semibold">
<p className="w-full max-w-xl text-center text-2xl">
Register for {hackathon.displayName} today!
</p>
<div className="flex flex-wrap justify-center gap-5">
{
//if there is no current hackathon then this page is never rendered anyway
<HackerAppCard hackathonName={hackathon.name} />
}
<HackerAppCard hackathonName={hackathon.name} />
</div>
</div>
);
}

const [resume, pastHackathons] = await Promise.allSettled([
api.resume.getResume(),
api.hackathon.getPastHackathons(),
]);

return (
<>
<div className="animate-mobile-initial-expand relative mx-auto flex h-0 bg-[#E5E7EB] dark:bg-[#0A0F1D] sm:py-0 sm:pb-0 lg:max-h-56">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -920,9 +920,9 @@ export function HackerFormPage({

existingApplicationRedirectedRef.current = true;
toast.info("You already submitted an application for this hackathon.");
router.replace("/dashboard");
router.replace(`/hackathon/${hackathonId}`);
router.refresh();
}, [applicationSubmitted, existingApplication, router]);
}, [applicationSubmitted, existingApplication, hackathonId, router]);

useEffect(() => {
if (prefillAppliedRef.current) return;
Expand Down Expand Up @@ -1200,7 +1200,7 @@ export function HackerFormPage({
toast.info(
"You already submitted an application for this hackathon.",
);
router.push("/dashboard");
router.push(`/hackathon/${hackathonId}`);
router.refresh();
setLoading(false);
return;
Expand Down Expand Up @@ -1298,13 +1298,14 @@ export function HackerFormPage({
asChild
className="h-12 rounded-full bg-white px-6 text-base font-black text-[#21103d] shadow-[0_18px_46px_rgba(0,0,0,0.42)] hover:bg-white/90"
>
<Link href="/dashboard">
Go to dashboard
<Link href={`/hackathon/${hackathonId}`}>
View {hackathonName} dashboard
<ArrowRight className="ml-2 size-4" />
</Link>
</Button>
<p className="text-sm font-semibold text-white/55">
Your dashboard will show your current application status.
Your hackathon dashboard will show your current
application status.
</p>
</div>
</div>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { MemberAppCard } from "~/app/_components/option-cards";
import { api } from "~/trpc/server";
import { AlumniDiscord } from "./AlumniDiscord";
import { AlumniRecap } from "./AlumniRecap";
import { CurrentHackathonNotice } from "./current-hackathon-notice";
import DayInHistory from "./day-in-history";
import EarlyAccessVolunteer from "./early-access-volunteer";
import { EventNumber } from "./event/event-number";
Expand Down Expand Up @@ -84,13 +83,11 @@ export default async function MemberDashboard({

const isAlumni = calcAlumniStatus(member.gradDate, member);

const [eventsValue, dues, hackathonsValue, currentHackathon] =
await Promise.all([
api.member.getEvents(),
api.duesPayment.validatePaidDues(),
isAlumni ? api.hackathon.getPastHackathons() : Promise.resolve([]),
api.hackathon.getCurrentHackathon(),
]);
const [eventsValue, dues, hackathonsValue] = await Promise.all([
api.member.getEvents(),
api.duesPayment.validatePaidDues(),
isAlumni ? api.hackathon.getPastHackathons() : Promise.resolve([]),
]);

const duesPaid = dues.duesPaid;

Expand All @@ -103,11 +100,6 @@ export default async function MemberDashboard({
return (
<div className="flex-col md:flex">
<div className="flex-1 space-y-4">
{currentHackathon && (
<CurrentHackathonNotice
hackathonDisplayName={currentHackathon.displayName}
/>
)}
{/* Unified View */}
<div className="animate-mobile-initial-expand space-y-4">
<div className="grid grid-cols-1 gap-4 md:h-[800px] md:grid-cols-3">
Expand Down Expand Up @@ -139,11 +131,6 @@ export default async function MemberDashboard({
return (
<div className="flex-col md:flex">
<div className="flex-1 space-y-4">
{currentHackathon && (
<CurrentHackathonNotice
hackathonDisplayName={currentHackathon.displayName}
/>
)}
{/* Unified View */}
<div className="animate-mobile-initial-expand space-y-4">
<div className="animate-fade-in grid gap-4 md:grid-cols-2 lg:grid-cols-4">
Expand Down
10 changes: 6 additions & 4 deletions apps/blade/src/app/_components/user-interface.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import type { api as serverCaller } from "~/trpc/server";
import MemberDashboard from "~/app/_components/dashboard/member-dashboard/member-dashboard";
import { MemberAppCard } from "~/app/_components/option-cards";
import { api } from "~/trpc/server";

export async function UserInterface() {
const member = await api.member.getMember();

export function UserInterface({
member,
}: {
member: Awaited<ReturnType<(typeof serverCaller.member)["getMember"]>>;
}) {
if (!member) {
return (
<div className="flex flex-col items-center justify-center gap-y-6 font-bold">
Expand Down
33 changes: 29 additions & 4 deletions apps/blade/src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { redirect } from "next/navigation";

import { auth } from "@forge/auth";

import { TacoTuesday } from "~/app/_components/discord-modal";
import { DashboardEntryDialogs } from "~/app/_components/dashboard/dashboard-entry-dialogs";
import { SessionNavbar } from "~/app/_components/navigation/session-navbar";
import { UserInterface } from "~/app/_components/user-interface";
import { api, HydrateClient } from "~/trpc/server";
Expand All @@ -15,18 +15,43 @@ export const metadata: Metadata = {

export default async function Dashboard() {
const session = await auth();
const isMember = await api.auth.getDiscordMemberStatus();

if (!session) {
redirect("/");
}

const [isDiscordMember, member, currentHackathon] = await Promise.all([
api.auth.getDiscordMemberStatus(),
api.member.getMember(),
api.hackathon.getCurrentHackathon(),
]);
const hacker = currentHackathon
? await api.hackerQuery.getHacker({
hackathonName: currentHackathon.name,
})
: null;
const now = new Date();

return (
<HydrateClient>
<SessionNavbar />
<main className="container h-screen py-16">
<TacoTuesday initialState={!isMember} />
<UserInterface />
<DashboardEntryDialogs
currentHackathon={
currentHackathon
? {
applicationsOpen: currentHackathon.applicationDeadline >= now,
displayName: currentHackathon.displayName,
isLive: currentHackathon.startDate <= now,
name: currentHackathon.name,
}
: null
}
hasHacker={hacker != null}
hasMember={member != null}
showDiscordPrompt={!isDiscordMember}
/>
<UserInterface member={member} />
</main>
</HydrateClient>
);
Expand Down
Loading
Loading