diff --git a/src/routes/home/components/announcementDialog/AnnouncementDialog.vue b/src/routes/home/components/announcementDialog/AnnouncementDialog.vue index cd40deed5..15ccc8472 100644 --- a/src/routes/home/components/announcementDialog/AnnouncementDialog.vue +++ b/src/routes/home/components/announcementDialog/AnnouncementDialog.vue @@ -55,7 +55,7 @@ import { ref, computed } from 'vue'; import { useI18n } from 'vue-i18n'; import dayjs from 'dayjs'; -import { getLocalStorage, setLocalStorage } from '_/utils/local-storage-utils.js'; +import { getLocalStorage, setLocalStorage, LS_ANNOUNCEMENT } from '_/utils/local-storage-utils.js'; import { announcementData } from './data/announcementData'; import { useAuthStore } from '@/stores/auth'; import BaseDialog from '@/components/BaseDialog.vue'; @@ -77,13 +77,13 @@ const announcementIsActive = computed(() => { const close = () => { if (!preferenceSaved.value) { - setLocalStorage('announcement', announcementData.id); + setLocalStorage(LS_ANNOUNCEMENT, announcementData.id); } show.value = false; preferenceSaved.value = true; }; -if (getLocalStorage('announcement') !== announcementData.id) { +if (getLocalStorage(LS_ANNOUNCEMENT) !== announcementData.id) { show.value = true; } diff --git a/src/routes/lobby/LobbyView.vue b/src/routes/lobby/LobbyView.vue index cd664b2ca..7c5b7b606 100644 --- a/src/routes/lobby/LobbyView.vue +++ b/src/routes/lobby/LobbyView.vue @@ -86,6 +86,8 @@ + + @@ -100,6 +102,7 @@ import { playAudio } from '@/util/audio.js'; import PlayerReadyIndicator from '@/components/PlayerReadyIndicator.vue'; import TheLanguageSelector from '@/components/TheLanguageSelector.vue'; import { ROUTE_NAME_GAME } from '_/src/router'; +import PlayTimeDialog from '@/routes/lobby/components/PlayTimeDialog.vue'; // Deps const { t } = useI18n(); diff --git a/src/routes/lobby/components/PlayTimeDialog.vue b/src/routes/lobby/components/PlayTimeDialog.vue new file mode 100644 index 000000000..31098efe4 --- /dev/null +++ b/src/routes/lobby/components/PlayTimeDialog.vue @@ -0,0 +1,94 @@ + + + + + {{ t('lobby.playTimeDialog.openPlaySessions') }} + + + + {{ t('lobby.playTimeDialog.discord') }} + + {{ t('lobby.playTimeDialog.discordLink') }} + + {{ t('lobby.playTimeDialog.findAGame') }} + + + + {{ t('lobby.playTimeDialog.botPlay') }} + + + + + {{ t('lobby.playTimeDialog.goHome') }} + + + {{ t('lobby.playTimeDialog.stay') }} + + + + + + + + diff --git a/src/translations/de.json b/src/translations/de.json index 8ace09773..e4b993327 100644 --- a/src/translations/de.json +++ b/src/translations/de.json @@ -68,6 +68,16 @@ "casual": "Spielmodus geändert zu Freizeit", "ranked": "Spielmodus geändert zu Rangliste" }, + "playTimeDialog": { + "title": "Finde ein Spiel", + "openPlaySessions": "Wir haben offene Spielsitzungen jeden Mittwoch um 20:30 Uhr ET und jeden Donnerstag um 12:00 Uhr ET. Wenn du zu diesen Zeiten auf die Seite kommst, findest du immer jemanden zum Spielen!", + "discord": "Wir haben einen {0} und du kannst den {1}-Kanal nutzen, um Mitspieler zu finden.", + "discordLink": "Discord-Kanal", + "findAGame": "#find-a-game", + "botPlay": "Du kannst von der Startseite aus gegen den Bot spielen.", + "goHome": "Zur Startseite", + "stay": "Im Lobby bleiben" + }, "error": { "fallback": "Ein unbekannter Fehler ist aufgetreten.", "forbidden": "Du bist kein Spieler in diesem Spiel!", diff --git a/src/translations/en.json b/src/translations/en.json index 1d30ce89e..7c938b570 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -68,6 +68,16 @@ "casual": "Game Mode changed to Casual", "ranked": "Game Mode changed to Ranked" }, + "playTimeDialog": { + "title": "Find a Game", + "openPlaySessions": "We have open play sessions every Wednesday at 8:30pm ET and every Thursday at 12pm ET. If you hop on the site at those times, you'll always have someone to play!", + "discord": "We have a {0} and you can use its {1} channel to find matches.", + "discordLink": "Discord channel", + "findAGame": "#find-a-game", + "botPlay": "You can play against the bot from the home page.", + "goHome": "Go Home", + "stay": "Stay in Lobby" + }, "error": { "fallback": "An unknown error has occurred.", "forbidden": "You are not a player in this game!", diff --git a/src/translations/es.json b/src/translations/es.json index 624aed3e6..b44e50d61 100644 --- a/src/translations/es.json +++ b/src/translations/es.json @@ -68,6 +68,16 @@ "casual": "El modo de juego cambió a Amistoso", "ranked": "El modo de juego cambió a Competitivo" }, + "playTimeDialog": { + "title": "Encuentra una partida", + "openPlaySessions": "Tenemos sesiones de juego abiertas todos los miércoles a las 8:30pm ET y todos los jueves a las 12pm ET. Si entras al sitio en esos horarios, ¡siempre habrá alguien con quien jugar!", + "discord": "Tenemos un {0} y puedes usar su canal {1} para encontrar partidas.", + "discordLink": "canal de Discord", + "findAGame": "#find-a-game", + "botPlay": "Puedes jugar contra el bot desde la página de inicio.", + "goHome": "Ir al inicio", + "stay": "Quedarme en el lobby" + }, "error": { "fallback": "Se ha producido un error desconocido.", "forbidden": "¡No eres un jugador en este juego!", diff --git a/src/translations/fr.json b/src/translations/fr.json index 8c01d57c6..585035987 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -68,6 +68,16 @@ "casual": "Mode de jeu modifié à Classique", "ranked": "Mode de jeu modifié à Classée" }, + "playTimeDialog": { + "title": "Trouver une partie", + "openPlaySessions": "Nous avons des sessions de jeu ouvertes tous les mercredis à 20h30 ET et tous les jeudis à 12h ET. Si vous vous connectez à ces horaires, vous trouverez toujours quelqu'un avec qui jouer !", + "discord": "Nous avons un {0} et vous pouvez utiliser son canal {1} pour trouver des adversaires.", + "discordLink": "canal Discord", + "findAGame": "#find-a-game", + "botPlay": "Vous pouvez jouer contre le bot depuis la page d'accueil.", + "goHome": "Retour à l'accueil", + "stay": "Rester dans le lobby" + }, "error": { "fallback": "Une erreur inconnue s'est produite.", "forbidden": "Vous n'êtes pas un joueur dans ce jeu !", diff --git a/src/translations/ukr.json b/src/translations/ukr.json index bb2eeb20d..ec292e9bf 100644 --- a/src/translations/ukr.json +++ b/src/translations/ukr.json @@ -68,6 +68,16 @@ "casual": "Режим гри змінено на Неофіційний", "ranked": "Режим гри змінено на Рейтинговий" }, + "playTimeDialog": { + "title": "Знайти гру", + "openPlaySessions": "У нас є відкриті ігрові сесії щосереди о 20:30 ET та щочетверга о 12:00 ET. Якщо ви зайдете на сайт у ці години, завжди знайдете з ким пограти!", + "discord": "У нас є {0}, і ви можете використовувати канал {1}, щоб знайти суперників.", + "discordLink": "канал Discord", + "findAGame": "#find-a-game", + "botPlay": "Ви можете грати проти бота з головної сторінки.", + "goHome": "На головну", + "stay": "Залишитися в лобі" + }, "error": { "fallback": "Сталася невідома помилка.", "forbidden": "Ви не гравець у цій грі!", diff --git a/tests/e2e/specs/in-game/game-over/rematch.spec.js b/tests/e2e/specs/in-game/game-over/rematch.spec.js index 8e7505844..698428a47 100644 --- a/tests/e2e/specs/in-game/game-over/rematch.spec.js +++ b/tests/e2e/specs/in-game/game-over/rematch.spec.js @@ -9,7 +9,6 @@ import { import { seasonFixtures } from '../../../fixtures/statsFixtures'; import { playerOne, playerTwo, playerThree } from '../../../fixtures/userFixtures'; import { Card } from '../../../fixtures/cards'; -import { announcementData } from '../../../../../src/routes/home/components/announcementDialog/data/announcementData'; const dayjs = require('dayjs'); @@ -48,7 +47,7 @@ describe('Creating And Updating Ranked Matches With Rematch', () => { beforeEach(function () { cy.wipeDatabase(); cy.visit('/'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); // Set up season const [ , diamondsSeason ] = seasonFixtures; @@ -256,7 +255,7 @@ describe('Creating And Updating Casual Games With Rematch', () => { beforeEach(function () { cy.wipeDatabase(); cy.visit('/'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); // Sign up players cy.signupOpponent(playerOne).as('playerOneId'); @@ -408,7 +407,7 @@ describe('Spectating Rematches', () => { describe('Spectating Casual Rematches', () => { beforeEach(() => { cy.setupGameAsSpectator(); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); }); it('Spectates a casual match using rematch', () => { @@ -467,7 +466,7 @@ describe('Spectating Rematches', () => { describe('Spectating Ranked Matches', () => { beforeEach(() => { cy.setupGameAsSpectator(true); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); const [ , , currentSeason ] = seasonFixtures; cy.loadSeasonFixture([ currentSeason ]); }); diff --git a/tests/e2e/specs/in-game/spectating/live-spectating.spec.js b/tests/e2e/specs/in-game/spectating/live-spectating.spec.js index 25508c9c2..9a4710f6a 100644 --- a/tests/e2e/specs/in-game/spectating/live-spectating.spec.js +++ b/tests/e2e/specs/in-game/spectating/live-spectating.spec.js @@ -15,14 +15,13 @@ import { } from '../../../support/helpers'; import { Card } from '../../../fixtures/cards'; import { SnackBarError } from '../../../fixtures/snackbarError'; -import { announcementData } from '../../../../../src/routes/home/components/announcementDialog/data/announcementData'; function setup() { cy.wipeDatabase(); cy.visit('/'); cy.signupPlayer(myUser); cy.vueRoute('/'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); } describe('Spectating Games', () => { @@ -440,7 +439,7 @@ describe('Creating And Updating Unranked Matches With Rematch - Spectating', () // Log in as playerOne cy.loginPlayer(playerOne); cy.setupGameAsSpectator(); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); }); it('Spectate unranked games with rematch', function () { diff --git a/tests/e2e/specs/in-game/vsAI.spec.js b/tests/e2e/specs/in-game/vsAI.spec.js index 66e66c608..e24fc88e1 100644 --- a/tests/e2e/specs/in-game/vsAI.spec.js +++ b/tests/e2e/specs/in-game/vsAI.spec.js @@ -1,14 +1,13 @@ import { myUser } from '../../fixtures/userFixtures'; import { Card } from '../../fixtures/cards'; import { assertGameState, assertVictory, assertLoss } from '../../support/helpers'; -import { announcementData } from '../../../../src/routes/home/components/announcementDialog/data/announcementData'; function setup() { cy.wipeDatabase(); cy.visit('/'); cy.signupPlayer(myUser); cy.vueRoute('/'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); cy.get('[data-cy=create-ai-game]').click(); cy.get('[data-player-hand-card]').should('have.length', 5); cy.get('[data-cy=opponent-username]').should('contain', 'CuttleBot'); diff --git a/tests/e2e/specs/out-of-game/authentication.spec.js b/tests/e2e/specs/out-of-game/authentication.spec.js index 9f2f17409..50dce886d 100644 --- a/tests/e2e/specs/out-of-game/authentication.spec.js +++ b/tests/e2e/specs/out-of-game/authentication.spec.js @@ -1,6 +1,5 @@ import { assertSnackbar } from '../../support/helpers'; import { myUser } from '../../fixtures/userFixtures'; -import { announcementData } from '../../../../src/routes/home/components/announcementDialog/data/announcementData'; function assertSuccessfulAuth(username) { // Confirm we have navigated to home @@ -38,7 +37,7 @@ describe('Auth - Page Content', () => { cy.wipeDatabase(); cy.visit('/signup'); cy.signupOpponent(myUser); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); }); it('Displays logo and navigates to rules page', () => { @@ -111,7 +110,7 @@ describe('Signing Up', () => { beforeEach(() => { cy.wipeDatabase(); cy.visit('/signup'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); }); /** diff --git a/tests/e2e/specs/out-of-game/home.spec.js b/tests/e2e/specs/out-of-game/home.spec.js index ad8f32f0f..379abcc09 100644 --- a/tests/e2e/specs/out-of-game/home.spec.js +++ b/tests/e2e/specs/out-of-game/home.spec.js @@ -3,7 +3,6 @@ import { Card } from '../../fixtures/cards'; import { myUser, opponentOne, opponentTwo, playerOne, playerTwo } from '../../fixtures/userFixtures'; import { SnackBarError } from '../../fixtures/snackbarError'; import GameStatus from '../../../../utils/GameStatus.json'; -import { announcementData } from '../../../../src/routes/home/components/announcementDialog/data/announcementData'; import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; dayjs.extend(utc); @@ -13,7 +12,7 @@ function setup() { cy.visit('/'); cy.signupPlayer(myUser); cy.vueRoute('/'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); } function assertSuccessfulJoin(gameState) { @@ -439,9 +438,7 @@ describe('Home - Create Game', () => { it('Saves ranked setting between sessions', () => { cy.clearLocalStorage(); - cy.window().then((win) => { - win.localStorage.setItem('announcement', announcementData.id); - }); + cy.dismissIntroPopups(); cy.get('[data-cy=create-game-btn]').click(); cy.get('[data-cy=create-game-dialog]').should('be.visible'); diff --git a/tests/e2e/specs/out-of-game/lobby.spec.js b/tests/e2e/specs/out-of-game/lobby.spec.js index b407fc7d4..089c72b31 100644 --- a/tests/e2e/specs/out-of-game/lobby.spec.js +++ b/tests/e2e/specs/out-of-game/lobby.spec.js @@ -3,11 +3,12 @@ import { assertSnackbar } from '../../support/helpers'; import { SnackBarError } from '../../fixtures/snackbarError'; import { announcementData } from '../../../../src/routes/home/components/announcementDialog/data/announcementData'; import ThemeColors from '../../../../utils/ThemeColors.json'; +import { LS_ANNOUNCEMENT, LS_PLAY_TIME_DIALOG_DISMISSED } from '../../../../utils/local-storage-utils'; function setup(isRanked = false) { cy.wipeDatabase(); cy.visit('/'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); cy.signupPlayer(myUser); cy.createGamePlayer({ gameName: 'Test Game', isRanked }).then((gameSummary) => { cy.window() @@ -485,7 +486,7 @@ describe('Lobby - P1 Perspective', () => { cy.wipeDatabase(); cy.visit('/'); cy.signupPlayer(myUser); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); cy.createGamePlayer({ gameName: 'Test Game', isRanked: false }).then((gameSummary) => { cy.wrap(gameSummary).as('gameSummary'); // Sign up new (other) user and subscribe them to game @@ -666,13 +667,51 @@ describe('Lobby - P1 Perspective', () => { }); }); +describe('Lobby - Play Time Dialog', () => { + beforeEach(() => { + cy.wipeDatabase(); + cy.visit('/'); + window.localStorage.setItem(LS_ANNOUNCEMENT, announcementData.id); + cy.signupPlayer(myUser); + cy.createGamePlayer({ gameName: 'Test Game', isRanked: false }).then((gameSummary) => { + cy.wrap(gameSummary).as('gameSummary'); + }); + }); + + function enterLobby(gameId) { + cy.window() + .its('cuttle.gameStore') + .then((store) => store.requestSubscribe(gameId)); + cy.vueRoute(`/lobby/${gameId}`); + } + + it('Dismisses dialog and sets localStorage when staying in lobby', function () { + enterLobby(this.gameSummary.gameId); + cy.wait(61000); + cy.get('#play-time-dialog').should('be.visible'); + cy.get('[data-cy=play-time-dialog-stay]').click(); + cy.get('#play-time-dialog').should('not.exist'); + cy.window().then((win) => { + expect(win.localStorage.getItem(LS_PLAY_TIME_DIALOG_DISMISSED)).to.eq('true'); + }); + }); + + it('Does not show dialog if it has already been dismissed', function () { + cy.window().then((win) => win.localStorage.setItem(LS_PLAY_TIME_DIALOG_DISMISSED, 'true')); + enterLobby(this.gameSummary.gameId); + cy.wait(62000); + cy.get('#play-time-dialog').should('not.exist'); + }); + +}); + describe('Lobby invite links', () => { beforeEach(() => { cy.wipeDatabase(); cy.visit('/'); cy.signupPlayer(myUser); cy.visit('/'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); cy.createGamePlayer({ gameName: 'Test Game', isRanked: false }).then((gameSummary) => { cy.wrap(gameSummary).as('gameSummary'); // Sign up new (other) user and subscribe them to game diff --git a/tests/e2e/specs/out-of-game/localization.spec.js b/tests/e2e/specs/out-of-game/localization.spec.js index 62ff6ac77..18bb65da0 100644 --- a/tests/e2e/specs/out-of-game/localization.spec.js +++ b/tests/e2e/specs/out-of-game/localization.spec.js @@ -5,15 +5,13 @@ import en from '../../../../src/translations/en.json'; import de from '../../../../src/translations/de.json'; import ukr from '../../../../src/translations/ukr.json'; -import { announcementData } from '../../../../src/routes/home/components/announcementDialog/data/announcementData'; - describe('Localization', () => { beforeEach(() => { cy.wipeDatabase(); cy.visit('/'); cy.signupPlayer(myUser); cy.vueRoute('/'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); }); const checkAndChangeLanguage = (name, lang) => { diff --git a/tests/e2e/specs/out-of-game/navigation.spec.js b/tests/e2e/specs/out-of-game/navigation.spec.js index 4aabdd454..a8d15afcd 100644 --- a/tests/e2e/specs/out-of-game/navigation.spec.js +++ b/tests/e2e/specs/out-of-game/navigation.spec.js @@ -1,5 +1,4 @@ import { playerOne } from '../../fixtures/userFixtures'; -import { announcementData } from '../../../../src/routes/home/components/announcementDialog/data/announcementData'; function verifyAuthenticatedLinks() { // Navigate to Rules @@ -49,7 +48,7 @@ describe('Navigation', () => { beforeEach(() => { cy.wipeDatabase(); cy.visit('/'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); }); describe('Authenticated Navigation', () => { @@ -87,7 +86,7 @@ describe('Navigation', () => { describe('Unauthenticated Navigation', () => { beforeEach(() => { - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); }); it('Navigates between Login and Rules when unauthenticated on DESKTOP', () => { diff --git a/tests/e2e/specs/out-of-game/rules.spec.js b/tests/e2e/specs/out-of-game/rules.spec.js index f150b3c7d..2249756cc 100644 --- a/tests/e2e/specs/out-of-game/rules.spec.js +++ b/tests/e2e/specs/out-of-game/rules.spec.js @@ -1,12 +1,11 @@ import { myUser } from '../../fixtures/userFixtures'; -import { announcementData } from '../../../../src/routes/home/components/announcementDialog/data/announcementData'; describe('Rules Page', () => { beforeEach(() => { cy.wipeDatabase(); cy.visit('/'); cy.vueRoute('/rules'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); }); it('Navigates to Login when unauthenticated and home when authenticated using the Ready To Play button', () => { diff --git a/tests/e2e/specs/out-of-game/stats.spec.js b/tests/e2e/specs/out-of-game/stats.spec.js index 76e3244f7..d6e8925f3 100644 --- a/tests/e2e/specs/out-of-game/stats.spec.js +++ b/tests/e2e/specs/out-of-game/stats.spec.js @@ -1,13 +1,12 @@ import { playerOne, playerTwo, playerThree, playerFour, playerFive } from '../../fixtures/userFixtures'; import { seasonFixtures, matchesFixture, gameFixtures } from '../../fixtures/statsFixtures'; -import { announcementData } from '../../../../src/routes/home/components/announcementDialog/data/announcementData'; const dayjs = require('dayjs'); function setup() { cy.viewport(1980, 1080); cy.wipeDatabase(); cy.visit('/'); - window.localStorage.setItem('announcement', announcementData.id); + cy.dismissIntroPopups(); // Signup opponents and store their newly created ids cy.signupOpponent(playerOne).as('player1'); cy.loginPlayer(playerOne); diff --git a/tests/e2e/support/commands.js b/tests/e2e/support/commands.js index dbc65530f..32c2eb91f 100644 --- a/tests/e2e/support/commands.js +++ b/tests/e2e/support/commands.js @@ -1,5 +1,7 @@ import { hasValidSuitAndRank, cardsMatch, printCard } from './helpers'; import { myUser, opponentOne, playerOne, playerTwo } from '../fixtures/userFixtures'; +import { announcementData } from '../../../src/routes/home/components/announcementDialog/data/announcementData'; +import { LS_ANNOUNCEMENT, LS_PLAY_TIME_DIALOG_DISMISSED } from '../../../utils/local-storage-utils'; import MoveType from '../../../utils/MoveType.json'; /** @@ -90,6 +92,13 @@ Cypress.Commands.add('wipeDatabase', () => { cy.log('Wiped database'); }); +Cypress.Commands.add('dismissIntroPopups', () => { + cy.window().then((win) => { + win.localStorage.setItem(LS_ANNOUNCEMENT, announcementData.id); + win.localStorage.setItem(LS_PLAY_TIME_DIALOG_DISMISSED, 'true'); + }); +}); + Cypress.Commands.add('refreshOpponentSocket', () => { io.socket.disconnect(); io.socket.reconnect(); diff --git a/utils/local-storage-utils.js b/utils/local-storage-utils.js index 2b8058c8f..ac7e9bd84 100644 --- a/utils/local-storage-utils.js +++ b/utils/local-storage-utils.js @@ -1,5 +1,7 @@ const LS_PREFERS_RANKED_NAME = 'prefersRanked'; const LS_IS_RETURNING_USER_NAME = 'isReturningUser'; +const LS_PLAY_TIME_DIALOG_DISMISSED = 'playTimeDialogDismissed'; +const LS_ANNOUNCEMENT = 'announcement'; const getLocalStorage = (key) => { try { @@ -17,4 +19,11 @@ const setLocalStorage = (key, value) => { } }; -export { getLocalStorage, setLocalStorage, LS_PREFERS_RANKED_NAME, LS_IS_RETURNING_USER_NAME }; +export { + getLocalStorage, + setLocalStorage, + LS_PREFERS_RANKED_NAME, + LS_IS_RETURNING_USER_NAME, + LS_PLAY_TIME_DIALOG_DISMISSED, + LS_ANNOUNCEMENT +};
+ {{ t('lobby.playTimeDialog.openPlaySessions') }} +
+ + {{ t('lobby.playTimeDialog.discord') }} + + {{ t('lobby.playTimeDialog.discordLink') }} + + {{ t('lobby.playTimeDialog.findAGame') }} + +
+ {{ t('lobby.playTimeDialog.botPlay') }} +