Skip to content

[0] Custom Hackathon Dashboards#475

Open
alexanderpaolini wants to merge 4 commits into
mainfrom
blade/hackathon-pages
Open

[0] Custom Hackathon Dashboards#475
alexanderpaolini wants to merge 4 commits into
mainfrom
blade/hackathon-pages

Conversation

@alexanderpaolini

@alexanderpaolini alexanderpaolini commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Custom Hackathon Dashboards

The hackathon dashboard now gets presented at /hackathon/slug. /hackathon and /hackathon/current both redirect to the current hackathon (determined by the api fetch), if one exists.

Test Plan

cc @DGoel1602 (my forge doesn't work)

his images:

image image image

Summary by CodeRabbit

  • New Features

    • Hackathon pages now route to the active event automatically and show a clear message when no hackathon is running.
    • Added a notice on member dashboards when a hackathon is currently live.
    • Improved hackathon dashboards with a dedicated registration prompt and updated quick-action links.
  • Bug Fixes

    • Dashboard content now stays aligned with the selected hackathon and current participant status.
    • Countdown and upcoming event panels now update correctly for the active hackathon.

@alexanderpaolini alexanderpaolini added Minor Small change - 1 reviewer required Blade Change modifies code in Blade app Database Change modifies code in the DB package labels Jun 23, 2026
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@alexanderpaolini, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 39 minutes and 52 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 4b0fbcb3-8dbf-44e1-9d5e-c075b0ba189c

📥 Commits

Reviewing files that changed from the base of the PR and between 8c152ba and 8f7eb2c.

📒 Files selected for processing (10)
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/components.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-dashboard.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/point-leaderboard.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/team-points.tsx
  • apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-dashboard.tsx
  • apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-data.tsx
  • apps/blade/src/app/_components/dashboard/member-dashboard/current-hackathon-notice.tsx
  • apps/blade/src/app/hackathon/bloomknights/page.tsx
  • apps/blade/src/app/hackathon/page.tsx
📝 Walkthrough

Walkthrough

Hackathon dashboard components were split into reusable base exports, dashboard data now receives explicit hackathon context, member surfaces gained current-hackathon notices, the hackathon route pages now resolve or redirect from current status, and createEvent no longer provisions external calendar events.

Changes

Hackathon dashboard and routing

Layer / File(s) Summary
Hackathon lookup and check-in validation
packages/api/src/routers/hackathon.ts, packages/api/src/routers/hackers/mutations.ts
getCurrentHackathon now uses a start/end date window, and eventCheckIn validates assignedClassCheckin with safeParse.
Shared dashboard leaf exports
apps/blade/src/app/_components/dashboard/hackathon-dashboard/countdown.tsx, .../issue-dialog.tsx, .../upcoming-events.tsx, .../point-leaderboard.tsx
BaseHackathonCountdown takes endDate, the issue button becomes a named client export, upcoming events filter by hackathonId, and the leaderboard export is removed.
BaseHackathonData card surface
apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx
BaseHackathonData now takes data, guideHref, and hackathon, adds reusable QR/wallet/guide buttons, updates the hacker query inputs, and changes the status, styling, and leaderboard dialog content.
Dashboard shell and delegate
apps/blade/src/app/_components/dashboard/hackathon-dashboard/components.tsx, apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-dashboard.tsx
BaseHackathonRegistrationPrompt and BaseHackathonDashboard are added, and HackathonDashboard resolves an active hackathon before rendering the base shell or empty state.
Hacker dashboard and fallback data
apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-dashboard.tsx, apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-data.tsx
HackerDashboard now receives a required hackathon, and HackerData derives its queries from that prop or a fallback hackathon lookup.
Active-hackathon member notice
apps/blade/src/app/_components/dashboard/member-dashboard/current-hackathon-notice.tsx, apps/blade/src/app/_components/dashboard/member-dashboard/member-dashboard.tsx
A new notice component is inserted into both member dashboard branches when currentHackathon exists.
Member-only interface
apps/blade/src/app/_components/user-interface.tsx
UserInterface now fetches only member and renders either MemberAppCard or MemberDashboard.
Current-hackathon redirect page
apps/blade/src/app/hackathon/page.tsx
The hackathon index page now checks auth, loads the current hackathon, shows a no-hackathon state when absent, and redirects to /hackathon/{name} when present.
BloomKnights page
apps/blade/src/app/hackathon/bloomknights/page.tsx
The BloomKnights page now requires a session, loads the fixed hackathon and hacker, and renders BaseHackathonDashboard or HackerDashboard based on check-in status.

Event creation API

Layer / File(s) Summary
Create-event external provisioning removal
packages/api/src/routers/event.ts
createEvent no longer creates or rolls back Discord scheduled events and Google Calendar events, and it inserts placeholder Discord/Google IDs instead.

Sequence Diagram(s)

sequenceDiagram
  participant HackathonDashboard
  participant CurrentHackathonApi as api.hackathon.getCurrentHackathon
  participant BaseHackathonDashboard
  participant BaseHackathonRegistrationPrompt
  participant BaseHackathonData
  participant BaseHackathonCountdown
  participant BaseHackathonUpcomingEvents

  HackathonDashboard->>CurrentHackathonApi: resolve active hackathon
  CurrentHackathonApi-->>HackathonDashboard: currentHackathon or null
  HackathonDashboard->>BaseHackathonDashboard: render with hackathon and hacker
  alt hacker is missing
    BaseHackathonDashboard->>BaseHackathonRegistrationPrompt: render registration prompt
  else hacker exists
    BaseHackathonDashboard->>BaseHackathonData: render dashboard data
    BaseHackathonDashboard->>BaseHackathonCountdown: render countdown
    BaseHackathonDashboard->>BaseHackathonUpcomingEvents: render upcoming events
  end
Loading
sequenceDiagram
  participant Browser
  participant BloomKnightsHackathonPage
  participant Auth as auth
  participant HackathonApi as api.hackathon.getHackathon
  participant HackerApi as api.hackerQuery.getHacker
  participant BaseHackathonDashboard
  participant HackerDashboard

  Browser->>BloomKnightsHackathonPage: request /hackathon/bloomknights
  BloomKnightsHackathonPage->>Auth: require session
  Auth-->>BloomKnightsHackathonPage: session or null
  BloomKnightsHackathonPage->>HackathonApi: getHackathon("bloomknights")
  BloomKnightsHackathonPage->>HackerApi: getHacker()
  alt hacker.status == "checkedin"
    BloomKnightsHackathonPage->>BaseHackathonDashboard: render dashboard
  else otherwise
    BloomKnightsHackathonPage->>HackerDashboard: render dashboard
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • KnightHacks/forge#374: Shares the hacker query and dashboard prop-plumbing changes that this PR threads through the hackathon dashboard components.
  • KnightHacks/forge#381: Touches the same apps/blade/src/app/_components/dashboard/hackathon-dashboard/upcoming-events.tsx file and related event rendering logic.
  • KnightHacks/forge#409: Modifies the same packages/api/src/routers/event.ts create-event path that this PR stubs out.

Suggested labels

Feature, Major

Suggested reviewers

  • DVidal1205
🚥 Pre-merge checks | ✅ 6 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title is related, but it does not match the required issue-number format like [#123]. Change the title to start with an issue reference in brackets, e.g. "[#123] Custom Hackathon Dashboards".
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Hardcoded Secrets ✅ Passed Scanned the changed files and found no credential-like literals; only public URLs and placeholder IDs, not API keys/passwords/tokens/secrets.
Validated Env Access ✅ Passed No raw process.env usage was found in the PR-relevant files; the touched dashboard/page/router code is clean.
No Typescript Escape Hatches ✅ Passed No TS escape hatches found in changed files: no any type, @ts-ignore, @ts-expect-error, or postfix !; only plain-text “any” hits appeared in copy/comments.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch blade/hackathon-pages

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@DGoel1602 DGoel1602 left a comment

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.

The first thing is minimal but I think the second one does need some eyes

Comment thread apps/blade/src/app/_components/dashboard/hackathon-dashboard/components.tsx Outdated
Comment thread apps/blade/src/app/hackathon/bloomknights/page.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/blade/src/app/_components/dashboard/hackathon-dashboard/point-leaderboard.tsx (1)

21-54: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Remove the hardcoded leaderboard cutoff from the base component.

targetDate is fixed to October 25, 2025. On June 24, 2026, targetDate <= Date.now() is always true, so non-admin users will stay in the hidden-leaderboard branch indefinitely. This breaks the new reusable/base behavior across hackathons.

💡 Suggested fix
-export function BaseHackathonPointLeaderboard({
-  hacker,
-  hId,
-}: {
+export function BaseHackathonPointLeaderboard({
+  hacker,
+  hId,
+  hideLeaderboardAfter,
+}: {
   hacker: Awaited<ReturnType<(typeof serverCall.hackerQuery)["getHacker"]>>;
   hId: string;
+  hideLeaderboardAfter?: Date;
 }) {
@@
-  const targetDate = new Date("2025-10-25T23:00:00").getTime();
+  const targetDate = hideLeaderboardAfter?.getTime() ?? Number.POSITIVE_INFINITY;
-<BaseHackathonPointLeaderboard
-  hacker={hacker}
-  hId={hackathon.name}
-/>
+<BaseHackathonPointLeaderboard
+  hacker={hacker}
+  hId={hackathon.name}
+  hideLeaderboardAfter={hackathon.endDate}
+/>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/blade/src/app/_components/dashboard/hackathon-dashboard/point-leaderboard.tsx`
around lines 21 - 54, The targetDate variable in the
BaseHackathonPointLeaderboard function is hardcoded to October 25, 2025, which
means once the current date passes this fixed date, the leaderboard visibility
condition will always be true for non-admin users, breaking the reusable
behavior across different hackathons. Remove the hardcoded targetDate variable
and instead pass the leaderboard cutoff date as a configurable prop to the
BaseHackathonPointLeaderboard function, or derive it from the hackathon data
that is already being passed in as the hId parameter, allowing each hackathon
instance to specify its own cutoff date.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/blade/src/app/_components/dashboard/hackathon-dashboard/components.tsx`:
- Around line 35-36: Remove the type assertion using `as Record<string,
BaseHackathonClassInfo>` from the DEFAULT_CLASS_INFO variable declaration and
replace it with an explicit type annotation instead. Change the declaration to
use a colon followed by the type annotation directly on the variable (`:
Record<string, BaseHackathonClassInfo>`) rather than casting with `as`. This
ensures proper type checking without bypassing it through assertions.

In `@apps/blade/src/app/hackathon/bloomknights/page.tsx`:
- Line 41: Remove the `as string` type assertion from the hacker.status
comparison on line 41. The status field is already properly typed as a string
literal union from the database schema, so the cast is unnecessary and bypasses
TypeScript's type safety. Replace the conditional check with optional chaining
syntax (hacker?.status) instead of the current `hacker && (hacker.status as
string)` pattern to achieve a cleaner, type-safe comparison while maintaining
the same functionality.

---

Outside diff comments:
In
`@apps/blade/src/app/_components/dashboard/hackathon-dashboard/point-leaderboard.tsx`:
- Around line 21-54: The targetDate variable in the
BaseHackathonPointLeaderboard function is hardcoded to October 25, 2025, which
means once the current date passes this fixed date, the leaderboard visibility
condition will always be true for non-admin users, breaking the reusable
behavior across different hackathons. Remove the hardcoded targetDate variable
and instead pass the leaderboard cutoff date as a configurable prop to the
BaseHackathonPointLeaderboard function, or derive it from the hackathon data
that is already being passed in as the hId parameter, allowing each hackathon
instance to specify its own cutoff date.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 8f344a94-5ac6-48f4-820f-80ce15e98baf

📥 Commits

Reviewing files that changed from the base of the PR and between 58ad852 and a2c28bb.

📒 Files selected for processing (19)
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/components.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/countdown.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-dashboard.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/issue-dialog.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/point-leaderboard.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/team-points.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/upcoming-events.tsx
  • apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-dashboard.tsx
  • apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-data.tsx
  • apps/blade/src/app/_components/dashboard/member-dashboard/current-hackathon-notice.tsx
  • apps/blade/src/app/_components/dashboard/member-dashboard/member-dashboard.tsx
  • apps/blade/src/app/_components/user-interface.tsx
  • apps/blade/src/app/hackathon/bloomknights/components/bk-hackathon-dashboard.tsx
  • apps/blade/src/app/hackathon/bloomknights/page.tsx
  • apps/blade/src/app/hackathon/current/page.tsx
  • apps/blade/src/app/hackathon/page.tsx
  • packages/api/src/routers/hackathon.ts
  • packages/api/src/routers/hackers/mutations.ts

Comment thread apps/blade/src/app/_components/dashboard/hackathon-dashboard/components.tsx Outdated
Comment thread apps/blade/src/app/hackathon/bloomknights/page.tsx Outdated
@alexanderpaolini alexanderpaolini marked this pull request as ready for review June 24, 2026 02:33
@alexanderpaolini alexanderpaolini changed the title [WIP] Custom Hackathon Dashboards [0] Custom Hackathon Dashboards Jun 24, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/api/src/routers/event.ts (1)

366-428: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Build break: discordEventId and googleEventId are no longer declared.

The catch block still references discordEventId (Line 406) and googleEventId (Line 418), but both were declared only inside the now-commented provisioning blocks (former Lines 301 and 330). The compiler will fail with Cannot find name 'discordEventId' / 'googleEventId', and even if it compiled, this cleanup is now dead logic since no Discord/Google events are created here.

Drop the external-cleanup branches and keep only the DB-failure path.

🐛 Proposed fix to remove the now-invalid cleanup branches
       } catch (error) {
         logger.error(JSON.stringify(error, null, 2));
 
-        try {
-          await discord.api.delete(
-            Routes.guildScheduledEvent(
-              DISCORD.KNIGHTHACKS_GUILD,
-              discordEventId,
-            ),
-          );
-        } catch (cleanupErr) {
-          logger.error(JSON.stringify(cleanupErr, null, 2));
-        }
-
-        try {
-          await google.calendar.events.delete({
-            calendarId: input.isOperationsCalendar
-              ? EVENTS.DEV_GOOGLE_CALENDAR_ID
-              : EVENTS.GOOGLE_CALENDAR_ID,
-            eventId: googleEventId,
-          });
-        } catch (cleanupErr) {
-          logger.error(JSON.stringify(cleanupErr, null, 2));
-        }
-
         throw new TRPCError({
           message: "Failed to create event in the database",
           code: "BAD_REQUEST",
         });
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/api/src/routers/event.ts` around lines 366 - 428, The catch block in
event creation still references discordEventId and googleEventId even though
those identifiers are no longer declared in this flow. Remove the Discord and
Google cleanup branches from the error handling in the event router’s create
path, and keep only the database rollback/error logging around the
db.insert(Event) and the final TRPCError throw. Use the existing catch block in
the create-event handler to locate and simplify this dead cleanup logic.
apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx (1)

201-219: 🎯 Functional Correctness | 🟠 Major

The "View Leaderboard" button currently opens an empty dialog.

Lines 201-219 wrap the button in a Dialog component, but the necessary DialogContent (or any child content) is missing. This renders the button non-functional; clicking it opens an empty modal overlay.

If the leaderboard UI is not yet ready, remove the Dialog wrapper and use a standard button or link instead to avoid dead interactions. If the dialog content exists elsewhere, ensure it is imported and placed inside the <Dialog> tags.

// Current (broken)
<Dialog>
  <DialogTrigger asChild>
    <button>View Leaderboard</button>
  </DialogTrigger>
  {/* Missing DialogContent here */}
</Dialog>

If the feature isn't ready, simplify to:

// Fixed (temporary)
<button className="..." onClick={() => window.location.href = '/leaderboard'}>
  View Leaderboard
</button>

Otherwise, add the modal structure:

<Dialog>
  <DialogTrigger asChild>
    <button>View Leaderboard</button>
  </DialogTrigger>
  <DialogContent>
    <DialogHeader>Leaderboard</DialogHeader>
    {/* Leaderboard content here */}
  </DialogContent>
</Dialog>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx`
around lines 201 - 219, The View Leaderboard control is wrapped in a Dialog
without any DialogContent, so it opens an empty modal. Update the
hackathon-dashboard component around the Dialog/DialogTrigger block by either
removing the Dialog wrapper and using a normal button/link if the leaderboard UI
is not ready, or by adding the missing DialogContent (with the leaderboard UI)
inside the Dialog so the trigger has real content to display.
🧹 Nitpick comments (1)
apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-dashboard.tsx (1)

24-42: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Return before loading secondary data on the registration-only path.

Lines 24-27 fetch resume and past-hackathon data before the !hacker guard in Line 29. For unregistered users, those requests are unused and delay the prompt unnecessarily.

Possible fix
-  const [resume, pastHackathons] = await Promise.allSettled([
-    api.resume.getResume(),
-    api.hackathon.getPastHackathons(),
-  ]);
-
   if (!hacker) {
     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!
@@
       </div>
     );
   }
+
+  const [resume, pastHackathons] = await Promise.allSettled([
+    api.resume.getResume(),
+    api.hackathon.getPastHackathons(),
+  ]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-dashboard.tsx`
around lines 24 - 42, The `HackerDashboard` component is fetching secondary data
with `Promise.allSettled` before the `!hacker` registration-only branch, which
delays the registration prompt for users who don’t need that data. Move the
`api.resume.getResume()` and `api.hackathon.getPastHackathons()` loading so it
only runs after the `!hacker` early return, and keep the guard in
`HackerDashboard` as the first decision point before any unused requests are
started.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx`:
- Around line 155-167: The inline styles in hackathon-data.tsx are using invalid
raw color values like primary and secondary, which will not render as CSS
colors. Update the affected JSX in the dashboard component to use Tailwind
utility classes where possible, or replace the style values with the correct
hsl(var(--...)) theme syntax; check the elements around the Trophy icon and
surrounding containers in the hackathon dashboard markup.

In `@apps/blade/src/app/hackathon/bloomknights/page.tsx`:
- Around line 2-3: The page component in bloomknights/page.tsx is rendering
NotFoundPage directly, which leaves the response as 200 instead of a real 404.
Update the page logic to call Next.js notFound() from next/navigation at the
point where the 404 is needed, and remove the manual NotFoundPage return so
routing emits the proper Not Found status. Use the page component and
NotFoundPage references to locate the affected branch.

In `@packages/api/src/routers/event.ts`:
- Around line 277-364: Remove the large commented-out Discord/Google
provisioning experiment from the event router and keep only the live
`updateEvent`/`deleteEvent` logic. The commented blocks around the Discord
scheduled event creation and Google Calendar insert/callback cleanup should be
deleted entirely rather than left as dead code. If this work is intentionally
paused, capture the context in a TODO, issue, or ADR instead of preserving the
commented implementation in `event.ts`.
- Around line 379-380: The temporary discordId and googleId values in the event
flow are being treated like real external IDs, which will cause update/delete
calls in updateEvent and deleteEvent to hit Discord/Google APIs with invalid
identifiers. Replace the arbitrary placeholder strings in the event record with
an explicit sentinel such as "PLACEHOLDER" or null, and update the external call
sites in updateEvent and deleteEvent to guard on valid IDs before calling
discord.api or the Google Calendar client. Use the existing eventRecord
discordId/googleId checks so external requests are skipped whenever the ID is
missing or marked as a placeholder.

---

Outside diff comments:
In
`@apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx`:
- Around line 201-219: The View Leaderboard control is wrapped in a Dialog
without any DialogContent, so it opens an empty modal. Update the
hackathon-dashboard component around the Dialog/DialogTrigger block by either
removing the Dialog wrapper and using a normal button/link if the leaderboard UI
is not ready, or by adding the missing DialogContent (with the leaderboard UI)
inside the Dialog so the trigger has real content to display.

In `@packages/api/src/routers/event.ts`:
- Around line 366-428: The catch block in event creation still references
discordEventId and googleEventId even though those identifiers are no longer
declared in this flow. Remove the Discord and Google cleanup branches from the
error handling in the event router’s create path, and keep only the database
rollback/error logging around the db.insert(Event) and the final TRPCError
throw. Use the existing catch block in the create-event handler to locate and
simplify this dead cleanup logic.

---

Nitpick comments:
In
`@apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-dashboard.tsx`:
- Around line 24-42: The `HackerDashboard` component is fetching secondary data
with `Promise.allSettled` before the `!hacker` registration-only branch, which
delays the registration prompt for users who don’t need that data. Move the
`api.resume.getResume()` and `api.hackathon.getPastHackathons()` loading so it
only runs after the `!hacker` early return, and keep the guard in
`HackerDashboard` as the first decision point before any unused requests are
started.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 6eba0fde-c616-4abd-b735-d373c45aaa05

📥 Commits

Reviewing files that changed from the base of the PR and between a2c28bb and 8c152ba.

📒 Files selected for processing (12)
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/components.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-dashboard.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/point-leaderboard.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/team-points.tsx
  • apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-dashboard.tsx
  • apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-data.tsx
  • apps/blade/src/app/_components/dashboard/member-dashboard/current-hackathon-notice.tsx
  • apps/blade/src/app/_components/dashboard/member-dashboard/member-dashboard.tsx
  • apps/blade/src/app/hackathon/bloomknights/page.tsx
  • apps/blade/src/app/hackathon/page.tsx
  • packages/api/src/routers/event.ts
💤 Files with no reviewable changes (4)
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/team-points.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/point-leaderboard.tsx
  • apps/blade/src/app/_components/dashboard/member-dashboard/member-dashboard.tsx
  • apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-dashboard.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/blade/src/app/_components/dashboard/member-dashboard/current-hackathon-notice.tsx
  • apps/blade/src/app/_components/dashboard/hacker-dashboard/hacker-data.tsx

Comment on lines +155 to +167
style={{ backgroundColor: `primary` }}
/>

<div className="relative">
{/* Icon */}
<div className="mb-2 flex justify-center sm:mb-3">
<div
className="rounded-full p-2 sm:p-2.5"
style={{ backgroundColor: `${teamColor}20` }}
style={{ backgroundColor: `primary` }}
>
<Trophy
className="h-6 w-6 sm:h-7 sm:w-7"
style={{ color: teamColor }}
style={{ color: "primary" }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx | sed -n '150,220p'

Repository: KnightHacks/forge

Length of output: 3624


🏁 Script executed:

grep -r "hsl(var(--primary)" apps/blade/src --include="*.tsx" --include="*.ts" | head -10

Repository: KnightHacks/forge

Length of output: 155


🏁 Script executed:

grep -rn "var(--primary" apps/blade/src --include="*.tsx" --include="*.css" | head -20

Repository: KnightHacks/forge

Length of output: 2401


🏁 Script executed:

cat -n apps/blade/src/app/globals.css | head -40

Repository: KnightHacks/forge

Length of output: 1475


🏁 Script executed:

grep -rn "text-primary" apps/blade/src --include="*.tsx" | head -10

Repository: KnightHacks/forge

Length of output: 1638


Fix invalid inline color values

Inline styles using raw "primary" or "secondary" are not valid CSS and will result in broken colors. Replace them with either Tailwind utility classes (preferred) or the correct hsl(var(--...)) syntax.

Correction details
- style={{ backgroundColor: `primary` }}
+ className="bg-primary"
+ style={{ backgroundColor: `hsl(var(--primary))` }}  // If inline is strictly required

- <Trophy style={{ color: "primary" }} />
+ <Trophy className="text-primary" />

- style={{ background: `linear-gradient(to bottom right, primary, primary)` }}
+ style={{ background: `linear-gradient(to bottom right, hsl(var(--primary)), hsl(var(--primary)))` }}

- style={{ backgroundColor: `primary`, color: "secondary" }}
+ className="bg-primary text-secondary-foreground"  // Or valid HSL equivalent
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/blade/src/app/_components/dashboard/hackathon-dashboard/hackathon-data.tsx`
around lines 155 - 167, The inline styles in hackathon-data.tsx are using
invalid raw color values like primary and secondary, which will not render as
CSS colors. Update the affected JSX in the dashboard component to use Tailwind
utility classes where possible, or replace the style values with the correct
hsl(var(--...)) theme syntax; check the elements around the Trophy icon and
surrounding containers in the hackathon dashboard markup.

Comment on lines +2 to +3
import { redirect } from "next/navigation";

@coderabbitai coderabbitai Bot Jun 25, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n apps/blade/src/app/hackathon/bloomknights/page.tsx | sed -n '1,35p'

Repository: KnightHacks/forge

Length of output: 1425


Use notFound() instead of rendering the 404 page component directly

Line 29 currently returns <NotFoundPage />, which renders a 404 UI but keeps the HTTP response status as 200 OK. This is invalid for an App Router page.tsx and interferes with correct 404 status handling.

Replace the manual return with notFound() to ensure a proper 404 Not Found status and to integrate with Next.js routing conventions.

Fix
-import { redirect } from "next/navigation";
+import { notFound, redirect } from "next/navigation";

-    return <NotFoundPage />;
+    notFound();

See App Router docs for details on 404 semantic handling.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { redirect } from "next/navigation";
import { notFound, redirect } from "next/navigation";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/blade/src/app/hackathon/bloomknights/page.tsx` around lines 2 - 3, The
page component in bloomknights/page.tsx is rendering NotFoundPage directly,
which leaves the response as 200 instead of a real 404. Update the page logic to
call Next.js notFound() from next/navigation at the point where the 404 is
needed, and remove the manual NotFoundPage return so routing emits the proper
Not Found status. Use the page component and NotFoundPage references to locate
the affected branch.

Source: Path instructions

✅ Confirmed as addressed by @alexanderpaolini

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@alexanderpaolini The PR description image 1 shows a dark BloomKnights dashboard with “Hello, Alchemist Dhruv!”, a checked-in status card, quick action buttons for QR / Apple Wallet / Hacker’s Guide / Report an Issue, a Hack Points card showing 35, a humanity vs monstrosity progress bar, and the top of a countdown section labeled “HACKING ENDS IN.”

The PR description image 2 shows the Blade member dashboard dimmed behind a centered modal titled “BloomKnights is live,” with copy about check-in tools, points, live events, and event-specific info, plus “Stay Here” and “Open Hackathon Dashboard” buttons.

The PR description image 3 shows the Hackathon Dashboard with “Hello, Dhruv!”, a “Confirmed” status, a QR action bar, a notice that “The confirmation deadline has passed.”, a red “WITHDRAW” button, and lower actions for “View Past Hackathons” and “Download Resume.”

Thanks for resolving this. Using notFound() here is the right App Router fix because it returns a real 404 response instead of a 200 page that only looks like a 404.

For reference, the intended pattern is:

import { notFound, redirect } from "next/navigation";

if (!hackathon) {
  notFound();
}

🧠 Learnings used
Learnt from: DVidal1205
Repo: KnightHacks/forge PR: 354
File: apps/blade/src/app/admin/club/data/_components/MemberDemographics.tsx:19-35
Timestamp: 2026-02-10T19:07:03.232Z
Learning: In the KnightHacks/forge repository, apply the pattern in TSX React components: gating rendering should occur only when all required data fetches succeed. Do not render partial success when some queries fail; instead, implement a unified loading/state or error handling that surfaces a single, coherent state once all data is ready or failed. This repo-wide guideline helps ensure consistent UX when multiple data sources are involved.

If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

Comment thread packages/api/src/routers/event.ts Outdated
Comment thread packages/api/src/routers/event.ts Outdated
Comment on lines 204 to 219
className="w-full rounded-lg py-2 text-sm font-semibold transition-all hover:shadow-md sm:py-2.5"
style={{
backgroundColor: `${teamColor}20`,
color: teamColor,
backgroundColor: `primary`,
color: "secondary",
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = `${teamColor}33`;
e.currentTarget.style.backgroundColor = `primary`;
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = `${teamColor}20`;
e.currentTarget.style.backgroundColor = `primary`;
}}
>
View Leaderboard
</button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Leaderboard</DialogTitle>
</DialogHeader>
<PointLeaderboard
hacker={hacker}
hId={hackathonData?.name ?? ""}
/>
</DialogContent>
</Dialog>

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.

let's nuke the leaderboard trigger along with the content, base dash won't need a leaderboard

textShadow: `0 0 10px primary`,
}}
>
{hacker?.points || 0}

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.

we also don't rlly need this big point section in base dash, since points are dependent on the hack at hand
base is ideally:

  • hacker info
  • hacker status management
  • upcoming events

base can remove anything concerning classes, points, leaderboards, etc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Blade Change modifies code in Blade app Database Change modifies code in the DB package Minor Small change - 1 reviewer required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants