Skip to content

Commit

Permalink
Merge pull request #1597 from notaphplover/refactor/update-non-starte…
Browse files Browse the repository at this point in the history
…d-game-list-item-with-button-options

Update NonStartedGameListItem with ButtonOptions
  • Loading branch information
notaphplover authored Aug 29, 2024
2 parents 92be0ab + 685ca15 commit 3c5f389
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,40 @@ 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<string, apiModels.GameArrayV1> | null;
}

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) => (
<NonStartedGameListItem key={key} game={game} onButtonClick={onClick} />
<NonStartedGameListItem key={key} game={game} buttons={buttonOptions} />
);
}

Expand Down Expand Up @@ -53,7 +68,7 @@ export const NonStartedGameList = (options: NonStartedGameListOptions) => {
TransitionProps={{ onExited: dequeue }}
></Snackbar>
<BaseGameList
buildGameItem={buildGameItemBuilder(enqueue)}
buildGameItem={buildGameItemBuilder(enqueue, options)}
{...options}
/>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -16,6 +19,10 @@ describe(NonStartedGameListItem.name, () => {

beforeAll(() => {
nonStartedGameListItemOptionsMock = {
buttons: {
join: { onclick: jest.fn() },
share: { onclick: jest.fn() },
},
game: {
id: 'id-fixture',
isPublic: false,
Expand All @@ -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 = (
<div className="base-game-list-item-fixture">
Expand All @@ -47,13 +55,10 @@ describe(NonStartedGameListItem.name, () => {
BaseGameListItem as jest.Mock<typeof BaseGameListItem>
).mockReturnValueOnce(baseGameListItemFixture);

(getSlug as jest.Mock<typeof getSlug>).mockReturnValueOnce(slugFixture);

const renderResult: RenderResult = render(
<NonStartedGameListItem
game={nonStartedGameListItemOptionsMock.game}
onButtonClick={
nonStartedGameListItemOptionsMock.onButtonClick as MouseEventHandler
}
/>,
<NonStartedGameListItem {...nonStartedGameListItemOptionsMock} />,
);

const baseGameListItem: ChildNode | undefined =
Expand All @@ -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);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -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<void> {
await navigator.clipboard.writeText(text);

if (onButtonClick !== undefined) {
onButtonClick(event);
if (onClick !== undefined) {
onClick(event);
}
}

Expand All @@ -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 = (
<Box component="div">
const gameListItemJoinButton: React.JSX.Element | undefined =
options.buttons?.join === undefined ||
options.buttons.join === false ? undefined : (
<Button
className="game-list-item-button"
component="a"
href={`${getSlug(PageName.joinGame)}?gameId=${options.game.id}`}
startIcon={<JoinInner />}
>
Join
</Button>
);

const gameListItemShareButton: React.JSX.Element | undefined =
options.buttons?.share === undefined ||
options.buttons.share === false ? undefined : (
<Button
className="game-list-item-button"
onClick={buildShareGameButtonOnClick(options)}
Expand All @@ -54,10 +82,19 @@ export const NonStartedGameListItem = (
>
Share
</Button>
);

const buttonsContainer: React.JSX.Element = (
<Box component="div">
{gameListItemJoinButton}
{gameListItemShareButton}
</Box>
);

return (
<BaseGameListItem button={button} game={options.game}></BaseGameListItem>
<BaseGameListItem
button={buttonsContainer}
game={options.game}
></BaseGameListItem>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ describe(HomeWithAuth.name, () => {

it('should call NonStartedGameList()', () => {
const expectedOptions: NonStartedGameListOptions = {
buttons: {
share: true,
},
gamesResult: null,
pagination: {
onNextPageButtonClick: expect.any(
Expand Down
17 changes: 10 additions & 7 deletions packages/frontend/web-ui/src/home/components/HomeWithAuth.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -107,18 +107,21 @@ export const HomeWithAuth = (): React.JSX.Element => {
component="div"
className="page-section-container home-auth-container"
>
<Grid container>
<Grid item xs={12}>
<Grid2 container>
<Grid2 size={12}>
<NonStartedGameList
buttons={{
share: true,
}}
gamesResult={nonStartedGamesResult}
pagination={{
onNextPageButtonClick: onNextPageNonStarted,
onPreviousPageButtonClick: onPreviousPageNonStarted,
}}
title="Pending Games"
/>
</Grid>
<Grid item xs={12}>
</Grid2>
<Grid2 size={12}>
<ActiveGameList
gamesResult={activeGamesResult}
pagination={{
Expand All @@ -127,8 +130,8 @@ export const HomeWithAuth = (): React.JSX.Element => {
}}
title="Active Games"
/>
</Grid>
</Grid>
</Grid2>
</Grid2>
</Box>
</CornieLayout>
);
Expand Down
6 changes: 3 additions & 3 deletions packages/frontend/web-ui/src/scss/home/_gameList.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 4 additions & 0 deletions packages/frontend/web-ui/src/scss/home/pages/home/_page.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
padding: 1rem;
}

.home-auth-container .games-container {
min-height: 340px;
}

.login-page-container {
min-height: 100vh;
}

0 comments on commit 3c5f389

Please sign in to comment.