From 298d0f5373c542bfe75c8fc1b5eaff3076288ca5 Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Mon, 2 Mar 2026 16:59:17 +0100 Subject: [PATCH 1/2] #306 Allow TOs to reveal and hide lists --- convex/_generated/api.d.ts | 2 ++ .../_helpers/getAvailableActions.ts | 3 ++ convex/_model/tournaments/index.ts | 4 +++ .../toggleTournamentListsRevealed.ts | 34 +++++++++++++++++++ convex/tournaments.ts | 5 +++ .../useToggleAlignmentsRevealedAction.ts | 2 +- .../actions/useToggleListsRevealedAction.ts | 22 ++++++++++++ src/services/tournaments.ts | 1 + 8 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 convex/_model/tournaments/mutations/toggleTournamentListsRevealed.ts create mode 100644 src/components/TournamentProvider/actions/useToggleListsRevealedAction.ts diff --git a/convex/_generated/api.d.ts b/convex/_generated/api.d.ts index 0b24d09b..be12e3e6 100644 --- a/convex/_generated/api.d.ts +++ b/convex/_generated/api.d.ts @@ -245,6 +245,7 @@ import type * as _model_tournaments_mutations_publishTournament from "../_model/ import type * as _model_tournaments_mutations_startTournament from "../_model/tournaments/mutations/startTournament.js"; import type * as _model_tournaments_mutations_startTournamentRound from "../_model/tournaments/mutations/startTournamentRound.js"; 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_queries_getTournament from "../_model/tournaments/queries/getTournament.js"; import type * as _model_tournaments_queries_getTournamentByTournamentPairing from "../_model/tournaments/queries/getTournamentByTournamentPairing.js"; @@ -575,6 +576,7 @@ declare const fullApi: ApiFromModules<{ "_model/tournaments/mutations/startTournament": typeof _model_tournaments_mutations_startTournament; "_model/tournaments/mutations/startTournamentRound": typeof _model_tournaments_mutations_startTournamentRound; "_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/queries/getTournament": typeof _model_tournaments_queries_getTournament; "_model/tournaments/queries/getTournamentByTournamentPairing": typeof _model_tournaments_queries_getTournamentByTournamentPairing; diff --git a/convex/_model/tournaments/_helpers/getAvailableActions.ts b/convex/_model/tournaments/_helpers/getAvailableActions.ts index 1adf1ac1..6db8f533 100644 --- a/convex/_model/tournaments/_helpers/getAvailableActions.ts +++ b/convex/_model/tournaments/_helpers/getAvailableActions.ts @@ -33,6 +33,8 @@ export enum TournamentActionKey { ToggleFactionsRevealed = 'toggleFactionsRevealed', + ToggleListsRevealed = 'toggleListsRevealed', + /** Set a published Tournament's status to 'active'. */ Start = 'start', @@ -127,6 +129,7 @@ export const getAvailableActions = async ( if (isOrganizer) { actions.push(TournamentActionKey.ToggleAlignmentsRevealed); actions.push(TournamentActionKey.ToggleFactionsRevealed); + actions.push(TournamentActionKey.ToggleListsRevealed); } if (isOrganizer && doc.status === 'published') { // TODO: Check for at least 2 competitors diff --git a/convex/_model/tournaments/index.ts b/convex/_model/tournaments/index.ts index 13fb519a..fedd894d 100644 --- a/convex/_model/tournaments/index.ts +++ b/convex/_model/tournaments/index.ts @@ -53,6 +53,10 @@ export { toggleTournamentAlignmentsRevealed, toggleTournamentAlignmentsRevealedArgs, } from './mutations/toggleTournamentAlignmentsRevealed'; +export { + toggleTournamentListsRevealed, + toggleTournamentListsRevealedArgs, +} from './mutations/toggleTournamentListsRevealed'; export { updateTournament, updateTournamentArgs, diff --git a/convex/_model/tournaments/mutations/toggleTournamentListsRevealed.ts b/convex/_model/tournaments/mutations/toggleTournamentListsRevealed.ts new file mode 100644 index 00000000..d5d875af --- /dev/null +++ b/convex/_model/tournaments/mutations/toggleTournamentListsRevealed.ts @@ -0,0 +1,34 @@ +import { + ConvexError, + Infer, + v, +} from 'convex/values'; + +import { MutationCtx } from '../../../_generated/server'; +import { getDocStrict } from '../../common/_helpers/getDocStrict'; +import { getErrorMessage } from '../../common/errors'; +import { getAvailableActions, TournamentActionKey } from '../_helpers/getAvailableActions'; + +export const toggleTournamentListsRevealedArgs = v.object({ + id: v.id('tournaments'), +}); + +export const toggleTournamentListsRevealed = async ( + ctx: MutationCtx, + args: Infer, +): Promise => { + + // --- AUTH ---- + const tournament = await getDocStrict(ctx, args.id); + const availableActions = await getAvailableActions(ctx, tournament); + if (!availableActions.includes(TournamentActionKey.ToggleListsRevealed)) { + throw new ConvexError(getErrorMessage('USER_DOES_NOT_HAVE_PERMISSION')); + } + + // ---- PRIMARY ACTIONS ---- + const listsRevealed = !tournament.listsRevealed; + await ctx.db.patch(args.id, { + listsRevealed, + }); + return listsRevealed; +}; diff --git a/convex/tournaments.ts b/convex/tournaments.ts index b61b8866..f9496111 100644 --- a/convex/tournaments.ts +++ b/convex/tournaments.ts @@ -45,6 +45,11 @@ export const toggleTournamentAlignmentsRevealed = mutation({ handler: model.toggleTournamentAlignmentsRevealed, }); +export const toggleTournamentListsRevealed = mutation({ + args: model.toggleTournamentListsRevealedArgs, + handler: model.toggleTournamentListsRevealed, +}); + export const endTournamentRound = mutation({ args: model.endTournamentRoundArgs, handler: model.endTournamentRound, diff --git a/src/components/TournamentProvider/actions/useToggleAlignmentsRevealedAction.ts b/src/components/TournamentProvider/actions/useToggleAlignmentsRevealedAction.ts index 796b6457..ceb64d2d 100644 --- a/src/components/TournamentProvider/actions/useToggleAlignmentsRevealedAction.ts +++ b/src/components/TournamentProvider/actions/useToggleAlignmentsRevealedAction.ts @@ -9,7 +9,7 @@ export const useToggleAlignmentsRevealedAction = ( subject: Tournament, ): ActionDefinition | null => { const { mutation } = useToggleTournamentAlignmentsRevealed({ - onSuccess: (revealed): void => toast.success(`${subject.displayName} is now ${revealed ? 'active' : 'inactive'}.`), + onSuccess: (revealed): void => toast.success(revealed ? 'Alignments are now visible to all players.' : 'Alignments are now hidden.'), }); if (subject.availableActions.includes(KEY)) { return { diff --git a/src/components/TournamentProvider/actions/useToggleListsRevealedAction.ts b/src/components/TournamentProvider/actions/useToggleListsRevealedAction.ts new file mode 100644 index 00000000..709433b4 --- /dev/null +++ b/src/components/TournamentProvider/actions/useToggleListsRevealedAction.ts @@ -0,0 +1,22 @@ +import { Tournament, TournamentActionKey } from '~/api'; +import { ActionDefinition } from '~/components/ContextMenu/ContextMenu.types'; +import { toast } from '~/components/ToastProvider'; +import { useToggleTournamentListsRevealed } from '~/services/tournaments'; + +const KEY = TournamentActionKey.ToggleListsRevealed; + +export const useToggleListsRevealedAction = ( + subject: Tournament, +): ActionDefinition | null => { + const { mutation } = useToggleTournamentListsRevealed({ + onSuccess: (revealed): void => toast.success(revealed ? 'Lists are now visible to all players.' : 'Lists are now hidden.'), + }); + if (subject.availableActions.includes(KEY)) { + return { + key: KEY, + label: subject.alignmentsRevealed ? 'Hide Lists' : 'Reveal Lists', + handler: () => mutation({ id: subject._id }), + }; + } + return null; +}; diff --git a/src/services/tournaments.ts b/src/services/tournaments.ts index 3d0ceac1..cc6cfd11 100644 --- a/src/services/tournaments.ts +++ b/src/services/tournaments.ts @@ -23,6 +23,7 @@ export const usePublishTournament = createMutationHook(api.tournaments.publishTo export const useStartTournament = createMutationHook(api.tournaments.startTournament); export const useStartTournamentRound = createMutationHook(api.tournaments.startTournamentRound); export const useToggleTournamentAlignmentsRevealed = createMutationHook(api.tournaments.toggleTournamentAlignmentsRevealed); +export const useToggleTournamentListsRevealed = createMutationHook(api.tournaments.toggleTournamentListsRevealed); // Actions export const useExportFowV4TournamentMatchData = createActionHook(api.tournaments.exportFowV4TournamentMatchData); From 311343c7131a8fdf356782b71b22b490750ecefc Mon Sep 17 00:00:00 2001 From: Ian Paschal Date: Mon, 2 Mar 2026 17:11:50 +0100 Subject: [PATCH 2/2] Update src/components/TournamentProvider/actions/useToggleListsRevealedAction.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../TournamentProvider/actions/useToggleListsRevealedAction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/TournamentProvider/actions/useToggleListsRevealedAction.ts b/src/components/TournamentProvider/actions/useToggleListsRevealedAction.ts index 709433b4..a8ed28fa 100644 --- a/src/components/TournamentProvider/actions/useToggleListsRevealedAction.ts +++ b/src/components/TournamentProvider/actions/useToggleListsRevealedAction.ts @@ -14,7 +14,7 @@ export const useToggleListsRevealedAction = ( if (subject.availableActions.includes(KEY)) { return { key: KEY, - label: subject.alignmentsRevealed ? 'Hide Lists' : 'Reveal Lists', + label: subject.listsRevealed ? 'Hide Lists' : 'Reveal Lists', handler: () => mutation({ id: subject._id }), }; }