Skip to content

#289 Show Alignments on Tournament Pairings Page#292

Merged
ianpaschal merged 2 commits intomainfrom
289-show-alignments-on-tournament-pairings-page
Jan 31, 2026
Merged

#289 Show Alignments on Tournament Pairings Page#292
ianpaschal merged 2 commits intomainfrom
289-show-alignments-on-tournament-pairings-page

Conversation

@ianpaschal
Copy link
Owner

@ianpaschal ianpaschal commented Jan 31, 2026

Resolves #289


Summary by CodeRabbit

  • New Features

    • Richer pairing validation with user-facing options and a new pairing error message when no valid pairings exist without allowing same-alignment.
    • New TournamentCompetitorIdentity component for competitor display.
  • Refactor

    • Centralized pairing validation flow; pairing generation now respects external pairing options and validation results.
  • Style

    • Flexible sizing for faction indicator, updated competitor/pairing layouts, and Pulsar now accepts external className.
  • Tests

    • Added unit tests covering pairing validation, alignment, and repeat detection.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Jan 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
combat-command Ready Ready Preview, Comment Jan 31, 2026 8:22pm

@coderabbitai
Copy link

coderabbitai bot commented Jan 31, 2026

Caution

Review failed

An error occurred during the review process. Please try again later.

Walkthrough

Adds alignment- and repeat-aware pairing validation and options, refactors pairing generation to use the validator, exposes pairing types and validator in the public API, adds unit tests, and updates pairing UI components and identity/avatar rendering.

Changes

Cohort / File(s) Summary
Error Codes & Types
convex/_model/common/errors.ts, convex/_model/tournamentPairings/types.ts
Added new error code NO_VALID_PAIRINGS_POSSIBLE_WITHOUT_SAME_ALIGNMENT and exported types TournamentPairingOptions and TournamentPairingStatus.
Pairing Helpers & Tests
convex/_model/tournamentPairings/_helpers/checkIfPairingIsRepeat.ts, convex/_model/tournamentPairings/_helpers/checkIfPairingIsRepeat.test.ts, convex/_model/tournamentPairings/_helpers/checkIfPairingIsSameAlignment.ts, convex/_model/tournamentPairings/_helpers/checkIfPairingIsSameAlignment.test.ts
New helper functions to detect repeat matchups and same-alignment conflicts plus unit tests covering expected scenarios.
Pairing Validation & Tests
convex/_model/tournamentPairings/_helpers/validateTournamentPairing.ts, convex/_model/tournamentPairings/_helpers/validateTournamentPairing.test.ts
New validateTournamentPairing returning error/warning/ok statuses for repeats, alignment conflicts, byes, and table warnings; comprehensive tests added.
Pairing Generation & Tests
convex/_model/tournamentPairings/_helpers/generateDraftPairings.ts, convex/_model/tournamentPairings/_helpers/generateDraftPairings.test.ts
Refactored to accept TournamentPairingOptions, replaced inline checks with validateTournamentPairing, removed local validators, and added post-backtracking diagnostics and tests for alignment/repeat scenarios.
Public API & Query Wiring
convex/_model/tournamentPairings/index.ts, convex/_model/tournamentPairings/queries/getDraftTournamentPairings.ts, src/api.ts
Exported validateTournamentPairing, TournamentPairingOptions, and TournamentPairingStatus; updated query args to accept an options object and pass it into pairing generation; re-exported types/function in public API.
Pairings Page — Logic & UI
src/pages/TournamentPairingsPage/TournamentPairingsPage.tsx, src/pages/TournamentPairingsPage/TournamentPairingsPage.utils.tsx, src/pages/TournamentPairingsPage/TournamentPairingsPage.module.scss
Derived pairingOptions from UI, passed options into draft pairing fetch and status computation, switched to TournamentCompetitorIdentity, updated layout to grid and surfaced faction/alignments.
Tournament Competitor Identity Component
src/components/TournamentCompetitorIdentity/TournamentCompetitorIdentity.tsx, src/components/TournamentCompetitorIdentity/TournamentCompetitorIdentity.module.scss, src/components/TournamentCompetitorIdentity/index.ts
Added new presentational component to render competitor avatar/name/loading states, styles, and a barrel export.
UI/Style Adjustments & Minor Hooks
src/components/FactionIndicator/FactionIndicator.module.scss, src/components/generic/Pulsar/Pulsar.tsx, src/pages/TournamentPairingsPage/components/TournamentRosterCard/TournamentRosterCard.utils.tsx, src/components/TournamentProvider/TournamentProvider.hooks.tsx
Made FactionIndicator size configurable, added className prop to Pulsar, updated roster card to use TournamentCompetitorIdentity, and removed a broken action (TODO).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Several changes extend beyond the core alignment display requirement, including new pairing validation helpers, repeat pairing checks, and refactored getDraftTournamentPairings logic that adds constraint-based options handling. Review and clarify whether alignment-constraint validation, repeat-pairing checks, and options-based filtering for generateDraftPairings are part of issue #289 or separate requirements that should be documented.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly reflects the main objective of displaying player alignments on the tournament pairings page, which aligns with the primary requirement in issue #289.
Linked Issues check ✅ Passed The PR implements both functional requirements: adding FactionIndicator display to pairing page UI and integrating new alignment validation logic (checkIfPairingIsSameAlignment and related helpers) without cluttering existing information.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 289-show-alignments-on-tournament-pairings-page

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

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

⚠️ Outside diff range comments (1)
convex/_model/tournamentPairings/queries/getDraftTournamentPairings.ts (1)

17-24: ⚠️ Potential issue | 🟠 Major

Make options optional to avoid breaking existing callers.

The validator now requires options, which will reject older clients/tests that omit it. Since the options already have defaults downstream, this can remain optional.

🛠️ Suggested fix
 export const getDraftTournamentPairingsArgs = v.object({
   method: tournamentPairingMethod,
   round: v.number(),
   tournamentId: v.id('tournaments'),
-  options: v.object({
-    allowSameAlignment: v.optional(v.boolean()),
-    allowRepeats: v.optional(v.boolean()),
-  }),
+  options: v.optional(v.object({
+    allowSameAlignment: v.optional(v.boolean()),
+    allowRepeats: v.optional(v.boolean()),
+  })),
 });
🤖 Fix all issues with AI agents
In `@convex/_model/tournamentPairings/_helpers/checkIfPairingIsRepeat.ts`:
- Around line 3-10: Remove the extra blank line between the JSDoc comment and
the function declaration for checkIfPairingIsRepeat; place the JSDoc immediately
above the export const checkIfPairingIsRepeat(...) declaration so the comment is
directly associated with the function.

In
`@convex/_model/tournamentPairings/_helpers/checkIfPairingIsSameAlignment.test.ts`:
- Around line 66-73: The test shows checkIfPairingIsSameAlignment treats two
empty alignment arrays as "same" (returning true), which blocks pairings when
allowSameAlignment is false; change the function checkIfPairingIsSameAlignment
to treat empty or missing alignment arrays as "unknown" (not matching) by
returning false when either competitor has an empty alignments array (or when
alignments are not visible), so empty/missing alignment data does not block
pairings—update the logic inside checkIfPairingIsSameAlignment (and any place it
reads details.alignments or alignmentsVisible) to short-circuit and return false
for empty/missing alignments or add a clear parameter/flag to control that
behavior if callers need explicit toggling.

In `@convex/_model/tournamentPairings/_helpers/checkIfPairingIsSameAlignment.ts`:
- Around line 13-33: The function checkIfPairingIsSameAlignment currently treats
empty alignment arrays as a conflict; update it so missing alignment data allows
pairing by adding an early check on a.details.alignments and
b.details.alignments: if either aAlignments.length === 0 || bAlignments.length
=== 0 return false (meaning not same alignment / allow pairing). Keep the
existing checks for 'flexible', multiple alignments, and differing single
alignments, but ensure the new empty-array guard runs before those checks to
avoid incorrectly blocking pairings.

In `@convex/_model/tournamentPairings/_helpers/validateTournamentPairing.test.ts`:
- Line 79: Create a tracked issue for the "TODO: Tests beyond here may need some
clean-up" in
convext/_model/tournamentPairings/_helpers/validateTournamentPairing.test.ts:
open a ticket in our tracker describing what needs cleanup (scope, why, rough
acceptance criteria) and then update the TODO comment in
validateTournamentPairing.test.ts to include the new issue number or link (e.g.,
"TODO (ISSUE-123): ...") so future readers can find the task; also add a brief
note in the PR description referencing the new issue.

In `@convex/_model/tournamentPairings/queries/getDraftTournamentPairings.ts`:
- Around line 47-56: The code computes orderBy from args.method but doesn't
normalize the AdjacentAlignment enum variant, so passing AdjacentAlignment
leaves orderedCompetitors empty; update the derivation of orderBy (used in
getDraftTournamentPairings where args.method, TournamentPairingMethod, and
orderBy are referenced) to map AdjacentAlignment to
TournamentPairingMethod.Adjacent before the branch checks (or otherwise
normalize args.method into Adjacent) so the existing branches that call
sortByRank and shuffle and then pass orderedCompetitors into
generateDraftPairings and sortCompetitorPairs run as intended.

In
`@src/components/TournamentCompetitorIdentity/TournamentCompetitorIdentity.tsx`:
- Around line 69-78: The button in the TournamentCompetitorIdentity component
currently relies on the default type (submit); update the JSX for the button
element in TournamentCompetitorIdentity to include an explicit type="button"
attribute (next to className, onClick, disabled, data-clickable) so clicks won't
trigger form submits; keep handleClick and the existing disabled/data-clickable
logic unchanged.
- Around line 64-66: The click handler currently calls onClick without passing
the competitor id; update handleClick to pass the resolved competitor id to the
callback (e.g., change onClick?.() to onClick?.(competitorId) or onClick?.(id)
depending on the local variable that holds the resolved id). Ensure you use the
existing identifier for the resolved competitor id in scope so consumers of the
onClick prop receive the id.

In `@src/components/TournamentProvider/TournamentProvider.hooks.tsx`:
- Line 43: The change commented out useSubmitMatchResultAction(subject) in
TournamentProvider.hooks.tsx removes match result submission and is unrelated to
the pairing alignment PR; either revert that change (uncomment and restore
calling useSubmitMatchResultAction with the same subject so MatchResult
submission behavior remains intact) or move the removal into a separate
branch/PR and leave a clear TODO comment referencing the need to migrate the
match result form; also open a tracking issue that mentions
useSubmitMatchResultAction and the match result form migration so the broken
functionality is filed for follow-up.

In `@src/pages/TournamentPairingsPage/TournamentPairingsPage.tsx`:
- Around line 21-25: pairingOptions currently uses a stale allowSameAlignment
value instead of reflecting tournament.pairingMethod; update pairingOptions
wherever it's built or used (including the pairing-method dropdown change
handler, draft generation call, and status validation path) to compute
allowSameAlignment = tournament.pairingMethod === 'AdjacentAlignment' (or the
correct enum/string for adjacent) based directly on tournament.pairingMethod
before creating TournamentPairingOptions/DraftTournamentPairing; ensure the
dropdown onChange re-computes pairingOptions and passes the fresh object into
the draft generation and status validation routines so switching methods
immediately changes allowed same-alignment behavior.

Comment on lines +3 to +10
/**
* Checks if two competitors have already played each other.
*/

export const checkIfPairingIsRepeat = (
a: DeepTournamentCompetitor,
b: DeepTournamentCompetitor,
): boolean => a.opponentIds.includes(b._id) || b.opponentIds.includes(a._id);
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Minor: Remove extra blank line between JSDoc and function.

There's an extra blank line (Line 6) between the JSDoc comment and the function declaration.

🧹 Suggested cleanup
 /**
  * Checks if two competitors have already played each other.
  */
-
 export const checkIfPairingIsRepeat = (
   a: DeepTournamentCompetitor,
   b: DeepTournamentCompetitor,
 ): boolean => a.opponentIds.includes(b._id) || b.opponentIds.includes(a._id);
📝 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
/**
* Checks if two competitors have already played each other.
*/
export const checkIfPairingIsRepeat = (
a: DeepTournamentCompetitor,
b: DeepTournamentCompetitor,
): boolean => a.opponentIds.includes(b._id) || b.opponentIds.includes(a._id);
/**
* Checks if two competitors have already played each other.
*/
export const checkIfPairingIsRepeat = (
a: DeepTournamentCompetitor,
b: DeepTournamentCompetitor,
): boolean => a.opponentIds.includes(b._id) || b.opponentIds.includes(a._id);
🤖 Prompt for AI Agents
In `@convex/_model/tournamentPairings/_helpers/checkIfPairingIsRepeat.ts` around
lines 3 - 10, Remove the extra blank line between the JSDoc comment and the
function declaration for checkIfPairingIsRepeat; place the JSDoc immediately
above the export const checkIfPairingIsRepeat(...) declaration so the comment is
directly associated with the function.

});
});

// TODO: Tests beyond here may need some clean-up:
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider tracking this TODO.

The TODO suggests these tests may need cleanup. Consider creating an issue to track this technical debt.

Would you like me to open a new issue to track this cleanup task?

🤖 Prompt for AI Agents
In `@convex/_model/tournamentPairings/_helpers/validateTournamentPairing.test.ts`
at line 79, Create a tracked issue for the "TODO: Tests beyond here may need
some clean-up" in
convext/_model/tournamentPairings/_helpers/validateTournamentPairing.test.ts:
open a ticket in our tracker describing what needs cleanup (scope, why, rough
acceptance criteria) and then update the TODO comment in
validateTournamentPairing.test.ts to include the new issue number or link (e.g.,
"TODO (ISSUE-123): ...") so future readers can find the task; also add a brief
note in the PR description referencing the new issue.

@ianpaschal
Copy link
Owner Author

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Jan 31, 2026

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@src/components/TournamentCompetitorIdentity/TournamentCompetitorIdentity.tsx`:
- Around line 62-79: The button is still focusable/announced interactive when no
onClick is provided; update the TournamentCompetitorIdentity component so the
button is disabled whenever onClick is undefined (in addition to the existing
showDisabled check). Change the disabled logic (useDisabledName) to incorporate
onClick (e.g., disabled = showDisabled || !onClick), ensure handleClick remains
safe (it already uses onClick?.(...)) and data-clickable reflects !!onClick so
assistive tech and styles correctly indicate non-interactive state; adjust any
className/attribute logic tied to interactivity accordingly.

@ianpaschal ianpaschal merged commit fd01876 into main Jan 31, 2026
3 checks passed
@ianpaschal ianpaschal deleted the 289-show-alignments-on-tournament-pairings-page branch January 31, 2026 20:55
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.

Show Alignments on Tournament Pairings Page

1 participant