
Separate who frmo text in Activities Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
178 lines
5.4 KiB
JavaScript
178 lines
5.4 KiB
JavaScript
import React, { useContext, useState, useMemo, useRef, useEffect } from "react";
|
|
import equal from "fast-deep-equal";
|
|
|
|
import { Resource } from './Resource.js';
|
|
import { Placard } from './Placard.js';
|
|
import { GlobalContext } from './GlobalContext.js';
|
|
import { assetsPath } from "./Common.js";
|
|
import "./Hand.css";
|
|
|
|
const Development = ({type, card, onClick}) => {
|
|
return (
|
|
<div className={`Development ${card.played ? 'Selected' : ''}`}
|
|
onClick={onClick}
|
|
style={{
|
|
backgroundImage:`url(${assetsPath}/gfx/card-${type}.png)`
|
|
}}/>
|
|
);
|
|
};
|
|
|
|
const Hand = ({buildActive, setBuildActive, setCardActive}) => {
|
|
const { ws } = useContext(GlobalContext);
|
|
const [priv, setPriv] = useState(undefined);
|
|
const [color, setColor] = useState(undefined);
|
|
const [turn, setTurn] = useState(undefined);
|
|
const [longestRoad, setLongestRoad] = useState(undefined);
|
|
const [largestArmy, setLargestArmy] = useState(undefined);
|
|
const [development, setDevelopment] = useState([]);
|
|
const [mostPorts, setMostPorts] = useState(undefined);
|
|
const [mostDeveloped, setMostDeveloped] = useState(undefined);
|
|
const [selected, setSelected] = useState(0);
|
|
|
|
const fields = useMemo(() => [
|
|
'private', 'turn', 'color', 'longestRoad', 'largestArmy', 'mostPorts', 'mostDeveloped'
|
|
], []);
|
|
const onWsMessage = (event) => {
|
|
const data = JSON.parse(event.data);
|
|
switch (data.type) {
|
|
case 'game-update':
|
|
console.log(`hand - game-update: `, data.update);
|
|
if ('private' in data.update && !equal(priv, data.update.private)) {
|
|
setPriv(data.update.private);
|
|
}
|
|
if ('turn' in data.update && !equal(turn, data.update.turn)) {
|
|
setTurn(data.update.turn);
|
|
}
|
|
if ('color' in data.update && color !== data.update.color) {
|
|
setColor(data.update.color);
|
|
}
|
|
if ('longestRoad' in data.update && longestRoad !== data.update.longestRoad) {
|
|
setLongestRoad(data.update.longestRoad);
|
|
}
|
|
if ('largestArmy' in data.update && largestArmy !== data.update.largestArmy) {
|
|
setLargestArmy(data.update.largestArmy);
|
|
}
|
|
if ('mostDeveloped' in data.update
|
|
&& data.update.mostDeveloped !== mostDeveloped) {
|
|
setMostDeveloped(data.update.mostDeveloped);
|
|
}
|
|
if ('mostPorts' in data.update
|
|
&& data.update.mostPorts !== mostPorts) {
|
|
setMostPorts(data.update.mostPorts);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
};
|
|
const refWsMessage = useRef(onWsMessage);
|
|
useEffect(() => { refWsMessage.current = onWsMessage; });
|
|
useEffect(() => {
|
|
if (!ws) { return; }
|
|
const cbMessage = e => refWsMessage.current(e);
|
|
ws.addEventListener('message', cbMessage);
|
|
return () => { ws.removeEventListener('message', cbMessage); }
|
|
}, [ws, refWsMessage]);
|
|
useEffect(() => {
|
|
if (!ws) { return; }
|
|
ws.send(JSON.stringify({
|
|
type: 'get',
|
|
fields
|
|
}));
|
|
}, [ws, fields]);
|
|
|
|
useEffect(() => {
|
|
if (!priv) {
|
|
return;
|
|
}
|
|
|
|
const cardClicked = (card) => {
|
|
setCardActive(card);
|
|
}
|
|
|
|
const stacks = {};
|
|
priv.development.forEach(card =>
|
|
(card.type in stacks)
|
|
? stacks[card.type].push(card)
|
|
: stacks[card.type] = [card]);
|
|
|
|
const development = [];
|
|
for (let type in stacks) {
|
|
const cards = stacks[type]
|
|
.sort((A, B) => {
|
|
if (A.played) {
|
|
return -1;
|
|
}
|
|
if (B.played) {
|
|
return +1;
|
|
}
|
|
return B.turn - A.turn; /* Put playable cards on top */
|
|
}).map(card => <Development
|
|
onClick={() => cardClicked(card)}
|
|
card={card}
|
|
key={`${type}-${card.card}`}
|
|
type={`${type}-${card.card}`}/>);
|
|
development.push(<div key={type} className="Stack">{ cards }</div>);
|
|
}
|
|
setDevelopment(development);
|
|
}, [priv, setDevelopment, setCardActive]);
|
|
|
|
useEffect(() => {
|
|
const count = document.querySelectorAll('.Hand .CardGroup .Resource.Selected');
|
|
if (count.length !== selected) {
|
|
setSelected(count.length);
|
|
}
|
|
}, [setSelected, selected, turn]);
|
|
|
|
if (!priv) {
|
|
return <></>;
|
|
}
|
|
|
|
const cardSelected = (event) => {
|
|
const count = document.querySelectorAll('.Hand .CardGroup .Resource.Selected');
|
|
setSelected(count.length);
|
|
}
|
|
|
|
return <div className="Hand">
|
|
{<div className="CardsSelected"
|
|
style={selected === 0 ? { display: 'none' } : {}}>
|
|
{selected} cards selected
|
|
</div>}
|
|
<div className="CardGroup">
|
|
<Resource type="wood" count={priv.wood} onClick={cardSelected}/>
|
|
<Resource type="wheat" count={priv.wheat} onClick={cardSelected} />
|
|
<Resource type="stone" count={priv.stone} onClick={cardSelected} />
|
|
<Resource type="brick" count={priv.brick} onClick={cardSelected} />
|
|
<Resource type="sheep" count={priv.sheep} onClick={cardSelected} />
|
|
</div>
|
|
<div className="CardGroup">
|
|
{ development }
|
|
</div>
|
|
{mostDeveloped && mostDeveloped === color &&
|
|
<Placard
|
|
type='most-developed'
|
|
/>
|
|
}
|
|
{mostPorts && mostPorts === color &&
|
|
<Placard
|
|
type='port-of-call'
|
|
/>
|
|
}
|
|
{ longestRoad && longestRoad === color &&
|
|
<Placard
|
|
type='longest-road'
|
|
/>
|
|
}
|
|
{ largestArmy && largestArmy === color &&
|
|
<Placard
|
|
type='largest-army'
|
|
/>
|
|
}
|
|
<Placard className="BuildCard"
|
|
{...{buildActive, setBuildActive}}
|
|
disabled={!turn || !turn.roll}
|
|
type={color}/>
|
|
</div>;
|
|
}
|
|
|
|
export { Hand }; |