Files
splendor-clone/src/components/Gameboard/Gameboard.tsx

108 lines
4.2 KiB
TypeScript

// types, data, utils
import { useCallback, useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import initializeBoard, { setCardRows } from '../../util/initializeBoard';
import { AppState, PlayerData, ResourceCost } from '../../util/types';
import { getChipsActions } from '../Player/ActionMethods';
import { StateProps } from '../../util/propTypes';
import './Gameboard.scss';
// components
import Nobles from '../Nobles/Nobles';
import AvailableChips from '../Resources/AvailableChips';
import AllPlayers from '../Player/AllPlayers';
import CardRow from '../Card/CardRow';
import SelectionView from '../Resources/SelectionView';
import { useCurrentPlayer } from '../../hooks/useCurrentPlayer';
import usePreviousPlayer from '../../hooks/usePreviousPlayer';
const { validateChips } = getChipsActions;
export default function Gameboard({ state, setState }: StateProps) {
const [view, setView] = useState(<p>Loading...</p>);
const [endgame, setEndgame] = useState<PlayerData>();
const [winner, setWinner] = useState<PlayerData>();
// callbacks for lifting state
const liftSelection = useCallback((value: keyof ResourceCost) => {
if (!state.actions.getChips.active) return;
setState((prev: AppState) => {
let newSelection = prev.actions.getChips.selection;
newSelection?.push(value);
let newState = {
...prev,
actions: {
...state.actions,
getChips: {
active: true,
selection: newSelection,
valid: false
}
}
}
const result = validateChips(newState);
newState.actions.getChips.valid = result;
return newState;
})
}, [state]);
// util functions, setup on mount
useEffect(() => initializeBoard(state, setState), [])
useEffect(() => {
setCardRows(state);
}, [state])
// endgame logic: once triggered, sets "endgame" to the player who triggered the effect
useEffect(() => {
const previousPlayer = usePreviousPlayer(state);
if (previousPlayer && previousPlayer.points >= 15) setEndgame(previousPlayer);
}, [state])
// endgame logic: determines the player with highest score after remaining allowed turns
useEffect(() => {
if (endgame) {
let winner: PlayerData;
const winnerData = state.players;
const currentPlayer = useCurrentPlayer(state);
if (!currentPlayer) return;
if (currentPlayer.id <= endgame.id) {
winner = winnerData.sort((x,y) => x.points + y.points)[0];
console.log(winner.name + ' wins!');
}
}
}, [state, endgame])
// rendering: displays state of board if data is populated, otherwise points to game constructor
useEffect(() => {
if (!state.players.length) {
setView(
<div className="error-page">
<strong>Sorry! It appears we've lost track of your game data.</strong>
<p>Please head back to the <Link to="/">home page</Link> to start a fresh game.</p>
</div>
);
} else {
setView(
<div className="gameboard">
<section className="gameboard-left">
<h1 className="round-marker">Round: {state.round}</h1>
<Nobles state={state} setState={setState} />
<CardRow tier={3} state={state} setState={setState} />
<CardRow tier={2} state={state} setState={setState} />
<CardRow tier={1} state={state} setState={setState} />
</section>
<section className="gameboard-right">
<SelectionView state={state} setState={setState} />
<AvailableChips state={state} setState={setState} liftSelection={liftSelection} />
<AllPlayers state={state} setState={setState} />
</section>
</div>
)
}
}, [state]);
return view
}