refactor HomePage

This commit is contained in:
Halit Aksoy 2022-07-31 00:59:36 +03:00
parent 44090516e2
commit ef8df2a018

View File

@ -1,22 +1,5 @@
import * as React from "react";
import { FunctionComponent, useEffect, useState } from "react";
import BoardView from "../components/board/BoardView";
import { RTMTWS } from "../rtmt/rtmt_websocket";
import {
channel_game_move,
channel_leave_game,
channel_on_game_crashed,
channel_on_game_start,
channel_on_game_update,
channel_on_game_user_leave,
channel_on_user_connection_change,
} from "../const/channel_names";
import InfoPanel from "../components/InfoPanel";
import { CommonMancalaGame, MancalaGame, Pit } from "mancala.js";
import { GameMove } from "../models/GameMove";
import PitAnimator from "../animation/PitAnimator";
import BoardViewModel from "../viewmodel/BoardViewModel";
import { v4 } from "uuid";
import { getColorByBrightness } from "../util/ColorUtil";
import { Theme } from "../theme/Theme";
import HeaderBar from "../components/headerbar/HeaderBar";
@ -26,228 +9,46 @@ import HeaderbarIcon from "../components/headerbar/HeaderbarIcon";
import HeaderbarTitle from "../components/headerbar/HeaderbarTitle";
import ThemeSwitchMenu from "../components/headerbar/ThemeSwitchMenu";
import Button from "../components/Button";
import BoardToolbar from "../components/board/BoardToolbar";
import UserStatus from "../components/UserStatus";
import Center from "../components/Center";
import CircularPanel from "../components/CircularPanel";
import useWindowDimensions from "../hooks/useWindowDimensions";
import { UserConnectionInfo } from "../models/UserConnectionInfo";
import { Context } from "../context/context";
import { ConnectionState } from "../models/ConnectionState";
import { Link, useNavigate } from "react-router-dom";
const Home: FunctionComponent<{
context: Context,
userKey?: string,
connectionState: ConnectionState
}> = ({ context, userKey, connectionState }) => {
theme: Theme,
}> = ({ context, userKey, theme }) => {
const [searchingOpponent, setSearchingOpponent] = useState<boolean>(false);
const [game, setGame] = useState<CommonMancalaGame | undefined>(undefined);
const [crashMessage, setCrashMessage] = useState<string | undefined>(undefined);
const [userKeyWhoLeave, setUserKeyWhoLeave] = useState<string | undefined>(undefined);
const [boardViewModel, setBoardViewModel] = useState<BoardViewModel | undefined>(undefined);
const [boardId, setBoardId] = useState<string>("-1");
const [pitAnimator, setPitAnimator] = useState<PitAnimator | undefined>(undefined);
const [theme, setTheme] = useState<Theme | undefined>(undefined);
// It is a flag for ongoing action such as send game move.
// We have to block future actions if there is an ongoing action.
const [hasOngoingAction, setHasOngoingAction] = useState<boolean>(false);
const { height, width } = useWindowDimensions();
const [isOpponentOnline, setIsOpponentOnline] = useState<boolean>(false);
const listenMessages = (pitAnimator: PitAnimator) => {
context.rtmt.listenMessage(channel_on_game_start, (message: Object) => {
const newGame: CommonMancalaGame = message as CommonMancalaGame;
const mancalaGame = MancalaGame.createFromMancalaGame(newGame);
setSearchingOpponent(false);
setGame(mancalaGame);
pitAnimator.setNewGame(mancalaGame);
setHasOngoingAction(false);
});
context.rtmt.listenMessage(channel_on_game_update, (message: Object) => {
const newGame: CommonMancalaGame = message as CommonMancalaGame;
const mancalaGame = MancalaGame.createFromMancalaGame(newGame);
setGame(mancalaGame);
pitAnimator.setUpdatedGame(mancalaGame);
setHasOngoingAction(false);
});
context.rtmt.listenMessage(channel_on_game_crashed, (message: any) => {
const newCrashMessage = message as string;
console.error("on_game_crash");
console.error(newCrashMessage);
setCrashMessage(newCrashMessage);
});
context.rtmt.listenMessage(channel_on_game_user_leave, (message: any) => {
const userKeyWhoLeave = message;
setUserKeyWhoLeave(userKeyWhoLeave);
setHasOngoingAction(false);
});
context.rtmt.listenMessage(channel_on_user_connection_change, (message: any) => {
const userConnectionInfo = message as UserConnectionInfo;
//todo: change this when implementing watch the game feature
setIsOpponentOnline(userConnectionInfo.isOnline);
})
};
const updateBoardViewModel = (boardViewModel: BoardViewModel) => {
boardViewModel.id = v4();
setBoardId(boardViewModel.id);
setBoardViewModel(boardViewModel);
};
const resetGameState = () => {
setGame(undefined);
setCrashMessage(undefined);
setUserKeyWhoLeave(undefined);
setHasOngoingAction(false);
};
const getBoardIndex = (index: number) => {
if (!game) return -1;
if (userKey === game.player2Id) return index + game.board.pits.length / 2;
return index;
};
const getOpponentId = () => game?.player1Id === userKey ? game?.player2Id : game?.player1Id;
const checkHasAnOngoingAction = () => hasOngoingAction;
React.useEffect(() => {
setTheme(context.themeManager.theme);
const pitAnimator = new PitAnimator(context, updateBoardViewModel);
setPitAnimator(pitAnimator);
listenMessages(pitAnimator);
return () => {
pitAnimator.dispose();
};
}, []);
React.useEffect(() => {
context.themeManager.onThemeChange = (theme) => {
setTheme(theme);
pitAnimator && game && updateBoardViewModel(pitAnimator.getBoardViewModelFromGame(game));
};
}, [boardViewModel]);
const navigate = useNavigate();
const onNewGameClick = () => {
resetGameState();
setSearchingOpponent(true);
context.rtmt.sendMessage("new_game", {});
navigate("/loby")
};
const onLeaveGameClick = () => {
context.rtmt.sendMessage(channel_leave_game, {});
};
const onPitSelect = (index: number, pit: Pit) => {
if (checkHasAnOngoingAction()) {
return;
}
setHasOngoingAction(true);
if (!boardViewModel) return;
//TODO : stoneCount comes from view model!
if (pit.stoneCount === 0) {
//TODO : warn user
return;
}
boardViewModel.pits[getBoardIndex(index)].pitColor =
context.themeManager.theme.pitSelectedColor;
updateBoardViewModel(boardViewModel);
const gameMove: GameMove = { index: index };
context.rtmt.sendMessage(channel_game_move, gameMove);
};
const textColorOnBoard = getColorByBrightness(
context.themeManager.theme.boardColor,
context.themeManager.theme.textColor,
context.themeManager.theme.textLightColor
);
const textColorOnAppBar = getColorByBrightness(
context.themeManager.theme.appBarBgColor,
context.themeManager.theme.textColor,
context.themeManager.theme.textLightColor
);
const renderNewGameBtn = userKeyWhoLeave || !game || (game && game.state == "ended");
const showBoardView = game && boardViewModel && userKey && true;
const opponentUser = { id: getOpponentId() || "0", name: "Anonymous", isOnline: isOpponentOnline, isAnonymous: true };
const user = { id: userKey || "1", name: "Anonymous", isOnline: connectionState === "connected", isAnonymous: true };
const isMobile = width < 600;
return (
<PageContainer theme={theme!}>
<HeaderBar color={theme?.appBarBgColor}>
<Row>
<HeaderbarIcon />
<HeaderbarTitle title={context.texts.Mancala} color={textColorOnAppBar} />
<Link style={{ textDecoration: 'none' }} to={"/"}>
<HeaderbarIcon />
</Link>
<Link style={{ textDecoration: 'none' }} to={"/"}>
<HeaderbarTitle title={context.texts.Mancala} color={textColorOnAppBar} />
</Link>
</Row>
<Row>
<ThemeSwitchMenu context={context} textColor={textColorOnAppBar} />
<Button
context={context}
color={context.themeManager.theme.pitColor}
text={renderNewGameBtn ? context.texts.NewGame : context.texts.Leave}
onClick={renderNewGameBtn ? onNewGameClick : onLeaveGameClick} />
text={context.texts.NewGame}
onClick={onNewGameClick} />
</Row>
</HeaderBar>
<BoardToolbar style={{ justifyContent: "center" }} visible={showBoardView && isMobile || false}>
<InfoPanel
style={{ marginTop: "0.5rem", marginBottom: "0.5rem" }}
context={context}
game={game}
crashMessage={crashMessage}
userKey={userKey}
userKeyWhoLeave={userKeyWhoLeave} />
</BoardToolbar>
<BoardToolbar style={{ alignItems: "flex-end" }} visible={showBoardView || false}>
<UserStatus style={{
marginBottom: "0.5rem", marginLeft: "6%", maxWidth: isMobile ? "40vw" : "30vw",
width: isMobile ? "40vw" : "30vw"
}} context={context} layoutMode="left" user={opponentUser} visible={showBoardView || false} />
<InfoPanel
style={{
marginTop: "0.5rem", marginBottom: "0.5rem",
}}
context={context}
game={game}
crashMessage={crashMessage}
userKey={userKey}
userKeyWhoLeave={userKeyWhoLeave}
visible={!isMobile} />
<UserStatus style={{
marginBottom: "0.5rem", marginRight: "6%", maxWidth: isMobile ? "40vw" : "30vw",
width: isMobile ? "40vw" : "30vw"
}} context={context} layoutMode="right" user={user} visible={showBoardView || false} />
</BoardToolbar>
{showBoardView ? (
<BoardView
userKey={userKey}
game={game}
boardId={boardId}
boardViewModel={boardViewModel}
context={context}
onPitSelect={onPitSelect} />
) : searchingOpponent && (
<Center>
<CircularPanel color={context.themeManager.theme.boardColor}>
<h4 style={{ margin: "0", color: textColorOnBoard }}>{`${context.texts.SearchingOpponent} ${context.texts.PleaseWait}...`}</h4>
</CircularPanel>
</Center>
)}
</PageContainer>
);
};