diff --git a/app/db/seed/index.ts b/app/db/seed/index.ts index a886e2936..c62acc7b8 100644 --- a/app/db/seed/index.ts +++ b/app/db/seed/index.ts @@ -893,6 +893,7 @@ function calendarEventWithToTools( sources: [{ bracketIdx: 0, placements: [4] }], }, ], + enableNoScreenToggle: true, } : event === "PP" ? { diff --git a/app/db/tables.ts b/app/db/tables.ts index e6c8641cb..4d6d06c41 100644 --- a/app/db/tables.ts +++ b/app/db/tables.ts @@ -389,6 +389,7 @@ export interface TournamentSettings { thirdPlaceMatch?: boolean; isRanked?: boolean; autoCheckInAll?: boolean; + enableNoScreenToggle?: boolean; } export interface CastedMatchesInfo { @@ -514,6 +515,7 @@ export interface TournamentTeam { inviteCode: string; name: string; prefersNotToHost: Generated; + noScreen: Generated; seed: number | null; tournamentId: number; } diff --git a/app/features/calendar/CalendarRepository.server.ts b/app/features/calendar/CalendarRepository.server.ts index 56fedfe51..c94e9d6c2 100644 --- a/app/features/calendar/CalendarRepository.server.ts +++ b/app/features/calendar/CalendarRepository.server.ts @@ -388,6 +388,7 @@ type CreateArgs = Pick< thirdPlaceMatch?: boolean; autoCheckInAll?: boolean; isRanked?: boolean; + enableNoScreenToggle?: boolean; }; export async function create(args: CreateArgs) { return db.transaction().execute(async (trx) => { @@ -399,6 +400,7 @@ export async function create(args: CreateArgs) { teamsPerGroup: args.teamsPerGroup, thirdPlaceMatch: args.thirdPlaceMatch, isRanked: args.isRanked, + enableNoScreenToggle: args.enableNoScreenToggle, autoCheckInAll: args.autoCheckInAll, }; @@ -474,6 +476,7 @@ export async function update(args: UpdateArgs) { teamsPerGroup: args.teamsPerGroup, thirdPlaceMatch: args.thirdPlaceMatch, isRanked: args.isRanked, + enableNoScreenToggle: args.enableNoScreenToggle, autoCheckInAll: args.autoCheckInAll, }; diff --git a/app/features/calendar/calendar-schemas.server.ts b/app/features/calendar/calendar-schemas.server.ts index e294da20a..f561981b8 100644 --- a/app/features/calendar/calendar-schemas.server.ts +++ b/app/features/calendar/calendar-schemas.server.ts @@ -71,6 +71,10 @@ export const newCalendarEventActionSchema = z toToolsEnabled: z.preprocess(checkboxValueToBoolean, z.boolean()), toToolsMode: z.enum(["ALL", "TO", "SZ", "TC", "RM", "CB"]).optional(), isRanked: z.preprocess(checkboxValueToBoolean, z.boolean().nullish()), + enableNoScreenToggle: z.preprocess( + checkboxValueToBoolean, + z.boolean().nullish(), + ), // // tournament format related fields // diff --git a/app/features/calendar/routes/calendar.new.tsx b/app/features/calendar/routes/calendar.new.tsx index f13331e41..8a4ea9071 100644 --- a/app/features/calendar/routes/calendar.new.tsx +++ b/app/features/calendar/routes/calendar.new.tsx @@ -118,6 +118,7 @@ export const action: ActionFunction = async ({ request }) => { teamsPerGroup: data.teamsPerGroup ?? undefined, thirdPlaceMatch: data.thirdPlaceMatch ?? undefined, isRanked: data.isRanked ?? undefined, + enableNoScreenToggle: data.enableNoScreenToggle ?? undefined, autoCheckInAll: data.autoCheckInAll ?? undefined, }; validate( @@ -263,6 +264,7 @@ export default function CalendarNewEventPage() { <> Tournament settings + ) : null} {isTournament ? ( @@ -647,6 +649,33 @@ function RankedToggle() { ); } +function EnableNoScreenToggle() { + const data = useLoaderData(); + const [enableNoScreen, setEnableNoScreen] = React.useState( + data.tournamentCtx?.settings.enableNoScreenToggle ?? true, + ); + const id = React.useId(); + + return ( +
+ + + + When registering ask teams if they want to play without Splattercolor + Screen. + +
+ ); +} + const mapPickingStyleToShort: Record< Tables["Tournament"]["mapPickingStyle"], "ALL" | "TO" | RankedModeShort diff --git a/app/features/sendouq/routes/q.match.$id.tsx b/app/features/sendouq/routes/q.match.$id.tsx index eded3fe7d..51e10d4cf 100644 --- a/app/features/sendouq/routes/q.match.$id.tsx +++ b/app/features/sendouq/routes/q.match.$id.tsx @@ -1269,7 +1269,7 @@ function BottomSection({ } function ScreenLegalityInfo({ ban }: { ban: boolean }) { - const { t } = useTranslation(["q", "weapons", "weapons"]); + const { t } = useTranslation(["q", "weapons"]); return (
@@ -1282,7 +1282,7 @@ function ScreenLegalityInfo({ ban }: { ban: boolean }) { path={specialWeaponImageUrl(SPLATTERCOLOR_SCREEN_ID)} width={30} height={30} - alt={`weapons:SPECIAL_${SPLATTERCOLOR_SCREEN_ID}`} + alt={t(`weapons:SPECIAL_${SPLATTERCOLOR_SCREEN_ID}`)} />
diff --git a/app/features/tournament-bracket/components/ScoreReporter.tsx b/app/features/tournament-bracket/components/ScoreReporter.tsx index 23982a2c1..308f49a57 100644 --- a/app/features/tournament-bracket/components/ScoreReporter.tsx +++ b/app/features/tournament-bracket/components/ScoreReporter.tsx @@ -14,7 +14,11 @@ import type { ModeShort, StageId } from "~/modules/in-game-lists"; import type { TournamentMapListMap } from "~/modules/tournament-map-list-generator"; import { databaseTimestampToDate } from "~/utils/dates"; import type { Unpacked } from "~/utils/types"; -import { modeImageUrl, stageImageUrl } from "~/utils/urls"; +import { + modeImageUrl, + specialWeaponImageUrl, + stageImageUrl, +} from "~/utils/urls"; import { type TournamentMatchLoaderData } from "../routes/to.$id.matches.$mid"; import { mapCountPlayedInSetWithCertainty, @@ -24,6 +28,9 @@ import { } from "../tournament-bracket-utils"; import { ScoreReporterRosters } from "./ScoreReporterRosters"; import type { TournamentDataTeam } from "../core/Tournament.server"; +import { CrossIcon } from "~/components/icons/Cross"; +import { CheckmarkIcon } from "~/components/icons/Checkmark"; +import { SPLATTERCOLOR_SCREEN_ID } from "~/modules/in-game-lists/weapon-ids"; export type Result = Unpacked< SerializeFrom["results"] @@ -107,6 +114,9 @@ export function ScoreReporter({ bestOf: data.match.bestOf, })} , + tournament.ctx.settings.enableNoScreenToggle ? ( + team.noScreen)} /> + ) : null, ]; return ( @@ -497,3 +507,24 @@ function ActionSectionWrapper({ ); } + +function ScreenBanIcons({ banned }: { banned: boolean }) { + const { t } = useTranslation(["weapons"]); + + return ( +
+ {banned ? : } + {t(`weapons:SPECIAL_${SPLATTERCOLOR_SCREEN_ID}`)} +
+ ); +} diff --git a/app/features/tournament-bracket/core/summarizer.test.ts b/app/features/tournament-bracket/core/summarizer.test.ts index 4af3b21e0..8a73527a2 100644 --- a/app/features/tournament-bracket/core/summarizer.test.ts +++ b/app/features/tournament-bracket/core/summarizer.test.ts @@ -27,6 +27,7 @@ const createTeam = (teamId: number, userIds: number[]): TournamentDataTeam => ({ })), name: "Team " + teamId, prefersNotToHost: 0, + noScreen: 0, seed: 1, }); diff --git a/app/features/tournament-bracket/core/tests/mocks.ts b/app/features/tournament-bracket/core/tests/mocks.ts index 5126af88e..32dcfdc19 100644 --- a/app/features/tournament-bracket/core/tests/mocks.ts +++ b/app/features/tournament-bracket/core/tests/mocks.ts @@ -2345,6 +2345,7 @@ export const PADDLING_POOL_257 = () => name: "Le classique à Cam", seed: 1, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709743534, members: [ @@ -2447,6 +2448,7 @@ export const PADDLING_POOL_257 = () => name: "New Generation", seed: 2, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709737918, members: [ @@ -2561,6 +2563,7 @@ export const PADDLING_POOL_257 = () => name: "Mafia mbappe", seed: 3, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709743523, members: [ @@ -2663,6 +2666,7 @@ export const PADDLING_POOL_257 = () => name: "better gaming chair", seed: 4, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709743262, members: [ @@ -2765,6 +2769,7 @@ export const PADDLING_POOL_257 = () => name: "Seaya", seed: 5, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709741396, members: [ @@ -2879,6 +2884,7 @@ export const PADDLING_POOL_257 = () => name: "NEVER BACK DOWN NEVER WHAT?", seed: 6, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709711811, members: [ @@ -2993,6 +2999,7 @@ export const PADDLING_POOL_257 = () => name: "Hazard", seed: 7, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709738831, members: [ @@ -3107,6 +3114,7 @@ export const PADDLING_POOL_257 = () => name: "ASC Shokkai ", seed: 8, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709737837, members: [ @@ -3209,6 +3217,7 @@ export const PADDLING_POOL_257 = () => name: "Naw, I’d win", seed: 9, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709741719, members: [ @@ -3335,6 +3344,7 @@ export const PADDLING_POOL_257 = () => name: "Chippeur arrête de Chipper", seed: 10, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709730354, members: [ @@ -3449,6 +3459,7 @@ export const PADDLING_POOL_257 = () => name: "There’s a snake in my boot 🐍", seed: 11, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709745630, members: [ @@ -3689,6 +3700,7 @@ export const PADDLING_POOL_257 = () => name: "ASC Niji", seed: 13, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709723749, members: [ @@ -3803,6 +3815,7 @@ export const PADDLING_POOL_257 = () => name: "Smoking Moais ", seed: 14, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709668399, members: [ @@ -3929,6 +3942,7 @@ export const PADDLING_POOL_257 = () => name: "SAN DIMAS HS FOOTBALL RULES!", seed: 15, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709735267, members: [ @@ -4035,6 +4049,7 @@ export const PADDLING_POOL_257 = () => name: "Pickup oder so ig", seed: 16, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709745849, members: [ @@ -4141,6 +4156,7 @@ export const PADDLING_POOL_257 = () => name: "DistInkt", seed: 17, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709742258, members: [ @@ -4369,6 +4385,7 @@ export const PADDLING_POOL_257 = () => name: "Blaze", seed: 19, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709746054, members: [ @@ -4577,6 +4594,7 @@ export const PADDLING_POOL_257 = () => name: "Squid Emoji", seed: 21, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709728278, members: [ @@ -4679,6 +4697,7 @@ export const PADDLING_POOL_257 = () => name: "Müll🚮", seed: 22, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709715006, members: [ @@ -4781,6 +4800,7 @@ export const PADDLING_POOL_257 = () => name: "Rogueport Rascals", seed: 23, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709660578, members: [ @@ -4887,6 +4907,7 @@ export const PADDLING_POOL_257 = () => name: "Shade", seed: 24, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709721869, members: [ @@ -5111,6 +5132,7 @@ export const PADDLING_POOL_257 = () => name: "Second Try", seed: 26, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709738747, members: [ @@ -5229,6 +5251,7 @@ export const PADDLING_POOL_257 = () => name: "1HP", seed: 27, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709626047, members: [ @@ -5343,6 +5366,7 @@ export const PADDLING_POOL_257 = () => name: "Préférence Pêche ", seed: 28, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709727951, members: [ @@ -5445,6 +5469,7 @@ export const PADDLING_POOL_257 = () => name: "AquaSonix", seed: 29, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709741482, members: [ @@ -5677,6 +5702,7 @@ export const PADDLING_POOL_257 = () => name: "Intrusive thoughts ", seed: 31, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709726536, members: [ @@ -5779,6 +5805,7 @@ export const PADDLING_POOL_257 = () => name: "Heaven sent Lunatics", seed: 32, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709558706, members: [ @@ -5885,6 +5912,7 @@ export const PADDLING_POOL_257 = () => name: "<_>Placeholder", seed: 33, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709744323, members: [ @@ -6003,6 +6031,7 @@ export const PADDLING_POOL_257 = () => name: "Big Tommy and the Flops", seed: 34, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709677397, members: [ @@ -6105,6 +6134,7 @@ export const PADDLING_POOL_257 = () => name: "G Gaming Gaming", seed: 35, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1709618711, members: [ @@ -8199,6 +8229,7 @@ export const PADDLING_POOL_255 = () => name: "Enperries 200p", seed: 2, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708535137, members: [ @@ -8301,6 +8332,7 @@ export const PADDLING_POOL_255 = () => name: "allo kayora ?", seed: 3, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708533764, members: [ @@ -8529,6 +8561,7 @@ export const PADDLING_POOL_255 = () => name: "Rule them", seed: 5, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708533309, members: [ @@ -8631,6 +8664,7 @@ export const PADDLING_POOL_255 = () => name: "NEVER BACK DOWN NEVER WHAT", seed: 6, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708430641, members: [ @@ -8745,6 +8779,7 @@ export const PADDLING_POOL_255 = () => name: "iPad jaune", seed: 7, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708536306, members: [ @@ -8949,6 +8984,7 @@ export const PADDLING_POOL_255 = () => name: "Hazard", seed: 9, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708506060, members: [ @@ -9075,6 +9111,7 @@ export const PADDLING_POOL_255 = () => name: "ASC Shokkai ", seed: 10, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708526814, members: [ @@ -9291,6 +9328,7 @@ export const PADDLING_POOL_255 = () => name: "Smoking Moais ", seed: 12, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708377426, members: [ @@ -9531,6 +9569,7 @@ export const PADDLING_POOL_255 = () => name: "https://youtu.be/Euq7uTeYCP0?si=", seed: 14, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708532602, members: [ @@ -9633,6 +9672,7 @@ export const PADDLING_POOL_255 = () => name: "Gambawaffeln", seed: 15, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708535205, members: [ @@ -9747,6 +9787,7 @@ export const PADDLING_POOL_255 = () => name: "ici ça bzzz", seed: 16, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708515945, members: [ @@ -9849,6 +9890,7 @@ export const PADDLING_POOL_255 = () => name: "Amoura", seed: 17, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708453334, members: [ @@ -10065,6 +10107,7 @@ export const PADDLING_POOL_255 = () => name: "Grandma Sicko Mode", seed: 19, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708375443, members: [ @@ -10179,6 +10222,7 @@ export const PADDLING_POOL_255 = () => name: "youtube.com/watch?v=dQw4w9WgXcQ", seed: 20, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708532665, members: [ @@ -10285,6 +10329,7 @@ export const PADDLING_POOL_255 = () => name: "Müll🚮", seed: 21, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708364254, members: [ @@ -10403,6 +10448,7 @@ export const PADDLING_POOL_255 = () => name: "Hisense RL170D4BWE Freestanding ", seed: 22, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708464101, members: [ @@ -10635,6 +10681,7 @@ export const PADDLING_POOL_255 = () => name: "Blaze", seed: 24, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708535804, members: [ @@ -10737,6 +10784,7 @@ export const PADDLING_POOL_255 = () => name: "Squid Emoji", seed: 25, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708535891, members: [ @@ -10851,6 +10899,7 @@ export const PADDLING_POOL_255 = () => name: "DistInkt", seed: 26, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708521749, members: [ @@ -10965,6 +11014,7 @@ export const PADDLING_POOL_255 = () => name: "We Are Innocent Caterpillars", seed: 27, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708536584, members: [ @@ -11067,6 +11117,7 @@ export const PADDLING_POOL_255 = () => name: "Ink Souls Maria", seed: 28, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708537772, members: [ @@ -11197,6 +11248,7 @@ export const PADDLING_POOL_255 = () => name: "Yoghurt Party", seed: 29, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708379916, members: [ @@ -11311,6 +11363,7 @@ export const PADDLING_POOL_255 = () => name: "Second Try", seed: 30, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708519753, members: [ @@ -11429,6 +11482,7 @@ export const PADDLING_POOL_255 = () => name: "ASC Niji~K", seed: 31, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708534312, members: [ @@ -11649,6 +11703,7 @@ export const PADDLING_POOL_255 = () => name: "Stream easy by lesserafim", seed: 33, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708477155, members: [ @@ -11755,6 +11810,7 @@ export const PADDLING_POOL_255 = () => name: "Bloody Wave", seed: 34, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708531564, members: [ @@ -11897,6 +11953,7 @@ export const PADDLING_POOL_255 = () => name: "Fresh takos ", seed: 35, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1708503356, members: [ @@ -14157,6 +14214,7 @@ export const IN_THE_ZONE_32 = () => name: "Starburst", seed: 1, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707443313, members: [ @@ -14247,6 +14305,7 @@ export const IN_THE_ZONE_32 = () => name: "Jackpot", seed: 2, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707366405, members: [ @@ -14337,6 +14396,7 @@ export const IN_THE_ZONE_32 = () => name: "Grougrou ", seed: 3, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1706912643, members: [ @@ -14427,6 +14487,7 @@ export const IN_THE_ZONE_32 = () => name: "atomic bomb ", seed: 4, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707359335, members: [ @@ -14541,6 +14602,7 @@ export const IN_THE_ZONE_32 = () => name: "Celeste", seed: 5, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707171426, members: [ @@ -14643,6 +14705,7 @@ export const IN_THE_ZONE_32 = () => name: "Moonlight", seed: 6, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707342696, members: [ @@ -14745,6 +14808,7 @@ export const IN_THE_ZONE_32 = () => name: "BEt", seed: 7, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707513942, members: [ @@ -14859,6 +14923,7 @@ export const IN_THE_ZONE_32 = () => name: "As you wish", seed: 8, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707526815, members: [ @@ -14973,6 +15038,7 @@ export const IN_THE_ZONE_32 = () => name: "UK MAFIA", seed: 9, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707583385, members: [ @@ -15063,6 +15129,7 @@ export const IN_THE_ZONE_32 = () => name: "Black Lotus ", seed: 10, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707486395, members: [ @@ -15153,6 +15220,7 @@ export const IN_THE_ZONE_32 = () => name: "ASC Tenshi", seed: 11, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707513290, members: [ @@ -15243,6 +15311,7 @@ export const IN_THE_ZONE_32 = () => name: "Hypernova", seed: 12, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707531084, members: [ @@ -15333,6 +15402,7 @@ export const IN_THE_ZONE_32 = () => name: "Zenith", seed: 13, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707568466, members: [ @@ -15435,6 +15505,7 @@ export const IN_THE_ZONE_32 = () => name: "Yaotl Teotl", seed: 14, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707481625, members: [ @@ -15525,6 +15596,7 @@ export const IN_THE_ZONE_32 = () => name: "FOAMS 34", seed: 15, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707530166, members: [ @@ -15615,6 +15687,7 @@ export const IN_THE_ZONE_32 = () => name: "New Generation ", seed: 16, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707181792, members: [ @@ -15717,6 +15790,7 @@ export const IN_THE_ZONE_32 = () => name: "Gen BOB Ten-Piece Chicken Nugget", seed: 17, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707550321, members: [ @@ -15823,6 +15897,7 @@ export const IN_THE_ZONE_32 = () => name: "Joga Bonito", seed: 18, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707575096, members: [ @@ -15925,6 +16000,7 @@ export const IN_THE_ZONE_32 = () => name: "JumpingCatapult ", seed: 19, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707569490, members: [ @@ -16039,6 +16115,7 @@ export const IN_THE_ZONE_32 = () => name: "metal pipe", seed: 20, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707537425, members: [ @@ -16129,6 +16206,7 @@ export const IN_THE_ZONE_32 = () => name: "Gentlemates", seed: 21, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707564691, members: [ @@ -16247,6 +16325,7 @@ export const IN_THE_ZONE_32 = () => name: "Hades", seed: 22, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707145818, members: [ @@ -16344,6 +16423,7 @@ export const IN_THE_ZONE_32 = () => name: "Hazard", seed: 23, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707558330, members: [ @@ -16434,6 +16514,7 @@ export const IN_THE_ZONE_32 = () => name: "Reputation (Taylor's Version)", seed: 24, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707586842, members: [ @@ -16524,6 +16605,7 @@ export const IN_THE_ZONE_32 = () => name: "Smoking Moais ", seed: 25, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707583597, members: [ @@ -16638,6 +16720,7 @@ export const IN_THE_ZONE_32 = () => name: "Zoneando", seed: 26, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707429804, members: [ @@ -16740,6 +16823,7 @@ export const IN_THE_ZONE_32 = () => name: "OVERTIME!!", seed: 27, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707539973, members: [ @@ -16846,6 +16930,7 @@ export const IN_THE_ZONE_32 = () => name: "11:11; Make a Wish", seed: 28, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707507831, members: [ @@ -16948,6 +17033,7 @@ export const IN_THE_ZONE_32 = () => name: "delulu ", seed: 29, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707586297, members: [ @@ -17164,6 +17250,7 @@ export const IN_THE_ZONE_32 = () => name: "Peaky P-Key ", seed: 31, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707578076, members: [ @@ -17360,6 +17447,7 @@ export const IN_THE_ZONE_32 = () => name: "all my homie hate pencil ", seed: 33, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707575330, members: [ @@ -17462,6 +17550,7 @@ export const IN_THE_ZONE_32 = () => name: "Whaa", seed: 34, prefersNotToHost: 0, + noScreen: 0, inviteCode: null, createdAt: 1707527645, members: [ diff --git a/app/features/tournament-bracket/core/tests/test-utils.ts b/app/features/tournament-bracket/core/tests/test-utils.ts index c45954c3f..748d70948 100644 --- a/app/features/tournament-bracket/core/tests/test-utils.ts +++ b/app/features/tournament-bracket/core/tests/test-utils.ts @@ -16,6 +16,7 @@ const tournamentCtxTeam = ( members: [], name: "Team " + teamId, prefersNotToHost: 0, + noScreen: 0, seed: teamId + 1, ...partial, }; diff --git a/app/features/tournament-bracket/tournament-bracket.css b/app/features/tournament-bracket/tournament-bracket.css index 1dda99d44..face89b65 100644 --- a/app/features/tournament-bracket/tournament-bracket.css +++ b/app/features/tournament-bracket/tournament-bracket.css @@ -114,6 +114,20 @@ } } +.tournament-bracket__no-screen { + display: flex; + gap: var(--s-0-5); +} + +.tournament-bracket__no-screen > svg { + width: 24px; + fill: var(--theme-success); +} + +.tournament-bracket__no-screen__banned > svg { + fill: var(--theme-error); +} + .tournament-bracket__during-match-actions { display: grid; grid-template-areas: diff --git a/app/features/tournament/TournamentRepository.server.ts b/app/features/tournament/TournamentRepository.server.ts index 5c10cdfe3..9cd9c889a 100644 --- a/app/features/tournament/TournamentRepository.server.ts +++ b/app/features/tournament/TournamentRepository.server.ts @@ -68,6 +68,7 @@ export async function findById(id: number) { "TournamentTeam.name", "TournamentTeam.seed", "TournamentTeam.prefersNotToHost", + "TournamentTeam.noScreen", "TournamentTeam.inviteCode", "TournamentTeam.createdAt", jsonArrayFrom( diff --git a/app/features/tournament/queries/createTeam.server.ts b/app/features/tournament/queries/createTeam.server.ts index e8458fcbd..0a8101c05 100644 --- a/app/features/tournament/queries/createTeam.server.ts +++ b/app/features/tournament/queries/createTeam.server.ts @@ -8,12 +8,14 @@ const createTeamStm = sql.prepare(/*sql*/ ` "tournamentId", "inviteCode", "name", - "prefersNotToHost" + "prefersNotToHost", + "noScreen" ) values ( @tournamentId, @inviteCode, @name, - @prefersNotToHost + @prefersNotToHost, + @noScreen ) returning * `); @@ -35,17 +37,20 @@ export const createTeam = sql.transaction( name, ownerId, prefersNotToHost, + noScreen, }: { tournamentId: TournamentTeam["tournamentId"]; name: TournamentTeam["name"]; ownerId: User["id"]; prefersNotToHost: TournamentTeam["prefersNotToHost"]; + noScreen: number; }) => { const team = createTeamStm.get({ tournamentId, name, inviteCode: nanoid(INVITE_CODE_LENGTH), prefersNotToHost, + noScreen, }) as TournamentTeam; createMemberStm.run({ tournamentTeamId: team.id, userId: ownerId }); diff --git a/app/features/tournament/queries/updateTeamInfo.server.ts b/app/features/tournament/queries/updateTeamInfo.server.ts index 95ebe78d3..a98d90190 100644 --- a/app/features/tournament/queries/updateTeamInfo.server.ts +++ b/app/features/tournament/queries/updateTeamInfo.server.ts @@ -6,7 +6,8 @@ const stm = sql.prepare(/*sql*/ ` "TournamentTeam" set "name" = @name, - "prefersNotToHost" = @prefersNotToHost + "prefersNotToHost" = @prefersNotToHost, + "noScreen" = @noScreen where "id" = @id `); @@ -15,14 +16,17 @@ export function updateTeamInfo({ id, name, prefersNotToHost, + noScreen, }: { id: TournamentTeam["id"]; name: TournamentTeam["name"]; prefersNotToHost: TournamentTeam["prefersNotToHost"]; + noScreen: number; }) { stm.run({ id, name, prefersNotToHost, + noScreen, }); } diff --git a/app/features/tournament/routes/to.$id.admin.tsx b/app/features/tournament/routes/to.$id.admin.tsx index 9c68fff96..146869382 100644 --- a/app/features/tournament/routes/to.$id.admin.tsx +++ b/app/features/tournament/routes/to.$id.admin.tsx @@ -71,6 +71,7 @@ export const action: ActionFunction = async ({ request, params }) => { tournamentId: tournamentId, ownerId: data.userId, prefersNotToHost: 0, + noScreen: 0, }); break; diff --git a/app/features/tournament/routes/to.$id.register.tsx b/app/features/tournament/routes/to.$id.register.tsx index 53146b6d1..57b39e890 100644 --- a/app/features/tournament/routes/to.$id.register.tsx +++ b/app/features/tournament/routes/to.$id.register.tsx @@ -119,6 +119,7 @@ export const action: ActionFunction = async ({ request, params }) => { name: data.teamName, id: ownTeam.id, prefersNotToHost: booleanToInt(data.prefersNotToHost), + noScreen: booleanToInt(data.noScreen), }); } else { validate(!HACKY_isInviteOnlyEvent(event), "Event is invite only"); @@ -136,6 +137,7 @@ export const action: ActionFunction = async ({ request, params }) => { tournamentId: tournamentId, ownerId: user.id, prefersNotToHost: booleanToInt(data.prefersNotToHost), + noScreen: booleanToInt(data.noScreen), }); } break; @@ -387,6 +389,7 @@ function RegistrationForms() { ) : null} @@ -579,14 +582,17 @@ function CheckIn({ function TeamInfo({ name, prefersNotToHost = 0, + noScreen = 0, canUnregister, }: { name?: string; prefersNotToHost?: number; + noScreen?: number; canUnregister: boolean; }) { const { t } = useTranslation(["tournament", "common"]); const fetcher = useFetcher(); + const tournament = useTournament(); return (
@@ -624,7 +630,7 @@ function TeamInfo({ defaultValue={name ?? undefined} />
-
+
+ + {tournament.ctx.settings.enableNoScreenToggle ? ( +
+ + +
+ ) : null}
{ // bye is gone await expect(page.locator('[data-match-id="1"]')).toBeVisible(); }); + + test("tournament no screen toggle works", async ({ page }) => { + const tournamentId = 4; + + await seed(page); + await impersonate(page); + + await navigate({ + page, + url: tournamentRegisterPage(tournamentId), + }); + + await page.getByTestId("no-screen-checkbox").click(); + await page.getByTestId("save-team-button").click(); + + await page.getByTestId("brackets-tab").click(); + await page.getByTestId("finalize-bracket-button").click(); + await page.getByTestId("confirm-finalize-bracket-button").click(); + + await page.locator('[data-match-id="7"]').click(); + await expect(page.getByTestId("screen-allowed")).toBeVisible(); + await backToBracket(page); + + await page.locator('[data-match-id="8"]').click(); + await expect(page.getByTestId("screen-banned")).toBeVisible(); + }); }); diff --git a/locales/en/tournament.json b/locales/en/tournament.json index 0285efe4a..275bb0da3 100644 --- a/locales/en/tournament.json +++ b/locales/en/tournament.json @@ -28,6 +28,7 @@ "pre.info.unregister": "Unregister", "pre.info.unregister.confirm": "Unregister from the tournament and delete team info?", "pre.info.noHost": "My team prefers not to host rooms", + "pre.info.noScreen": "My team prefers to avoid Splattercolor Screen", "pre.roster.header": "Fill roster", "pre.roster.footer": "At least {{atLeastCount}} members are required to participate. Max roster size is {{maxCount}}", diff --git a/migrations/050-tournament-no-screen.js b/migrations/050-tournament-no-screen.js new file mode 100644 index 000000000..2943807b0 --- /dev/null +++ b/migrations/050-tournament-no-screen.js @@ -0,0 +1,5 @@ +export function up(db) { + db.prepare( + /* sql */ `alter table "TournamentTeam" add "noScreen" integer not null default 0`, + ).run(); +}