Skip to content

Fix contest system UI, permissions, notifications and layout - #26

Draft
ronits2407 wants to merge 9 commits into
devfrom
fix/contest-bugs
Draft

Fix contest system UI, permissions, notifications and layout#26
ronits2407 wants to merge 9 commits into
devfrom
fix/contest-bugs

Conversation

@ronits2407

Copy link
Copy Markdown
Contributor

Fix Contest Listing, Match History, Knockout Permissions, Desktop Notifications, and Panel Layout

This PR addresses all 7 reported issues/bugs across the contest platform:

  1. Match Visibility / Non-Participant Views: Allowed non-participants to view completed contests, redirecting them straight to the room's results view instead of throwing a "Contest Cancelled" page.
  2. Match History UI Enhancements: Contest name is now always displayed. The outcome badges (Victory/Tie/Defeat) and scores are conditionally shown only for users who actually participated in the match.
  3. Filter Button Heights: Always render the ListFilter icon in the "All Formats" button to prevent layout shifting when it toggles. Added a fixed height: 36px to .filterBtn to maintain uniform styling.
  4. Knockout Gating: Moved createBracketContest to the user-facing contest action file and removed the isAdmin check, allowing all authenticated users to create bracket/knockout contests.
  5. Roster Avatar fallbacks: Removed Codeforces (cp?.cfAvatar) avatar fallbacks so that profile photos only use the website-uploaded profile photo.
  6. Desktop Notifications: Leveraged the browser Notification API to send OS-level push notifications for every activity log event, complete with customized SVG data-URIs matching the feed icons.
  7. Panel Heights: Bounded the outer layouts (.contestMain layout container, .page, and flex/grid children) to fix flexbox overflow collapsing and resolve the whitespace gap at the bottom of the screen.

@maydayv7

Copy link
Copy Markdown
Contributor

The bracket creation flow needs stronger server-side validation. This is not entirely introduced by this PR, but broadening bracket creation to all authenticated users makes it more important.

Validate server-side:

  • Start and registration times
  • Maximum registrations and team sizes
  • Registered user IDs and CP-profile eligibility
  • Problem-selection configuration
  • All fields currently validated only by the modal

Ideally, contest creation actions should share a common validation layer so direct server-action calls cannot bypass the checks.

Minor issues:

  1. bulkMinContestId is not copied from the selected preset or persisted by the new action.
  2. Notification.requestPermission() is called from a mount-time effect. Firefox and Safari require permission requests to originate from a user gesture, so notifications will not be enabled reliably. Expose an explicit “Enable notifications” action and request permission from its click handler.

@ronits2407
ronits2407 marked this pull request as draft July 29, 2026 19:55
@ronits2407

Copy link
Copy Markdown
Contributor Author

Update: All Review Items Addressed

Here is a full summary of everything pushed to this branch (fix/contest-bugs) in response to the review.


1. Server-side validation for createBracketContest

Added a complete validation layer at the top of createBracketContest before any DB writes, mirroring the checks already present in createRoomContest:

  • name — non-empty, max 100 characters
  • mode — must be "blitz" or "arena"
  • startTime — valid date, must be at least REGISTRATION_DEADLINE_MINUTES + 1 minutes in the future
  • registrationType — must be "open" or "closed"
  • Bulk mode (custom preset): bulkRatingMin < bulkRatingMax, both within 800–3500, bulkProblemCount between 1 and 20
  • Fine-tuned mode (custom preset): non-empty problemSlots with filled problemId fields per round
  • Pre-seeded users (closed registration): each entry is a valid ObjectId, has a linked CPUser, and has a verified cfHandle

2. bulkMinContestId — contest timeframe for problem auto-picking

This field was added to the models and workers by @maydayv7 in 3e4b61e, but createBracketContest and CreateRoomModal never carried it through. Fixed:

src/lib/actions/contests.ts

  • Added let bulkMinContestId = data.bulkMinContestId ?? 0
  • When a preset is selected: bulkMinContestId = data.bulkMinContestId ?? preset.bulkMinContestId ?? 0 (data overrides preset, consistent with admin action)
  • Persisted in ContestMatch.create() as bulkMinContestId: bulkMinContestId || undefined

src/components/contests/CreateRoomModal.tsx

  • Added bulkMinContestId: 0 to formData initial state
  • Copied from preset in the preset-change handler (preset.bulkMinContestId ?? prev.bulkMinContestId)
  • Added a "Contest Release Date" dropdown below the problem count field in the bulk section, using the existing CF_CONTEST_YEAR_OPTIONS constant (disabled when a preset is selected, since the preset defines it)

3. Notification.requestPermission() on mount

Removed the mount-time useEffect that called Notification.requestPermission() automatically in both ArenaRoomClient and BlitzRoomClient — this was silently failing on Firefox and Safari due to the user-gesture requirement.

Replaced with an explicit "🔔 Enable Notifications" pill button rendered inside the Activity Feed header. It only appears when permission is not already granted, and calls requestPermission() from its click handler, satisfying the browser requirement on all platforms.


4. SVG icons consolidated into Icons.tsx

The notification icon map in both room clients was previously a duplicated block of raw SVG strings. Refactored:

  • Added IconLock, IconGavel, and IconPersonOff to src/components/shared/Icons.tsx
  • Replaced NOTIFICATION_SVG_ICONS (raw string map) in both clients with NOTIFICATION_ICON_MAP — maps each icon key to an Icons.tsx component + its color
  • Added getNotificationIconUri() — uses renderToStaticMarkup to render the component to an SVG data URI at call time
  • All notification SVGs now have a single source of truth in Icons.tsx

5. Housekeeping

  • scripts/companion-bot.ts removed from git tracking and added to .gitignore
  • blog/, *.zip also added to .gitignore to prevent accidental commits
  • scripts/seed.ts restored to the dev branch version (club account, Secretary role)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants