Commit 8ac968c
Implement track-based prize structure and submission visibility updates (#578)
* fix(hackathons): single-column teams tab and primary-colored pager (#562)
* fix(hackathons): single-column teams tab and primary-colored pager
Revert the teams tab grid to a single column and rework the shared
Pagination component to match the icon-chevron layout used by the
organizer submissions and participants pages, styled with the primary
color.
* feat(submissions): link submission card avatars to profile pages
Wrap the individual avatar on SubmissionCard in a profile link and
forward team-member usernames to GroupAvatar so each clustered avatar
opens that user's profile in a new tab.
* feat(hackathons): track-based prize structure + submission polish + tracks UI (#564)
* feat(hackathons): add "hidden until results" submission visibility mode
Surfaces the new HIDDEN_UNTIL_RESULTS option (added in the nestjs PR) in
the organizer settings tab. Reorders the three visibility options so the
recommended "Shortlisted only" leads, the new "Hidden until results are
announced" sits in the middle, and "All submissions" comes last. Rewrites
the copy on the "All submissions" choice that incorrectly claimed
disqualified projects would be shown -- they never were on the backend,
and Phase 2 makes that an explicit guarantee. Aligns the form's default
and API-fallback value with the backend default (ACCEPTED_SHORTLISTED,
not ALL) so organizers don't see a misleading initial selection.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(hackathons): track-based prize structure, submission polish, tracks UI
Wires the frontend for the new track-based prize flow:
- New TracksSettingsTab with full CRUD: name/slug/description/eligibility/
prompt/customQuestions/requiredArtifacts; per-row bulk-opt-in action with
confirmation dialog for retrofitting existing submissions
- RewardsTab gains a 3-card prize structure picker, per-tier kind toggle and
track dropdown, amber "tracks unbound" banner, and an inline Manage Tracks
dialog embedding the settings table
- SubmissionForm: track picker + per-track answers (prompt / custom
questions / required artifacts), tagline, builtWith chips, screenshots,
license, code attestation, with soft compliance gate for already-submitted
submissions. trackIds hydrate from trackEntries on edit so bulk-opted-in
submitters don't strip themselves out
- SubmissionDetailModal renders tagline, screenshots, built-with, license
badge, and per-track answers
- Public hackathon page: Overview splits prizes into Overall/Track sections;
sidebar tier list shows TRACK prefix and looks up track names; Winners tab
gets a Track Winners section with per-track cards
- API client: lib/api/hackathons/tracks.ts with listTracks /
listOrganizerTracks / createTrack / updateTrack / deleteTrack /
bulkOptInAllSubmissions, plus types for HackathonTrack,
TrackCustomQuestion, TrackRequiredArtifact, TrackAnswer,
SubmissionTrackEntry, BulkOptInResult
- Hackathon provider/hooks expose trackWinners and per-track entries
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Feat/submission visibility hidden until results (#566)
* feat(hackathons): add "hidden until results" submission visibility mode
Surfaces the new HIDDEN_UNTIL_RESULTS option (added in the nestjs PR) in
the organizer settings tab. Reorders the three visibility options so the
recommended "Shortlisted only" leads, the new "Hidden until results are
announced" sits in the middle, and "All submissions" comes last. Rewrites
the copy on the "All submissions" choice that incorrectly claimed
disqualified projects would be shown -- they never were on the backend,
and Phase 2 makes that an explicit guarantee. Aligns the form's default
and API-fallback value with the backend default (ACCEPTED_SHORTLISTED,
not ALL) so organizers don't see a misleading initial selection.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(hackathons): track-based prize structure, submission polish, tracks UI
Wires the frontend for the new track-based prize flow:
- New TracksSettingsTab with full CRUD: name/slug/description/eligibility/
prompt/customQuestions/requiredArtifacts; per-row bulk-opt-in action with
confirmation dialog for retrofitting existing submissions
- RewardsTab gains a 3-card prize structure picker, per-tier kind toggle and
track dropdown, amber "tracks unbound" banner, and an inline Manage Tracks
dialog embedding the settings table
- SubmissionForm: track picker + per-track answers (prompt / custom
questions / required artifacts), tagline, builtWith chips, screenshots,
license, code attestation, with soft compliance gate for already-submitted
submissions. trackIds hydrate from trackEntries on edit so bulk-opted-in
submitters don't strip themselves out
- SubmissionDetailModal renders tagline, screenshots, built-with, license
badge, and per-track answers
- Public hackathon page: Overview splits prizes into Overall/Track sections;
sidebar tier list shows TRACK prefix and looks up track names; Winners tab
gets a Track Winners section with per-track cards
- API client: lib/api/hackathons/tracks.ts with listTracks /
listOrganizerTracks / createTrack / updateTrack / deleteTrack /
bulkOptInAllSubmissions, plus types for HackathonTrack,
TrackCustomQuestion, TrackRequiredArtifact, TrackAnswer,
SubmissionTrackEntry, BulkOptInResult
- Hackathon provider/hooks expose trackWinners and per-track entries
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(submissions): tighten Zod schema + surface backend debug info
- Add max constraints that previously only existed on the backend DTO so
validation fires inline (projectName 100, description 5000, URL 500).
- ApiErrorField gains an optional `debug` field that the backend Prisma
filter populates outside production.
- useSubmission's error formatter prefers `debug` over the generic field
message when present, so toasts show the real Prisma reason behind
"Data validation failed" instead of a blank "validation: …" line.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(submit-page): hydrate Phase A fields + stop wiping user input on re-render
The submit page mapped `initialData` inline on every render, which (a)
recreated the object reference on every render so the form's reset
effect fired continuously and wiped values the user was typing, and (b)
dropped the Phase A fields entirely (tagline, builtWith, screenshots,
license, codeAttestedAt) plus trackEntries. The combined effect was the
documented symptom — only logo and videoUrl survived the save because
those round-tripped through the type-narrowed object literal, while
tagline / builtWith / license kept appearing to "switch to empty".
- Memoize `initialData` against `mySubmission` so the reference only
changes when the underlying submission actually changes.
- Pass through Phase A fields and trackEntries so the form can hydrate
the saved values, and so a follow-up save doesn't write back empties.
- Widen SubmissionFormContent's `initialData` prop to accept the raw
server-side extras (trackEntries, codeAttestedAt) that the form
already consumes via cast — keeps the parent's hydration explicit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(hackathons): always open submissions in a new tab (#568)
* fix(hackathons): single-column teams tab and primary-colored pager
Revert the teams tab grid to a single column and rework the shared
Pagination component to match the icon-chevron layout used by the
organizer submissions and participants pages, styled with the primary
color.
* feat(submissions): link submission card avatars to profile pages
Wrap the individual avatar on SubmissionCard in a profile link and
forward team-member usernames to GroupAvatar so each clustered avatar
opens that user's profile in a new tab.
* fix(hackathons): always open submissions in a new tab
Across the hackathon, organizer, judge, and profile surfaces, clicking
a submission now opens the project page in a new tab so reviewers and
participants do not lose their list/queue context. Switched the
remaining anchor tags to next/link Link components.
* feat(judging): organizer dashboard — coverage, preview, per-track results (#570) (#572)
Pairs with boundless-nestjs feat(judging) organizer dashboard upgrades.
Adds three new components to the organizer judging page; no changes to
existing components, judges, or scoring flows.
- `CoverageMatrix` — heatmap on the Overview tab. Rows are
submissions, columns are judges. Surfaces idle judges (mostly-empty
columns) and orphan submissions (rows with 0-1 scores) at a glance —
both block a defensible publish.
- `AllocationPreviewCard` — sits above the Publish button on the
Results tab. Read-only allocator dry-run showing overall placements
+ per-track winners exactly as publish-results would commit. Calls
out EXCLUSIVE stacking effects (track leader losing to overall),
plus surfaces publish gates (deadline, completeness, partner
allocation) so the organizer sees blockers without attempting to
publish.
- `TrackResultsSection` — per-track collapsible standings on the
Results tab. Each section is scoped to a track's opt-ins, sorted by
averageScore, with the bound prize tier shown as a chip. The leader
is highlighted as the current pick — soft preview only; the
Allocation Preview above shows the authoritative EXCLUSIVE-stacked
outcome.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(judging): unallocated partner funds become a warning, not a blocker (#574)
Mirrors the backend relaxation. The allocator preview's
"Ready to publish" badge previously turned amber whenever any partner
contribution had unallocated balance — but the backend gate that
backed that signal has been relaxed (the funds stay in escrow
post-publish; they're not lost).
Split the existing publish-readiness messaging into two lists:
- Blockers — the hard gates (deadline, completeness, no reviews).
Same red treatment, same ready-to-publish badge logic.
- Warnings — informational, never blocks. Renders in blue, calls out
the unallocated amount with a note that it remains in escrow.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(rewards): show track winners on the organizer rewards page (#576)
The rewards page was filtering winners by `submission.rank` only, so
on the track-based prize structure it silently dropped every track
winner. For the Boundless × Trustless Work hackathon (3 overall + 5
track tiers), the page rendered 3 of 8 winners and the publish wizard
preview showed 3 of 8 prize tiers paired.
Same root cause as boundlessfi/boundless-nestjs#132: track winners
live on `SubmissionTrackEntry.wonRank`, not on `submission.rank`, and
the rewards UI was rank-keyed end to end.
Changes:
- Extend `Submission` with optional track-winner fields (`isTrackWinner`,
`trackId`, `trackName`, `trackPrize`, `trackWonRank`).
- `useHackathonRewards` now fetches `getHackathonWinners` in a
dedicated effect that runs once results are published. The
`trackWinners` payload is stamped onto matching submissions AND
returned raw so the page can render a per-track section.
- `useHackathonRewards` also preserves `tier.kind` and `tier.trackId`
on the mapped `prizeTiers` and re-sorts so track tiers no longer
collapse to the 999 fallback rank.
- `rewards/page.tsx` winners filter now ORs `s.isTrackWinner` with the
rank-based check, and `maxRank` counts only OVERALL tiers so the
rank-keyed lookups don't get polluted with synthetic track ranks.
- New `TrackWinnersSection` component renders below the existing
rank-based `PodiumSection`. Mirrors the public WinnersTab pattern:
one card per track with prize chip, project name, team, avatars.
- `PublishWinnersWizard` includes track winners in its preview list
and threads `kind`/`trackId` through to `WinnersGrid`.
- `WinnersGrid` now renders overall + track tiers as separate
sections. Overall keeps the 2-1-3 podium re-order; track tiers
render in display order. Each tier is matched to its winner via
rank OR trackId.
Pairs with boundless-nestjs#132 (BE trigger endpoint already
respects track winners after that merged).
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Nnaji Benjamin <60315147+Benjtalkshow@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Benjtalkshow <chinedubenj@gmail.com>1 parent 451775f commit 8ac968c
8 files changed
Lines changed: 419 additions & 64 deletions
File tree
- app/(landing)/organizations/[id]/hackathons/[hackathonId]/rewards
- components/organization/hackathons/rewards
- hooks
Lines changed: 12 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
34 | 35 | | |
35 | 36 | | |
36 | 37 | | |
| |||
43 | 44 | | |
44 | 45 | | |
45 | 46 | | |
46 | | - | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
47 | 55 | | |
48 | | - | |
| 56 | + | |
| 57 | + | |
49 | 58 | | |
50 | 59 | | |
51 | 60 | | |
| |||
121 | 130 | | |
122 | 131 | | |
123 | 132 | | |
| 133 | + | |
124 | 134 | | |
125 | 135 | | |
126 | 136 | | |
| |||
Lines changed: 3 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
14 | 17 | | |
15 | 18 | | |
16 | 19 | | |
| |||
Lines changed: 25 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
44 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
45 | 56 | | |
46 | 57 | | |
47 | 58 | | |
48 | | - | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
49 | 62 | | |
50 | 63 | | |
51 | 64 | | |
| |||
92 | 105 | | |
93 | 106 | | |
94 | 107 | | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
95 | 111 | | |
96 | 112 | | |
97 | 113 | | |
98 | 114 | | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
99 | 119 | | |
100 | | - | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
101 | 123 | | |
102 | 124 | | |
103 | 125 | | |
| |||
Lines changed: 10 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
| 25 | + | |
24 | 26 | | |
25 | 27 | | |
26 | 28 | | |
| |||
41 | 43 | | |
42 | 44 | | |
43 | 45 | | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
44 | 52 | | |
45 | 53 | | |
46 | 54 | | |
| |||
57 | 65 | | |
58 | 66 | | |
59 | 67 | | |
| 68 | + | |
60 | 69 | | |
61 | 70 | | |
62 | 71 | | |
| |||
214 | 223 | | |
215 | 224 | | |
216 | 225 | | |
| 226 | + | |
217 | 227 | | |
218 | 228 | | |
219 | 229 | | |
| |||
Lines changed: 114 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
0 commit comments