diff --git a/packages/frontend/web-ui/src/game/components/NonStartedGameList.tsx b/packages/frontend/web-ui/src/game/components/NonStartedGameList.tsx index 091ed9e54..374a45158 100644 --- a/packages/frontend/web-ui/src/game/components/NonStartedGameList.tsx +++ b/packages/frontend/web-ui/src/game/components/NonStartedGameList.tsx @@ -6,11 +6,20 @@ import { Fragment } from 'react'; import { Either } from '../../common/models/Either'; import useConsecutiveSnackbars from '../hooks/useConsecutiveSnackbars'; import { BaseGameList, BaseGameListPaginationOptions } from './BaseGameList'; -import { NonStartedGameListItem } from './NonStartedGameListItem'; +import { + NonStartedGameListItem, + NonStartedGameListItemButtonsOptions, +} from './NonStartedGameListItem'; const SNACKBAR_MESSAGE_CONTENT: string = 'Link copied to the clipboard'; +export interface NonStartedGameListButtonsOptions { + join?: boolean; + share?: boolean; +} + export interface NonStartedGameListOptions { + buttons?: NonStartedGameListButtonsOptions; pagination?: BaseGameListPaginationOptions | undefined; title?: string | undefined; gamesResult: Either | null; @@ -18,13 +27,19 @@ export interface NonStartedGameListOptions { function buildGameItemBuilder( enqueue: (messageContent: string) => void, + options: NonStartedGameListOptions, ): (game: apiModels.GameV1, key: number) => React.JSX.Element { - const onClick: () => void = () => { + const onclick: () => void = () => { enqueue(SNACKBAR_MESSAGE_CONTENT); }; + const buttonOptions: NonStartedGameListItemButtonsOptions = { + join: options.buttons?.join ?? false, + share: options.buttons?.share === true ? { onclick } : false, + }; + return (game: apiModels.GameV1, key: number) => ( - + ); } @@ -53,7 +68,7 @@ export const NonStartedGameList = (options: NonStartedGameListOptions) => { TransitionProps={{ onExited: dequeue }} > diff --git a/packages/frontend/web-ui/src/game/components/NonStartedGameListItem.spec.tsx b/packages/frontend/web-ui/src/game/components/NonStartedGameListItem.spec.tsx index c044f8d55..fa8ddec2f 100644 --- a/packages/frontend/web-ui/src/game/components/NonStartedGameListItem.spec.tsx +++ b/packages/frontend/web-ui/src/game/components/NonStartedGameListItem.spec.tsx @@ -1,10 +1,13 @@ import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals'; +jest.mock('../../common/helpers/getSlug'); jest.mock('./BaseGameListItem'); import { render, RenderResult } from '@testing-library/react'; -import React, { MouseEventHandler } from 'react'; +import React from 'react'; +import { getSlug } from '../../common/helpers/getSlug'; +import { PageName } from '../../common/models/PageName'; import { BaseGameListItem, BaseGameListItemOptions } from './BaseGameListItem'; import { NonStartedGameListItem, @@ -16,6 +19,10 @@ describe(NonStartedGameListItem.name, () => { beforeAll(() => { nonStartedGameListItemOptionsMock = { + buttons: { + join: { onclick: jest.fn() }, + share: { onclick: jest.fn() }, + }, game: { id: 'id-fixture', isPublic: false, @@ -25,17 +32,18 @@ describe(NonStartedGameListItem.name, () => { status: 'nonStarted', }, }, - onButtonClick: jest.fn(), }; }); describe('when called', () => { let baseGameListItemContentFixture: string; + let slugFixture: string; let baseGameListItemContent: string | null | undefined; beforeAll(() => { baseGameListItemContentFixture = 'Expected content fixture'; + slugFixture = '/slug-fixture'; const baseGameListItemFixture = (
@@ -47,13 +55,10 @@ describe(NonStartedGameListItem.name, () => { BaseGameListItem as jest.Mock ).mockReturnValueOnce(baseGameListItemFixture); + (getSlug as jest.Mock).mockReturnValueOnce(slugFixture); + const renderResult: RenderResult = render( - , + , ); const baseGameListItem: ChildNode | undefined = @@ -77,6 +82,11 @@ describe(NonStartedGameListItem.name, () => { expect(BaseGameListItem).toHaveBeenCalledWith(expectedOptions, {}); }); + it('should call getSlug()', () => { + expect(getSlug).toHaveBeenCalledTimes(1); + expect(getSlug).toHaveBeenCalledWith(PageName.joinGame); + }); + it('should return expected content', () => { expect(baseGameListItemContent).toBe(baseGameListItemContentFixture); }); diff --git a/packages/frontend/web-ui/src/game/components/NonStartedGameListItem.tsx b/packages/frontend/web-ui/src/game/components/NonStartedGameListItem.tsx index b75f7a82b..3ae41ec07 100644 --- a/packages/frontend/web-ui/src/game/components/NonStartedGameListItem.tsx +++ b/packages/frontend/web-ui/src/game/components/NonStartedGameListItem.tsx @@ -1,24 +1,37 @@ import { models as apiModels } from '@cornie-js/api-models'; -import { Share } from '@mui/icons-material'; +import { JoinInner, Share } from '@mui/icons-material'; import { Box, Button } from '@mui/material'; import { MouseEvent, MouseEventHandler } from 'react'; +import { getSlug } from '../../common/helpers/getSlug'; +import { PageName } from '../../common/models/PageName'; import { BaseGameListItem } from './BaseGameListItem'; +export type NonStartedGameListItemButtonOptions = + | boolean + | { + onclick: MouseEventHandler; + }; + +export interface NonStartedGameListItemButtonsOptions { + join?: NonStartedGameListItemButtonOptions; + share?: NonStartedGameListItemButtonOptions; +} + export interface NonStartedGameListItemOptions { + buttons?: NonStartedGameListItemButtonsOptions; game: apiModels.GameV1; - onButtonClick?: MouseEventHandler; } async function copyTextToClipboard( text: string, event: MouseEvent, - onButtonClick?: MouseEventHandler, + onClick?: MouseEventHandler | undefined, ): Promise { await navigator.clipboard.writeText(text); - if (onButtonClick !== undefined) { - onButtonClick(event); + if (onClick !== undefined) { + onClick(event); } } @@ -28,23 +41,38 @@ function buildShareGameButtonOnClick( return (event: MouseEvent) => { const currentUrl: URL = new URL(window.location.href); const joinGameUrl = new URL( - `/games/join?gameId=${options.game.id}`, + `${getSlug(PageName.joinGame)}?gameId=${options.game.id}`, currentUrl, ); - void copyTextToClipboard( - joinGameUrl.toString(), - event, - options.onButtonClick, - ); + const onClickHandler: MouseEventHandler | undefined = + 'object' === typeof options.buttons?.share + ? options.buttons.share.onclick + : undefined; + + void copyTextToClipboard(joinGameUrl.toString(), event, onClickHandler); }; } export const NonStartedGameListItem = ( options: NonStartedGameListItemOptions, ) => { - const button = ( - + const gameListItemJoinButton: React.JSX.Element | undefined = + options.buttons?.join === undefined || + options.buttons.join === false ? undefined : ( + + ); + + const gameListItemShareButton: React.JSX.Element | undefined = + options.buttons?.share === undefined || + options.buttons.share === false ? undefined : ( + ); + + const buttonsContainer: React.JSX.Element = ( + + {gameListItemJoinButton} + {gameListItemShareButton} ); return ( - + ); }; diff --git a/packages/frontend/web-ui/src/home/components/HomeWithAuth.spec.tsx b/packages/frontend/web-ui/src/home/components/HomeWithAuth.spec.tsx index 8b94644db..36379c88b 100644 --- a/packages/frontend/web-ui/src/home/components/HomeWithAuth.spec.tsx +++ b/packages/frontend/web-ui/src/home/components/HomeWithAuth.spec.tsx @@ -125,6 +125,9 @@ describe(HomeWithAuth.name, () => { it('should call NonStartedGameList()', () => { const expectedOptions: NonStartedGameListOptions = { + buttons: { + share: true, + }, gamesResult: null, pagination: { onNextPageButtonClick: expect.any( diff --git a/packages/frontend/web-ui/src/home/components/HomeWithAuth.tsx b/packages/frontend/web-ui/src/home/components/HomeWithAuth.tsx index 3d84bac49..332139b8e 100644 --- a/packages/frontend/web-ui/src/home/components/HomeWithAuth.tsx +++ b/packages/frontend/web-ui/src/home/components/HomeWithAuth.tsx @@ -1,5 +1,5 @@ import { models as apiModels } from '@cornie-js/api-models'; -import { Box, Grid } from '@mui/material'; +import { Box, Grid2 } from '@mui/material'; import { useState } from 'react'; import { cornieApi } from '../../common/http/services/cornieApi'; @@ -107,9 +107,12 @@ export const HomeWithAuth = (): React.JSX.Element => { component="div" className="page-section-container home-auth-container" > - - + + { }} title="Pending Games" /> - - + + { }} title="Active Games" /> - - + + ); diff --git a/packages/frontend/web-ui/src/scss/home/_gameList.scss b/packages/frontend/web-ui/src/scss/home/_gameList.scss index 69179dd00..7bfced3cd 100644 --- a/packages/frontend/web-ui/src/scss/home/_gameList.scss +++ b/packages/frontend/web-ui/src/scss/home/_gameList.scss @@ -5,7 +5,6 @@ flex-direction: column; justify-content: space-between; margin: 1rem 0rem; - min-height: 330px; border: 1px solid var(--cg-bkg-primary-dark); border-radius: 10px; background-color: var(--cg-bkg-primary-dark); @@ -48,16 +47,17 @@ .games-container .game-list-item .game-list-item-button { background-color: var(--cg-bkg-primary-dark); border: 1px solid var(--cg-bkg-secondary-light); + box-shadow: 0 4px 8px 0 var(--cg-text-primary); + color: var(--cg-text-primary); font-weight: bold; height: 2.5rem; width: 7rem; - box-shadow: 0 4px 8px 0 var(--cg-text-primary); } .games-container .game-list-item .game-list-item-button:hover { background-color: var(--cg-bkg-secondary-main); - font-weight: bold; color: var(--cg-btn-third-txt); + font-weight: bold; } .games-container .game-list-pagination { diff --git a/packages/frontend/web-ui/src/scss/home/pages/home/_page.scss b/packages/frontend/web-ui/src/scss/home/pages/home/_page.scss index 0fab0a0eb..228a4bd2d 100644 --- a/packages/frontend/web-ui/src/scss/home/pages/home/_page.scss +++ b/packages/frontend/web-ui/src/scss/home/pages/home/_page.scss @@ -38,6 +38,10 @@ padding: 1rem; } +.home-auth-container .games-container { + min-height: 340px; +} + .login-page-container { min-height: 100vh; }