From 412febe086e245167830429dd5947f2cbc46221f Mon Sep 17 00:00:00 2001 From: DVidal1205 Date: Fri, 3 Jul 2026 14:03:11 -0700 Subject: [PATCH 01/10] feat: move bloom participant flows out of blade Co-authored-by: Madu --- .env.example | 3 +- .../hackathon/manage/hackathon-manager.tsx | 114 +- .../dashboard/dashboard-entry-dialogs.tsx | 89 - .../hackathon-dashboard/components.tsx | 88 - .../hackathon-dashboard/countdown.tsx | 127 - .../hackathon-dashboard/hackathon-data.tsx | 137 - .../hackathon-dashboard/issue-dialog.tsx | 96 - .../hackathon-dashboard/upcoming-events.tsx | 96 - .../hacker-dashboard/confirm-button.tsx | 112 - .../hacker-dashboard/hacker-dashboard.tsx | 121 - .../hacker-dashboard/hacker-data.tsx | 307 -- .../hacker-dashboard/hacker-qr-button.tsx | 108 - .../hacker-dashboard/hacker-resume-button.tsx | 30 - .../hacker-dashboard/past-hackathons.tsx | 114 - .../dashboard/hacker/hackbackgrounds/khix.ts | 456 --- .../hackathon/portal-unavailable.tsx | 24 + .../src/app/_components/option-cards.tsx | 42 +- apps/blade/src/app/_components/providers.tsx | 7 +- .../settings/delete-hacker-button.tsx | 124 - .../app/_components/settings/sidebar-nav.tsx | 22 +- .../_components/theme-toggle-route-guard.tsx | 20 - apps/blade/src/app/dashboard/page.tsx | 28 +- apps/blade/src/app/hackathon/README.md | 156 +- apps/blade/src/app/hackathon/[slug]/page.tsx | 61 +- .../src/app/hackathon/bloomknights/page.tsx | 51 - apps/blade/src/app/hackathon/page.tsx | 47 +- .../application/[hackathon-id]/page.tsx | 106 +- .../src/app/settings/hacker-profile/page.tsx | 79 +- apps/blade/src/app/settings/page.tsx | 5 - apps/blade/src/consts/index.ts | 4 - apps/blade/src/lib/hackathon-portal.ts | 30 + apps/bloomknights/next.config.js | 14 +- apps/bloomknights/package.json | 5 + .../src/app/(marketing)/layout.tsx | 41 + .../src/app/{ => (marketing)}/page.tsx | 16 +- .../hackbackgrounds/bloomknights.ts | 0 .../application}/hackbackgrounds/index.ts | 30 +- .../application}/hackbackgrounds/types.ts | 0 .../hacker-application-background.tsx | 0 .../application}/hacker-application-form.tsx | 467 +-- .../app/(portal)/_components/auth-retry.tsx | 31 + .../(portal)/_components/bloom-dashboard.tsx | 446 +++ .../bloomknights-action-blooms.tsx | 367 +++ .../bloomknights-ambient-background.tsx | 102 + .../bloomknights-dashboard-logo.tsx | 23 + .../bloomknights-dashboard-shell.tsx | 126 + .../bloomknights-flower-cursor.tsx | 204 ++ .../_components}/hacker-profile-form.tsx | 222 +- .../(portal)/_components/portal-header.tsx | 31 + .../src/app/(portal)/apply/page.tsx | 69 + .../src/app/(portal)/dashboard/page.tsx | 32 + .../app/(portal)/dashboard/profile/page.tsx | 47 + .../hacker/application/bloomknights/page.tsx | 5 + apps/bloomknights/src/app/(portal)/layout.tsx | 15 + .../src/app/_components/navbar/NavContent.tsx | 28 + .../src/app/_components/navbar/Navbar.tsx | 18 +- .../_components/register/registerButton.tsx | 7 +- .../src/app/api/auth/[...all]/route.ts | 3 + .../src/app/api/auth/signin/route.ts | 1 + .../src/app/api/trpc/[trpc]/route.ts | 31 + apps/bloomknights/src/app/layout.tsx | 35 +- apps/bloomknights/src/auth/client.ts | 9 + apps/bloomknights/src/auth/server.ts | 10 + apps/bloomknights/src/env.ts | 25 + apps/bloomknights/src/lib/portal-config.ts | 17 + docs/API-AND-PERMISSIONS.md | 12 + docs/ARCHITECTURE.md | 49 +- packages/api/package.json | 4 + packages/api/src/minio/minio-client.ts | 8 +- packages/api/src/participant-contract.ts | 94 + packages/api/src/participant.ts | 41 + packages/api/src/resume-storage.ts | 8 +- packages/api/src/routers/hackathon.ts | 6 + packages/api/src/routers/hackers/mutations.ts | 31 +- .../api/src/routers/participant-portal.ts | 545 ++++ packages/api/src/storage-env.ts | 14 + packages/api/src/trpc.ts | 5 +- packages/auth/package.json | 3 + packages/auth/src/callback-url.ts | 20 +- packages/auth/src/client-factory.ts | 69 + packages/auth/src/config.ts | 123 - packages/auth/src/env.ts | 21 +- packages/auth/src/factory.ts | 113 + packages/auth/src/index.rsc.ts | 100 +- packages/auth/src/index.ts | 42 +- packages/auth/src/server-factory.ts | 115 + packages/auth/src/shared-env.ts | 20 + .../0010_wooden_supreme_intelligence.sql | 7 + packages/db/drizzle/meta/0010_snapshot.json | 2786 +++++++++++++++++ packages/db/drizzle/meta/_journal.json | 7 + packages/db/src/schemas/knight-hacks.ts | 2 + packages/hackathon/README.md | 51 + packages/hackathon/eslint.config.js | 4 + packages/hackathon/package.json | 43 + packages/hackathon/src/application-schema.ts | 337 ++ packages/hackathon/src/client.tsx | 328 ++ packages/hackathon/src/config.ts | 78 + packages/hackathon/src/index.ts | 3 + packages/hackathon/src/lifecycle.ts | 60 + packages/hackathon/src/query-client.ts | 20 + packages/hackathon/src/server.ts | 15 + packages/hackathon/src/types.ts | 18 + packages/hackathon/tsconfig.json | 9 + packages/utils/src/discord-env.ts | 9 + packages/utils/src/discord.ts | 6 +- packages/utils/src/google-env.ts | 12 + packages/utils/src/google.ts | 9 +- packages/utils/src/stripe-env.ts | 9 + packages/utils/src/stripe.ts | 6 +- packages/validators/package.json | 1 + packages/validators/src/hackathons.ts | 45 + packages/validators/src/hacker.ts | 41 + packages/validators/src/index.ts | 1 + pnpm-lock.yaml | 70 + turbo.json | 3 +- 115 files changed, 7157 insertions(+), 3547 deletions(-) delete mode 100644 apps/blade/src/app/_components/dashboard/dashboard-entry-dialogs.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hackathon-dashboard/components.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hackathon-dashboard/countdown.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hackathon-dashboard/issue-dialog.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hackathon-dashboard/upcoming-events.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hacker-dashboard/confirm-button.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-dashboard.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-data.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-qr-button.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-resume-button.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hacker-dashboard/past-hackathons.tsx delete mode 100644 apps/blade/src/app/_components/dashboard/hacker/hackbackgrounds/khix.ts create mode 100644 apps/blade/src/app/_components/hackathon/portal-unavailable.tsx delete mode 100644 apps/blade/src/app/_components/settings/delete-hacker-button.tsx delete mode 100644 apps/blade/src/app/_components/theme-toggle-route-guard.tsx delete mode 100644 apps/blade/src/app/hackathon/bloomknights/page.tsx create mode 100644 apps/blade/src/lib/hackathon-portal.ts create mode 100644 apps/bloomknights/src/app/(marketing)/layout.tsx rename apps/bloomknights/src/app/{ => (marketing)}/page.tsx (91%) rename apps/{blade/src/app/_components/dashboard/hacker => bloomknights/src/app/(portal)/_components/application}/hackbackgrounds/bloomknights.ts (100%) rename apps/{blade/src/app/_components/dashboard/hacker => bloomknights/src/app/(portal)/_components/application}/hackbackgrounds/index.ts (59%) rename apps/{blade/src/app/_components/dashboard/hacker => bloomknights/src/app/(portal)/_components/application}/hackbackgrounds/types.ts (100%) rename apps/{blade/src/app/_components/dashboard/hacker => bloomknights/src/app/(portal)/_components/application}/hacker-application-background.tsx (100%) rename apps/{blade/src/app/_components/dashboard/hacker => bloomknights/src/app/(portal)/_components/application}/hacker-application-form.tsx (85%) create mode 100644 apps/bloomknights/src/app/(portal)/_components/auth-retry.tsx create mode 100644 apps/bloomknights/src/app/(portal)/_components/bloom-dashboard.tsx create mode 100644 apps/bloomknights/src/app/(portal)/_components/bloomknights-action-blooms.tsx create mode 100644 apps/bloomknights/src/app/(portal)/_components/bloomknights-ambient-background.tsx create mode 100644 apps/bloomknights/src/app/(portal)/_components/bloomknights-dashboard-logo.tsx create mode 100644 apps/bloomknights/src/app/(portal)/_components/bloomknights-dashboard-shell.tsx create mode 100644 apps/bloomknights/src/app/(portal)/_components/bloomknights-flower-cursor.tsx rename apps/{blade/src/app/_components/settings => bloomknights/src/app/(portal)/_components}/hacker-profile-form.tsx (83%) create mode 100644 apps/bloomknights/src/app/(portal)/_components/portal-header.tsx create mode 100644 apps/bloomknights/src/app/(portal)/apply/page.tsx create mode 100644 apps/bloomknights/src/app/(portal)/dashboard/page.tsx create mode 100644 apps/bloomknights/src/app/(portal)/dashboard/profile/page.tsx create mode 100644 apps/bloomknights/src/app/(portal)/hacker/application/bloomknights/page.tsx create mode 100644 apps/bloomknights/src/app/(portal)/layout.tsx create mode 100644 apps/bloomknights/src/app/api/auth/[...all]/route.ts create mode 100644 apps/bloomknights/src/app/api/auth/signin/route.ts create mode 100644 apps/bloomknights/src/app/api/trpc/[trpc]/route.ts create mode 100644 apps/bloomknights/src/auth/client.ts create mode 100644 apps/bloomknights/src/auth/server.ts create mode 100644 apps/bloomknights/src/env.ts create mode 100644 apps/bloomknights/src/lib/portal-config.ts create mode 100644 packages/api/src/participant-contract.ts create mode 100644 packages/api/src/participant.ts create mode 100644 packages/api/src/routers/participant-portal.ts create mode 100644 packages/api/src/storage-env.ts create mode 100644 packages/auth/src/client-factory.ts delete mode 100644 packages/auth/src/config.ts create mode 100644 packages/auth/src/factory.ts create mode 100644 packages/auth/src/server-factory.ts create mode 100644 packages/auth/src/shared-env.ts create mode 100644 packages/db/drizzle/0010_wooden_supreme_intelligence.sql create mode 100644 packages/db/drizzle/meta/0010_snapshot.json create mode 100644 packages/hackathon/README.md create mode 100644 packages/hackathon/eslint.config.js create mode 100644 packages/hackathon/package.json create mode 100644 packages/hackathon/src/application-schema.ts create mode 100644 packages/hackathon/src/client.tsx create mode 100644 packages/hackathon/src/config.ts create mode 100644 packages/hackathon/src/index.ts create mode 100644 packages/hackathon/src/lifecycle.ts create mode 100644 packages/hackathon/src/query-client.ts create mode 100644 packages/hackathon/src/server.ts create mode 100644 packages/hackathon/src/types.ts create mode 100644 packages/hackathon/tsconfig.json create mode 100644 packages/utils/src/discord-env.ts create mode 100644 packages/utils/src/google-env.ts create mode 100644 packages/utils/src/stripe-env.ts create mode 100644 packages/validators/src/hacker.ts diff --git a/.env.example b/.env.example index bb272bc96..79544a8e4 100644 --- a/.env.example +++ b/.env.example @@ -35,6 +35,7 @@ MINIO_SECRET_KEY="minioadmin" # Blade URL BLADE_URL="http://localhost:3000" +BLOOMKNIGHTS_URL="http://localhost:3006" # Passkit WWDR_CERT_BASE64="wwdr-cert-b64" @@ -48,4 +49,4 @@ TEAM_IDENTIFIER="team-identifier" LISTMONK_URL="https://localhost/" LISTMONK_USER="ci" LISTMONK_TOKEN="ci" -LISTMONK_FROM_EMAIL="ci@localhost" \ No newline at end of file +LISTMONK_FROM_EMAIL="ci@localhost" diff --git a/apps/blade/src/app/_components/admin/hackathon/manage/hackathon-manager.tsx b/apps/blade/src/app/_components/admin/hackathon/manage/hackathon-manager.tsx index 3b5c8573f..368e14dd1 100644 --- a/apps/blade/src/app/_components/admin/hackathon/manage/hackathon-manager.tsx +++ b/apps/blade/src/app/_components/admin/hackathon/manage/hackathon-manager.tsx @@ -1,7 +1,6 @@ "use client"; import { useState } from "react"; -import Link from "next/link"; import { ExternalLink, Loader2, Pencil, Plus, ShieldCheck } from "lucide-react"; import { z } from "zod"; @@ -55,7 +54,9 @@ import { getHackathonBackgroundIssues, getHackathonDateWindowIssues, getHackathonEmailTemplateIssues, + hackathonConfirmationCapacitySchema, hackathonDisplayNameSchema, + hackathonPortalBaseUrlSchema, hackathonRouteNameSchema, hackathonThemeSchema, } from "@forge/validators"; @@ -105,6 +106,8 @@ const formSchema = z applicationBackgroundKey: hackathonApplicationBackgroundKeySchema, emailTemplateEnabled: z.boolean(), emailTemplateKey: hackathonEmailTemplateKeySchema, + portalBaseUrl: z.string(), + confirmationCapacity: z.string(), applicationOpen: z.string().min(1, "Application open is required."), applicationDeadline: z.string().min(1, "Application deadline is required."), confirmationDeadline: z @@ -119,6 +122,28 @@ const formSchema = z const confirmationDeadline = new Date(values.confirmationDeadline); const startDate = new Date(values.startDate); const endDate = new Date(values.endDate); + const portalResult = hackathonPortalBaseUrlSchema.safeParse( + values.portalBaseUrl, + ); + const capacityResult = hackathonConfirmationCapacitySchema.safeParse( + values.confirmationCapacity, + ); + + if (!portalResult.success) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: portalResult.error.issues[0]?.message ?? "Invalid portal URL.", + path: ["portalBaseUrl"], + }); + } + + if (!capacityResult.success) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: capacityResult.error.issues[0]?.message ?? "Invalid capacity.", + path: ["confirmationCapacity"], + }); + } for (const issue of getHackathonBackgroundIssues(values)) { ctx.addIssue({ @@ -197,6 +222,8 @@ function getDefaultValues( ), emailTemplateEnabled: hackathon.emailTemplateEnabled, emailTemplateKey: getSafeEmailTemplateKey(hackathon.emailTemplateKey), + portalBaseUrl: hackathon.portalBaseUrl ?? "", + confirmationCapacity: hackathon.confirmationCapacity?.toString() ?? "", applicationOpen: toDateTimeLocalValue(hackathon.applicationOpen), applicationDeadline: toDateTimeLocalValue(hackathon.applicationDeadline), confirmationDeadline: toDateTimeLocalValue( @@ -223,6 +250,8 @@ function getDefaultValues( applicationBackgroundKey: DEFAULT_BACKGROUND_KEY, emailTemplateEnabled: false, emailTemplateKey: DEFAULT_EMAIL_TEMPLATE_KEY, + portalBaseUrl: "", + confirmationCapacity: "", applicationOpen: toDateTimeLocalValue(applicationOpen), applicationDeadline: toDateTimeLocalValue(applicationDeadline), confirmationDeadline: toDateTimeLocalValue(confirmationDeadline), @@ -246,6 +275,10 @@ function toMutationPayload(values: HackathonFormValues) { emailTemplateKey: values.emailTemplateEnabled ? (values.emailTemplateKey as EmailTemplateKey | undefined) : null, + portalBaseUrl: hackathonPortalBaseUrlSchema.parse(values.portalBaseUrl), + confirmationCapacity: hackathonConfirmationCapacitySchema.parse( + values.confirmationCapacity, + ), applicationOpen: new Date(values.applicationOpen), applicationDeadline: new Date(values.applicationDeadline), confirmationDeadline: new Date(values.confirmationDeadline), @@ -401,8 +434,15 @@ export function HackathonManager() {
{hackathon.displayName}
- /hacker/application/{hackathon.name} + {hackathon.portalBaseUrl ?? + "No participant portal configured"}
+ {hackathon.confirmationCapacity != null && ( +
+ Capacity:{" "} + {hackathon.confirmationCapacity.toLocaleString()} +
+ )}
@@ -437,12 +477,20 @@ export function HackathonManager() {
- + {hackathon.portalBaseUrl ? ( + + ) : ( + Portal missing + )}
diff --git a/apps/blade/src/app/_components/dashboard/dashboard-entry-dialogs.tsx b/apps/blade/src/app/_components/dashboard/dashboard-entry-dialogs.tsx deleted file mode 100644 index b6f8e7509..000000000 --- a/apps/blade/src/app/_components/dashboard/dashboard-entry-dialogs.tsx +++ /dev/null @@ -1,89 +0,0 @@ -"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; -} - -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 && ( - - - - - {currentHackathon.displayName} is{" "} - {currentHackathon.isLive ? "live" : "coming up"} - - - {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.`} - - - - - - - - - - - )} - - {!routingOpen && showDiscordPrompt && } - - ); -} diff --git a/apps/blade/src/app/_components/dashboard/hackathon-dashboard/components.tsx b/apps/blade/src/app/_components/dashboard/hackathon-dashboard/components.tsx deleted file mode 100644 index c4f4e8c36..000000000 --- a/apps/blade/src/app/_components/dashboard/hackathon-dashboard/components.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import type { SelectHackathon } from "@forge/db/schemas/knight-hacks"; - -import type { api as serverCall } from "~/trpc/server"; -import { HackerAppCard } from "~/app/_components/option-cards"; -import { BaseHackathonCountdown } from "./countdown"; -import { BaseHackathonData } from "./hackathon-data"; -import { BaseHackathonUpcomingEvents } from "./upcoming-events"; - -export { - BaseHackathonGuideButton, - BaseHackathonQRCodeButton, - BaseHackathonWalletButton, -} from "./hackathon-data"; -export { BaseHackathonCountdown } from "./countdown"; -export * from "./issue-dialog"; -export { BaseHackathonUpcomingEvents } from "./upcoming-events"; - -const DEFAULT_HACKER_GUIDE_HREF = - "https://knight-hacks.notion.site/knight-hacks-viii"; - -export function BaseHackathonRegistrationPrompt({ - hackathon, -}: { - hackathon: SelectHackathon; -}) { - return ( -
-

- Register for {hackathon.displayName} today! -

-
- -
-
- ); -} - -export function BaseHackathonDashboard({ - guideHref = DEFAULT_HACKER_GUIDE_HREF, - hackathon, - hacker, -}: { - guideHref?: string; - hackathon: SelectHackathon; - hacker: Awaited>; -}) { - if (!hacker) { - return ; - } - - return ( - <> -
- - -
- -
- -
-
-
- -
-
-
- -
-
-
- -
-
- -
- - ); -} diff --git a/apps/blade/src/app/_components/dashboard/hackathon-dashboard/countdown.tsx b/apps/blade/src/app/_components/dashboard/hackathon-dashboard/countdown.tsx deleted file mode 100644 index 3bab0cd08..000000000 --- a/apps/blade/src/app/_components/dashboard/hackathon-dashboard/countdown.tsx +++ /dev/null @@ -1,127 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; - -import { Card, CardContent } from "@forge/ui/card"; - -export function BaseHackathonCountdown({ endDate }: { endDate: Date }) { - const [timeLeft, setTimeLeft] = useState({ - days: 0, - hours: 0, - minutes: 0, - seconds: 0, - }); - - useEffect(() => { - const targetDate = endDate.getTime(); - - const updateCountdown = () => { - const now = new Date().getTime(); - const distance = targetDate - now; - - if (distance < 0) { - setTimeLeft({ days: 0, hours: 0, minutes: 0, seconds: 0 }); - return; - } - - const days = Math.floor(distance / (1000 * 60 * 60 * 24)); - const hours = Math.floor( - (distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60), - ); - const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); - const seconds = Math.floor((distance % (1000 * 60)) / 1000); - - setTimeLeft({ days, hours, minutes, seconds }); - }; - - updateCountdown(); - const interval = setInterval(updateCountdown, 1000); - - return () => clearInterval(interval); - }, [endDate]); - - const formatNumber = (num: number) => String(num).padStart(2, "0"); - - return ( -
- - -

- HACKING ENDS IN -

- -
- {/* Days */} -
- - -
- {formatNumber(timeLeft.days)} -
-
- Days -
-
- D -
-
-
-
:
-
- - {/* Hours */} -
- - -
- {formatNumber(timeLeft.hours)} -
-
- Hours -
-
- H -
-
-
-
:
-
- - {/* Minutes */} -
- - -
- {formatNumber(timeLeft.minutes)} -
-
- Minutes -
-
- M -
-
-
-
:
-
- - {/* Seconds */} - - -
- {formatNumber(timeLeft.seconds)} -
-
- Seconds -
-
- S -
-
-
-
-
-
-
- ); -} diff --git a/apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx b/apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx deleted file mode 100644 index 5b2f6f9de..000000000 --- a/apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx +++ /dev/null @@ -1,137 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { BookOpen, CircleCheckBig } from "lucide-react"; - -import type { SelectHackathon } from "@forge/db/schemas/knight-hacks"; -import { Button } from "@forge/ui/button"; - -import type { api as serverCall } from "~/trpc/server"; -import { HackerQRCodePopup } from "~/app/_components/dashboard/hacker-dashboard/hacker-qr-button"; -import { DownloadQRPass } from "~/app/_components/dashboard/member-dashboard/download-qr-pass"; -import { HACKER_STATUS_MAP } from "~/consts"; -import { api } from "~/trpc/react"; -import { BaseHackathonIssueButton } from "./issue-dialog"; - -type HackerProfile = Awaited< - ReturnType<(typeof serverCall.hackerQuery)["getHacker"]> ->; - -export function BaseHackathonQRCodeButton() { - return ; -} - -export function BaseHackathonWalletButton({ - profile, -}: { - profile: HackerProfile; -}) { - return ( - - ); -} - -export function BaseHackathonGuideButton({ href }: { href: string }) { - return ( - - ); -} - -export function BaseHackathonData({ - data, - guideHref, - hackathon, -}: { - data: HackerProfile; - guideHref: string; - hackathon: SelectHackathon; -}) { - const { data: hacker, isError } = api.hackerQuery.getHacker.useQuery( - { hackathonName: hackathon.name }, - { - initialData: data, - }, - ); - - if (isError || !hacker) { - return ( -
-

- Something went wrong. Please refresh and try again. -

-
- ); - } - - const hackerStatus = HACKER_STATUS_MAP.checkedin.name; - const hackerStatusColor = HACKER_STATUS_MAP.checkedin.color; - - return ( -
- {/* Name, Status, and Actions */} -
- {/* Profile Card */} -
-
- {/* Name and Info Column */} -
-

- {hacker.firstName} {hacker.lastName} -

- - {/* Status Badge */} -
-
- - {hackerStatus} - - - -
-
-
-
-
- - {/* Action Buttons */} -
-

- Quick Actions -

- - {/* Primary actions */} -
- - -
- - {/* Secondary actions */} -
- - -
-
-
-
- ); -} diff --git a/apps/blade/src/app/_components/dashboard/hackathon-dashboard/issue-dialog.tsx b/apps/blade/src/app/_components/dashboard/hackathon-dashboard/issue-dialog.tsx deleted file mode 100644 index 2dbd7d119..000000000 --- a/apps/blade/src/app/_components/dashboard/hackathon-dashboard/issue-dialog.tsx +++ /dev/null @@ -1,96 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { AlertCircle } from "lucide-react"; - -import { Button } from "@forge/ui/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@forge/ui/dialog"; -import { Label } from "@forge/ui/label"; -import { Textarea } from "@forge/ui/textarea"; -import { toast } from "@forge/ui/toast"; - -import { api } from "~/trpc/react"; - -export function BaseHackathonIssueButton() { - const [open, setOpen] = useState(false); - const [issue, setIssue] = useState(""); - - const reportIssueMutation = - api.eventFeedback.logHackathonFeedback.useMutation({ - onSuccess: () => { - setOpen(false); - setIssue(""); - toast.success("Issue reported successfully!"); - }, - onError: (error) => { - const errorMessage = - error instanceof Error ? error.message : "An error occurred"; - toast.error(`Error: ${errorMessage}`); - }, - }); - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - if (issue.trim()) { - reportIssueMutation.mutate({ description: issue }); - } - }; - - return ( - - - - - -
- - Report an Issue - - Describe the issue you're experiencing. We'll look into it as soon - as possible. - - -
-
- -