Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions convex/_fixtures/createMockTournament.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import {
CurrencyCode,
GameSystem,
getGameSystem,
tournamentPairingConfig,
} from '@ianpaschal/combat-command-game-systems/common';

import { Doc } from '../_generated/dataModel';
import {
defaultValues as tournamentPairingConfigDefaultValues,
} from '../_model/common/tournamentPairingConfig';
import { RankingFactor } from '../_model/common/types';

const DAY_LENGTH_MS = 172800000;
Expand Down Expand Up @@ -46,7 +48,10 @@ export const createMockTournament = (
currency: CurrencyCode.EUR,
},
roundCount: 5,
pairingConfig: tournamentPairingConfig.defaultValues,
pairingConfig: {
...tournamentPairingConfigDefaultValues,
tableCount: Math.ceil(overrides?.maxCompetitors ?? 48 / 2) ?? 1,
},
Comment on lines +51 to +54
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Operator-precedence bug: division is only applied to the fallback, not to the override.

Due to JavaScript's operator precedence, ?? binds less tightly than /, so overrides?.maxCompetitors ?? 48 / 2 is parsed as overrides?.maxCompetitors ?? (48 / 2) — i.e. overrides?.maxCompetitors ?? 24. When maxCompetitors is supplied as an override (e.g. 32), Math.ceil(32) = 32, but tableCount should be Math.ceil(32 / 2) = 16. The trailing ?? 1 is also dead code since Math.ceil always returns a number.

🐛 Proposed fix
-      tableCount: Math.ceil(overrides?.maxCompetitors ?? 48 / 2) ?? 1,
+      tableCount: Math.ceil((overrides?.maxCompetitors ?? 48) / 2),
📝 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
pairingConfig: {
...tournamentPairingConfigDefaultValues,
tableCount: Math.ceil(overrides?.maxCompetitors ?? 48 / 2) ?? 1,
},
pairingConfig: {
...tournamentPairingConfigDefaultValues,
tableCount: Math.ceil((overrides?.maxCompetitors ?? 48) / 2),
},
🤖 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 `@convex/_fixtures/createMockTournament.ts` around lines 51 - 54, The
tableCount calculation in pairingConfig incorrectly applies the division only to
the fallback due to operator precedence; change the expression so the nullish
coalescing picks the competitor count first and then divide by 2 (e.g. compute
Math.ceil((overrides?.maxCompetitors ?? 48) / 2)), and remove the redundant
trailing ?? 1 since Math.ceil always returns a number; update the expression in
the pairingConfig block that references tournamentPairingConfigDefaultValues and
tableCount accordingly.

gameSystemConfig: gameSystemConfig.defaultValues,
startsAt: Date.now() + (DAY_LENGTH_MS * 3),
endsAt: Date.now() + (DAY_LENGTH_MS * 5),
Expand Down
6 changes: 6 additions & 0 deletions convex/_generated/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ import type * as _model_tournamentRegistrations__helpers_deepenTournamentRegistr
import type * as _model_tournamentRegistrations__helpers_getAvailableActions from "../_model/tournamentRegistrations/_helpers/getAvailableActions.js";
import type * as _model_tournamentRegistrations__helpers_getCreateSuccessMessage from "../_model/tournamentRegistrations/_helpers/getCreateSuccessMessage.js";
import type * as _model_tournamentRegistrations__helpers_getDeleteSuccessMessage from "../_model/tournamentRegistrations/_helpers/getDeleteSuccessMessage.js";
import type * as _model_tournamentRegistrations__helpers_sortTournamentCompetitorsByName from "../_model/tournamentRegistrations/_helpers/sortTournamentCompetitorsByName.js";
import type * as _model_tournamentRegistrations_index from "../_model/tournamentRegistrations/index.js";
import type * as _model_tournamentRegistrations_mutations_createTournamentRegistration from "../_model/tournamentRegistrations/mutations/createTournamentRegistration.js";
import type * as _model_tournamentRegistrations_mutations_deleteTournamentRegistration from "../_model/tournamentRegistrations/mutations/deleteTournamentRegistration.js";
Expand Down Expand Up @@ -233,6 +234,7 @@ import type * as _model_tournaments__helpers_deepenTournament from "../_model/to
import type * as _model_tournaments__helpers_extractSearchTokens from "../_model/tournaments/_helpers/extractSearchTokens.js";
import type * as _model_tournaments__helpers_getAvailableActions from "../_model/tournaments/_helpers/getAvailableActions.js";
import type * as _model_tournaments__helpers_getDisplayName from "../_model/tournaments/_helpers/getDisplayName.js";
import type * as _model_tournaments__helpers_getLastVisibleRound from "../_model/tournaments/_helpers/getLastVisibleRound.js";
import type * as _model_tournaments__helpers_getTournamentDeep from "../_model/tournaments/_helpers/getTournamentDeep.js";
import type * as _model_tournaments__helpers_getTournamentNextRound from "../_model/tournaments/_helpers/getTournamentNextRound.js";
import type * as _model_tournaments__helpers_getTournamentPlayerUserIds from "../_model/tournaments/_helpers/getTournamentPlayerUserIds.js";
Expand All @@ -249,6 +251,7 @@ import type * as _model_tournaments_mutations_startTournamentRound from "../_mod
import type * as _model_tournaments_mutations_toggleTournamentAlignmentsRevealed from "../_model/tournaments/mutations/toggleTournamentAlignmentsRevealed.js";
import type * as _model_tournaments_mutations_toggleTournamentListsRevealed from "../_model/tournaments/mutations/toggleTournamentListsRevealed.js";
import type * as _model_tournaments_mutations_updateTournament from "../_model/tournaments/mutations/updateTournament.js";
import type * as _model_tournaments_mutations_updateTournamentPairingConfig from "../_model/tournaments/mutations/updateTournamentPairingConfig.js";
import type * as _model_tournaments_queries_getTournament from "../_model/tournaments/queries/getTournament.js";
import type * as _model_tournaments_queries_getTournamentByTournamentPairing from "../_model/tournaments/queries/getTournamentByTournamentPairing.js";
import type * as _model_tournaments_queries_getTournamentOpenRound from "../_model/tournaments/queries/getTournamentOpenRound.js";
Expand Down Expand Up @@ -531,6 +534,7 @@ declare const fullApi: ApiFromModules<{
"_model/tournamentRegistrations/_helpers/getAvailableActions": typeof _model_tournamentRegistrations__helpers_getAvailableActions;
"_model/tournamentRegistrations/_helpers/getCreateSuccessMessage": typeof _model_tournamentRegistrations__helpers_getCreateSuccessMessage;
"_model/tournamentRegistrations/_helpers/getDeleteSuccessMessage": typeof _model_tournamentRegistrations__helpers_getDeleteSuccessMessage;
"_model/tournamentRegistrations/_helpers/sortTournamentCompetitorsByName": typeof _model_tournamentRegistrations__helpers_sortTournamentCompetitorsByName;
"_model/tournamentRegistrations/index": typeof _model_tournamentRegistrations_index;
"_model/tournamentRegistrations/mutations/createTournamentRegistration": typeof _model_tournamentRegistrations_mutations_createTournamentRegistration;
"_model/tournamentRegistrations/mutations/deleteTournamentRegistration": typeof _model_tournamentRegistrations_mutations_deleteTournamentRegistration;
Expand Down Expand Up @@ -572,6 +576,7 @@ declare const fullApi: ApiFromModules<{
"_model/tournaments/_helpers/extractSearchTokens": typeof _model_tournaments__helpers_extractSearchTokens;
"_model/tournaments/_helpers/getAvailableActions": typeof _model_tournaments__helpers_getAvailableActions;
"_model/tournaments/_helpers/getDisplayName": typeof _model_tournaments__helpers_getDisplayName;
"_model/tournaments/_helpers/getLastVisibleRound": typeof _model_tournaments__helpers_getLastVisibleRound;
"_model/tournaments/_helpers/getTournamentDeep": typeof _model_tournaments__helpers_getTournamentDeep;
"_model/tournaments/_helpers/getTournamentNextRound": typeof _model_tournaments__helpers_getTournamentNextRound;
"_model/tournaments/_helpers/getTournamentPlayerUserIds": typeof _model_tournaments__helpers_getTournamentPlayerUserIds;
Expand All @@ -588,6 +593,7 @@ declare const fullApi: ApiFromModules<{
"_model/tournaments/mutations/toggleTournamentAlignmentsRevealed": typeof _model_tournaments_mutations_toggleTournamentAlignmentsRevealed;
"_model/tournaments/mutations/toggleTournamentListsRevealed": typeof _model_tournaments_mutations_toggleTournamentListsRevealed;
"_model/tournaments/mutations/updateTournament": typeof _model_tournaments_mutations_updateTournament;
"_model/tournaments/mutations/updateTournamentPairingConfig": typeof _model_tournaments_mutations_updateTournamentPairingConfig;
"_model/tournaments/queries/getTournament": typeof _model_tournaments_queries_getTournament;
"_model/tournaments/queries/getTournamentByTournamentPairing": typeof _model_tournaments_queries_getTournamentByTournamentPairing;
"_model/tournaments/queries/getTournamentOpenRound": typeof _model_tournaments_queries_getTournamentOpenRound;
Expand Down
36 changes: 34 additions & 2 deletions convex/_model/common/tournamentPairingConfig.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,36 @@
import { tournamentPairingConfig as config } from '@ianpaschal/combat-command-game-systems/common';
import { TournamentPairingPolicy } from '@ianpaschal/combat-command-game-systems/common';
import { createEnumSchema } from '@ianpaschal/combat-command-game-systems/utils';
import { zodToConvex } from 'convex-helpers/server/zod';
import { z } from 'zod';

export const tournamentPairingConfig = zodToConvex(config.schema);
import { Id } from '../../_generated/dataModel';

export const schema = z.object({
orderBy: z.union([z.literal('ranking'), z.literal('random')]),
policies: z.object({
sameAlignment: createEnumSchema(TournamentPairingPolicy),
repeat: createEnumSchema(TournamentPairingPolicy),
}),
tableCount: z.optional(z.number().min(1)), // TODO: REMOVE POST MIGRATION
});

export const generationSchema = schema.extend({
include: z.array(z.string()).transform((val): Id<'tournamentCompetitors'>[] => val as Id<'tournamentCompetitors'>[]),
});

export type TournamentPairingConfig = z.infer<typeof schema>;

export type TournamentPairingPolicies = Partial<TournamentPairingConfig['policies']>;

export const defaultValues = {
orderBy: 'ranking',
policies: {
sameAlignment: TournamentPairingPolicy.Allow,
repeat: TournamentPairingPolicy.Block,
},
tableCount: 1,
} satisfies TournamentPairingConfig;

export const tournamentPairingConfig = zodToConvex(schema);

export const tournamentPairingInput = zodToConvex(generationSchema);
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const createTournamentCompetitor = async (
throw new ConvexError(getErrorMessage('CANNOT_MODIFY_ARCHIVED_TOURNAMENT'));
}
const tournamentCompetitors = await ctx.db.query('tournamentCompetitors')
.withIndex('by_tournament_id', (q) => q.eq('tournamentId', args.tournamentId))
.withIndex('by_tournament', (q) => q.eq('tournamentId', args.tournamentId))
.collect();
const existingTeamNames = tournamentCompetitors.map((item) => item.teamName);
if (args.teamName && existingTeamNames.includes(args.teamName)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ export const getTournamentCompetitorsByTournament = async (
ctx: QueryCtx,
args: Infer<typeof getTournamentCompetitorsByTournamentArgs>,
): Promise<DeepTournamentCompetitor[]> => {
const tournamentCompetitors = await ctx.db.query('tournamentCompetitors')
.withIndex('by_tournament_id', (q) => q.eq('tournamentId', args.tournamentId))
const results = await ctx.db.query('tournamentCompetitors')
.withIndex('by_tournament', (q) => q.eq('tournamentId', args.tournamentId))
.collect();
return (await Promise.all(tournamentCompetitors.map(async (item) => (
return (await Promise.all(results.map(async (item) => (
await deepenTournamentCompetitor(ctx, item, args.rankingRound)
)))).sort(sortTournamentCompetitorsByName);
};
2 changes: 1 addition & 1 deletion convex/_model/tournamentCompetitors/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ export default defineTable({
...editableFields,
...computedFields,
})
.index('by_tournament_id', ['tournamentId']);
.index('by_tournament', ['tournamentId']);
2 changes: 1 addition & 1 deletion convex/_model/tournamentPairings/_helpers/assignTables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const assignTables = (
);
playedTablesMap.set(null, []);

const tableCount = (data.tournament?.competitorCount ?? 2) / 2; // TODO: Use actual table count
const tableCount = data.tournament.pairingConfig.tableCount!; // TODO remove assertion post MIGRATION
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid hard dependency on migration completion here.

At Line 23, removing the fallback and forcing pairingConfig.tableCount can break pair generation for tournaments not yet backfilled. Keep a runtime fallback until migration is guaranteed complete in all environments.

Suggested fix
-  const tableCount = data.tournament.pairingConfig.tableCount!; // TODO remove assertion post MIGRATION
+  const tableCount = data.tournament.pairingConfig.tableCount
+    ?? Math.ceil((data.tournament.competitorCount ?? 2) / 2);
📝 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
const tableCount = data.tournament.pairingConfig.tableCount!; // TODO remove assertion post MIGRATION
const tableCount = data.tournament.pairingConfig.tableCount
?? Math.ceil((data.tournament.competitorCount ?? 2) / 2);
🤖 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 `@convex/_model/tournamentPairings/_helpers/assignTables.ts` at line 23, The
code uses a non-null assertion on data.tournament.pairingConfig.tableCount which
will break tournaments not yet migrated; replace the assertion with a
runtime-safe fallback (e.g., use optional chaining and nullish coalescing:
data.tournament.pairingConfig?.tableCount ?? <fallback>) and pick an appropriate
fallback (a constant DEFAULT_TABLE_COUNT, a value derived from
data.tournament/player count, or a domain-specific safe default) inside the
assignTables logic so pair generation still works until migration is complete;
remove the "!" on tableCount and reference the pairingConfig?.tableCount and the
chosen DEFAULT_TABLE_COUNT or computed fallback in the same function.


const draftPairings = pairings.map((p) => ({
...p,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Infer, v } from 'convex/values';

import { api } from '../../../_generated/api';
import { Id } from '../../../_generated/dataModel';
import { ActionCtx } from '../../../_generated/server';
import { tournamentPairingConfig } from '../../common/tournamentPairingConfig';
import { DeepTournamentCompetitor } from '../../tournamentCompetitors';
Expand All @@ -17,11 +18,14 @@ export const generateDraftTournamentPairingsArgs = v.object({
tournamentId: v.id('tournaments'),
round: v.number(),
config: tournamentPairingConfig,
include: v.array(v.id('tournamentCompetitors')),
});

export type GenerateDraftTournamentPairingsArgs = Infer<typeof generateDraftTournamentPairingsArgs>;

export const generateDraftTournamentPairings = async (
ctx: ActionCtx,
args: Infer<typeof generateDraftTournamentPairingsArgs>,
args: GenerateDraftTournamentPairingsArgs,
): Promise<DraftTournamentPairing[]> => {

const tournamentCompetitors = await ctx.runQuery(
Expand All @@ -30,7 +34,9 @@ export const generateDraftTournamentPairings = async (
},
);

const activeCompetitors = tournamentCompetitors.filter(({ active }) => active);
const include = new Set<Id<'tournamentCompetitors'>>(args.include);

const activeCompetitors = tournamentCompetitors.filter((c) => include.has(c._id));

const orderedCompetitors: DeepTournamentCompetitor[] = [];
if (args.config.orderBy === 'ranking') {
Expand Down
5 changes: 4 additions & 1 deletion convex/_model/tournamentPairings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ export {
deepenTournamentPairing,
type TournamentPairingDeep,
} from './_helpers/deepenTournamentPairing';
export { generateDraftPairings } from './_helpers/generateDraftPairings';
export {
generateDraftPairings,
} from './_helpers/generateDraftPairings';
export { TournamentPairingActionKey } from './_helpers/getAvailableActions';
export { getTournamentPairingDeep } from './_helpers/getTournamentPairingDeep';
export { getTournamentPairingShallow } from './_helpers/getTournamentPairingShallow';
Expand All @@ -24,6 +26,7 @@ export type {
// Actions
export {
generateDraftTournamentPairings,
type GenerateDraftTournamentPairingsArgs,
generateDraftTournamentPairingsArgs,
} from './actions/generateDraftTournamentPairings';
export {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,6 @@ export const createTournamentPairings = async (
if (!competitor) {
throw new ConvexError(getErrorMessage('CANNOT_ADD_PAIRING_FOR_MISSING_COMPETITOR'));
}
if (!competitor.active) {
throw new ConvexError(getErrorMessage('CANNOT_ADD_PAIRING_FOR_INACTIVE_COMPETITOR'));
}
if (pairedCompetitorIds.has(id)) {
throw new ConvexError(getErrorMessage('CANNOT_ADD_PAIRING_FOR_ALREADY_PAIRED_COMPETITOR'));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import { getDocStrict } from '../../common/_helpers/getDocStrict';
import { getErrorMessage } from '../../common/errors';
import { getListsByTournamentRegistration } from '../../lists';
import { checkUserIsTournamentOrganizer } from '../../tournamentOrganizers';
import { getTournamentResultsByUser } from '../../tournamentResults';
import { getUser } from '../../users';
import { getAvailableActions } from './getAvailableActions';

/* eslint-disable @typescript-eslint/explicit-function-return-type */
export const deepenTournamentRegistration = async (
ctx: QueryCtx,
doc: Doc<'tournamentRegistrations'>,
round?: number,
) => {
const userId = await getAuthUserId(ctx);
const { details, ...restDoc } = doc;
Expand All @@ -25,6 +27,11 @@ export const deepenTournamentRegistration = async (

const tournament = await getDocStrict(ctx, doc.tournamentId);

const results = await getTournamentResultsByUser(ctx, {
userId: doc.userId,
tournamentId: doc.tournamentId,
round: round ?? tournament?.lastRound ?? 0,
});
const availableActions = await getAvailableActions(ctx, doc);

const isOrganizer = await checkUserIsTournamentOrganizer(ctx, tournament._id, userId);
Expand All @@ -43,6 +50,7 @@ export const deepenTournamentRegistration = async (

return {
...restDoc,
...results,
availableActions,
details: visibleDetails,
user,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { DeepTournamentRegistration } from './deepenTournamentRegistration';

export const sortTournamentRegistrationsByName = (
a: DeepTournamentRegistration,
b: DeepTournamentRegistration,
): number => a.displayName.localeCompare(b.displayName);
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,21 @@ import {
deepenTournamentRegistration,
DeepTournamentRegistration,
} from '../_helpers/deepenTournamentRegistration';
import { sortTournamentRegistrationsByName } from '../_helpers/sortTournamentCompetitorsByName';

export const getTournamentRegistrationsByTournamentArgs = v.object({
tournamentId: v.id('tournaments'),
rankingRound: v.optional(v.number()),
});

export const getTournamentRegistrationsByTournament = async (
ctx: QueryCtx,
args: Infer<typeof getTournamentRegistrationsByTournamentArgs>,
): Promise<DeepTournamentRegistration[]> => {
const tournamentRegistrations = await ctx.db.query('tournamentRegistrations')
const results = await ctx.db.query('tournamentRegistrations')
.withIndex('by_tournament', (q) => q.eq('tournamentId', args.tournamentId))
.collect();
return await Promise.all(
tournamentRegistrations.map(async (registration) => await deepenTournamentRegistration(ctx, registration)),
);
return (await Promise.all(results.map(async (item) => (
await deepenTournamentRegistration(ctx, item, args.rankingRound)
)))).sort(sortTournamentRegistrationsByName);
};
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const aggregateTournamentData = async (
.withIndex('by_tournament', (q) => q.eq('tournamentId', tournament._id))
.collect();
const tournamentCompetitors = await ctx.db.query('tournamentCompetitors')
.withIndex('by_tournament_id', (q) => q.eq('tournamentId', tournament._id))
.withIndex('by_tournament', (q) => q.eq('tournamentId', tournament._id))
.collect();
const tournamentPairings = await ctx.db.query('tournamentPairings')
.withIndex('by_tournament_id', (q) => q.eq('tournamentId', tournament._id))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const refreshTournamentResult = async (
throw new ConvexError(getErrorMessage('TOURNAMENT_NOT_FOUND'));
}
const tournamentCompetitors = await ctx.db.query('tournamentCompetitors')
.withIndex('by_tournament_id', (q) => q.eq('tournamentId', args.tournamentId))
.withIndex('by_tournament', (q) => q.eq('tournamentId', args.tournamentId))
.collect();
const tournamentRegistrations = await ctx.db.query('tournamentRegistrations')
.withIndex('by_tournament', (q) => q.eq('tournamentId', args.tournamentId))
Expand Down
33 changes: 18 additions & 15 deletions convex/_model/tournaments/_helpers/deepenTournament.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '../../tournamentOrganizers';
import { getAvailableActions } from './getAvailableActions';
import { getDisplayName } from './getDisplayName';
import { getLastVisibleRound } from './getLastVisibleRound';
import { getTournamentNextRound } from './getTournamentNextRound';

/* eslint-disable @typescript-eslint/explicit-function-return-type */
Expand All @@ -24,43 +25,45 @@ import { getTournamentNextRound } from './getTournamentNextRound';
*/
export const deepenTournament = async (
ctx: QueryCtx,
tournament: Doc<'tournaments'>,
doc: Doc<'tournaments'>,
) => {
const userId = await getAuthUserId(ctx);
const logoUrl = await getStorageUrl(ctx, tournament.logoStorageId);
const bannerUrl = await getStorageUrl(ctx, tournament.bannerStorageId);
const availableActions = await getAvailableActions(ctx, tournament);
const logoUrl = await getStorageUrl(ctx, doc.logoStorageId);
const bannerUrl = await getStorageUrl(ctx, doc.bannerStorageId);
const availableActions = await getAvailableActions(ctx, doc);
const tournamentOrganizers = await getTournamentOrganizersByTournament(ctx, {
tournamentId: tournament._id,
tournamentId: doc._id,
});
const isOrganizer = await checkUserIsTournamentOrganizer(ctx, tournament._id, userId);
const lastVisibleRound = await getLastVisibleRound(ctx, doc);
const isOrganizer = await checkUserIsTournamentOrganizer(ctx, doc._id, userId);
const tournamentCompetitors = await ctx.db.query('tournamentCompetitors')
.withIndex('by_tournament_id', (q) => q.eq('tournamentId', tournament._id))
.withIndex('by_tournament', (q) => q.eq('tournamentId', doc._id))
.collect();
const tournamentRegistrations = await ctx.db.query('tournamentRegistrations')
.withIndex('by_tournament', (q) => q.eq('tournamentId', tournament._id))
.withIndex('by_tournament', (q) => q.eq('tournamentId', doc._id))
.collect();

const playerUserIds = tournamentRegistrations.map((r) => r.userId);
const activePlayerUserIds = tournamentRegistrations.filter((r) => r.active).map((p) => p.userId);

return {
...tournament,
...doc,
activePlayerCount: activePlayerUserIds.length,
activePlayerUserIds,
alignmentsVisible: isOrganizer || tournament.alignmentsRevealed,
alignmentsVisible: isOrganizer || doc.alignmentsRevealed,
availableActions,
bannerUrl,
competitorCount: tournamentCompetitors.length,
displayName: getDisplayName(tournament),
factionsVisible: isOrganizer || tournament.factionsRevealed,
displayName: getDisplayName(doc),
factionsVisible: isOrganizer || doc.factionsRevealed,
lastRound: lastVisibleRound,
logoUrl,
maxPlayers : tournament.maxCompetitors * tournament.competitorSize,
nextRound: getTournamentNextRound(tournament),
maxPlayers : doc.maxCompetitors * doc.competitorSize,
nextRound: getTournamentNextRound(doc),
organizers: tournamentOrganizers,
playerCount: playerUserIds.length,
playerUserIds,
useTeams: tournament.competitorSize > 1,
useTeams: doc.competitorSize > 1,
};
};

Expand Down
Loading