Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POC - Add tooltip to modal, Modal provider (for computer challenge, language picker, game fork) #2845

Draft
wants to merge 7 commits into
base: devel
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion jest.config.js → jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ module.exports = {
"src",
"node_modules"
],
"moduleNameMapper": {
'^@/(.*)': '<rootDir>/src/$1',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing the tests!

},
"setupFiles": ["./setup-jest.js"],
"setupFilesAfterEnv": ["jest-chain"],
"setupFilesAfterEnv": ["jest-chain", "@testing-library/jest-dom"],
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@
"sanitize-html": "^2.12.1",
"sweetalert2": "^11.4.17",
"ts-md5": "^1.3.1",
"ts-node": "^10.9.2",
"valid-url": "^1.0.9",
"whatwg-fetch": "^3.0.0"
},
Expand Down
89 changes: 89 additions & 0 deletions src/components/ChallengeModal/ChallengeModal.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (C) Online-Go.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/* cspell: words groupadmin cotsen */
import * as React from "react";

import * as ChallengeModal from "./ChallengeModal";
import { fireEvent, render, screen } from "@testing-library/react";
import { ModalProvider } from "../Modal/ModalProvider";
import { ModalContext, ModalTypes } from "../Modal/ModalContext";
import * as DynamicHelp from "react-dynamic-help";

jest.mock("./../Modal", () => {
return {
...jest.requireActual("./../Modal"),
};
});

describe("ChallengeModal", () => {
it("should do a computer challenge via provider", () => {
const challengeModalSpy = jest
.spyOn(ChallengeModal, "ChallengeModal")
.mockImplementation(jest.fn());

render(
<ModalProvider>
<ModalContext.Consumer>
{({ showModal }) => {
showModal(ModalTypes.Challenge);
return null;
}}
</ModalContext.Consumer>
</ModalProvider>,
);

expect(challengeModalSpy.mock.calls[0][0]).toStrictEqual({
mode: "computer",
initialState: null,
playerId: undefined,
});

challengeModalSpy.mockRestore();
});

it("should close", () => {
const DynamicHelpProviderValue = {
registerTargetItem: jest.fn().mockReturnValue({ ref: jest.fn() }),
triggerFlow: jest.fn(),
enableHelp: jest.fn(),
getFlowInfo: jest.fn(),
enableFlow: jest.fn(),
reloadUserState: jest.fn(),
signalUsed: jest.fn(),
getSystemStatus: jest.fn(),
resetHelp: jest.fn(),
};

render(
<DynamicHelp.Api.Provider value={DynamicHelpProviderValue}>
<ModalProvider>
<ModalContext.Consumer>
{({ showModal }) => {
showModal(ModalTypes.Challenge);
return null;
}}
</ModalContext.Consumer>
</ModalProvider>
</DynamicHelp.Api.Provider>,
);
const closeButton = screen.getByText("Close");
expect(closeButton).toBeInTheDocument();
fireEvent.click(closeButton);
expect(closeButton).not.toBeInTheDocument();
});
});
12 changes: 7 additions & 5 deletions src/components/ChallengeModal/ChallengeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,11 @@ import {
saveTimeControlSettings,
updateSystem,
} from "@/components/TimeControl/TimeControlUpdates";
import { ActivateTooltip } from "@/views/HelpFlows/ModalHelp";

export type ChallengeDetails = rest_api.ChallengeDetails;

type ChallengeModes = "open" | "computer" | "player" | "demo";
export type ChallengeModes = "open" | "computer" | "player" | "demo";

interface Events {}

Expand Down Expand Up @@ -1778,7 +1779,11 @@ export class ChallengeModalBody extends React.Component<
&nbsp; {player_username}
</span>
)}
{mode === "computer" && <span>{_("Computer")}</span>}
{mode === "computer" && (
<ActivateTooltip flow="modal-help" item="intro">
<span>{_("Computer")}</span>
</ActivateTooltip>
)}
</h2>
</div>
<div className="body">
Expand Down Expand Up @@ -1960,9 +1965,6 @@ export function createDemoBoard(
/>,
);
}
export function challengeComputer() {
return challenge(undefined, null, true);
}
export function challengeRematch(
goban: GobanRenderer,
opponent: GobanEnginePlayerEntry,
Expand Down
123 changes: 49 additions & 74 deletions src/components/ChallengeModal/ForkModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,94 +18,69 @@
import * as React from "react";
import * as data from "@/lib/data";
import { _ } from "@/lib/translate";
import { Modal, openModal } from "@/components/Modal";
import { GobanRenderer } from "goban";
import { PlayerAutocomplete } from "@/components/PlayerAutocomplete";
import { MiniGoban } from "@/components/MiniGoban";
import { challenge } from "@/components/ChallengeModal";
import { PlayerCacheEntry } from "@/lib/player_cache";

interface Events {}
import { ModalContext } from "../Modal/ModalContext";

interface ForkModalProperties {
goban: GobanRenderer;
}

export class ForkModal extends Modal<Events, ForkModalProperties, any> {
constructor(props: ForkModalProperties) {
super(props);
export const ForkModal = ({ goban }: ForkModalProperties) => {
const [currPlayer, setCurrPlayer] = React.useState(null as PlayerCacheEntry | null);
const { hideModal } = React.useContext(ModalContext);

const goban = this.props.goban;
this.state = {
player: null,
fork_preview: {
//"moves": goban.engine.cur_move.getMoveStringToThisPoint(),
//"initial_state": goban.engine.initial_state,
//"initial_player": goban.engine.config.initial_player,
moves: [],
initial_state: goban.engine.computeInitialStateForForkedGame(),
initial_player: goban.engine.colorToMove(),
width: goban.engine.width,
height: goban.engine.height,
rules: goban.engine.rules,
handicap: goban.engine.handicap,
komi: goban.engine.komi,
move_number: goban.engine.getMoveNumber(),
game_name: goban.engine.name,
},
};
}
const forkPreview = {
moves: [],
initial_state: goban.engine.computeInitialStateForForkedGame(),
initial_player: goban.engine.colorToMove(),
width: goban.engine.width,
height: goban.engine.height,
rules: goban.engine.rules,
handicap: goban.engine.handicap,
komi: goban.engine.komi,
move_number: goban.engine.getMoveNumber(),
game_name: goban.engine.name,
};

openChallengeModal = () => {
this.close();
challenge(this.state.player.id, this.state.fork_preview);
const openChallengeModal = () => {
hideModal();
if (currPlayer) {
challenge(currPlayer.id, forkPreview);
}
};

setPlayer = (player: PlayerCacheEntry | null) => {
this.setState({ player: player });
const setPlayer = (player: PlayerCacheEntry | null) => {
setCurrPlayer(player);
};

render() {
return (
<div className="Modal ForkModal">
<div className="header space-around">
<h2>{_("Player to challenge")}:</h2>{" "}
<PlayerAutocomplete onComplete={this.setPlayer} />
</div>
<div className="body space-around">
<MiniGoban
game_id={0}
black={undefined}
white={undefined}
json={this.state.fork_preview}
noLink
/>
</div>
<div className="buttons">
<button onClick={this.close}>{_("Cancel")}</button>
<button
className="primary"
disabled={
this.state.player == null ||
this.state.player.id === data.get("user").id
}
onClick={this.openChallengeModal}
>
{_("Game settings")} &rarr;
</button>
</div>
return (
<div className="Modal ForkModal">
<div className="header space-around">
<h2>{_("Player to challenge")}:</h2> <PlayerAutocomplete onComplete={setPlayer} />
</div>
);
}
}

export function openForkModal(goban: GobanRenderer) {
return openModal(<ForkModal goban={goban} />);
}
export function challengeFromBoardPosition(goban: GobanRenderer) {
if (!goban) {
return;
}

openForkModal(goban);
}
<div className="body space-around">
<MiniGoban
game_id={0}
black={undefined}
white={undefined}
json={forkPreview}
noLink
/>
</div>
<div className="buttons">
<button onClick={hideModal}>{_("Cancel")}</button>
<button
className="primary"
disabled={currPlayer == null || currPlayer.id === data.get("user").id}
onClick={openChallengeModal}
>
{_("Game settings")} &rarr;
</button>
</div>
</div>
);
};
Loading
Loading