commit 9784950f377f5a1349471e5f378ea573a350fba5 (patch)
parent 894fa1b729e9014b0cb359847b6df91baa0a8813
Author: Chris Karle <chriskarle@hotmail.com>
Date: Tue, 14 Apr 2020 00:57:33 -0400
CardTable, MainHand
When game starts, apply names so local user is bottom.
Created MainHand row of clickable cards - overlapping
cards TBD.
Comment grid colors (just a layout guide).
Diffstat:
5 files changed, 247 insertions(+), 63 deletions(-)
diff --git a/assets/app.js b/assets/app.js
@@ -6,9 +6,11 @@ import CardTable from './components/CardTable';
import { w3cwebsocket as W3CWebSocket } from 'websocket';
const client = new W3CWebSocket('ws://localhost:3000/play');
+// additional fakeClient sockets, only used on debug
+let fc1, fc2, fc3 = null;
-const tableDebug = false;
+const tableDebug = true;
class App extends React.Component {
@@ -21,16 +23,17 @@ class App extends React.Component {
tableName: initialTable,
showTable: tableDebug
};
- if (tableDebug) { // on tableDebug send join w initialTable to server
- // wait 1 second so socket establishes connection
+ if (tableDebug) {
+ // on tableDebug send join plus add 3 fakeClient players that join+sit
+ fc1 = new W3CWebSocket('ws://localhost:3000/play');
+ fc2 = new W3CWebSocket('ws://localhost:3000/play');
+ fc3 = new W3CWebSocket('ws://localhost:3000/play');
+ // wait 1 second so sockets establish connection
setTimeout(()=>{
- client.send(JSON.stringify({
- action:'join_game',
- player_name: initialName,
- game_id: initialTable
- }));
+ this.setFakeGame(initialName, initialTable);
}, 1000);
}
+ this.pingTimer = setInterval(() => { client.send(JSON.stringify({action:'ping'})) }, 5000);
}
setPlayerName = name => {
@@ -53,6 +56,16 @@ class App extends React.Component {
});
}
+ setFakeGame = (initialName, initialTable) => {
+ client.send(JSON.stringify({ action:'join_game', player_name: initialName, game_id: initialTable }));
+ fc1.send(JSON.stringify({ action:'join_game', player_name: 'Betty', game_id: initialTable }));
+ fc2.send(JSON.stringify({ action:'join_game', player_name: 'CJ', game_id: initialTable }));
+ fc3.send(JSON.stringify({ action:'join_game', player_name: 'Dana', game_id: initialTable }));
+ fc1.send(JSON.stringify({ action:'take_seat', seat: 0 }));
+ fc2.send(JSON.stringify({ action:'take_seat', seat: 1 }));
+ fc3.send(JSON.stringify({ action:'take_seat', seat: 3 }));
+ }
+
render () {
const {showTable, playerName, tableName} = this.state;
return (
diff --git a/assets/app.scss b/assets/app.scss
@@ -50,6 +50,32 @@
align-items: center;
height: 20vh;
}
+.start__game {
+ display: flex;
+ .bx--dropdown__wrapper {
+ width: -webkit-fill-available;
+ }
+}
+.player__name {
+ font-size: 1.3rem;
+}
+.tm__left {
+ // background-color: rgb(217, 249, 255);
+ .player__name {
+ float: right;
+ }
+}
+.tt__center {
+ // background-color: rgb(217, 249, 255);
+ text-align: center;
+}
+
+.mh__card {
+ width: 100px;
+}
+.mh__card__row {
+ display: flex;
+}
.table__header {
height: 10vh;
@@ -64,36 +90,33 @@
height: 20vh;
}
-.hd__left {
- background-color: rosybrown;
-}
-.hd__right {
- background-color: skyblue;
-}
-.tt__left {
- background-color: slategray;
-}
-.tt__center {
- background-color: lightgreen;
-}
-.tt__right {
- background-color: lightsalmon;
-}
-.tm__left {
- background-color: lightskyblue;
-}
+
+
+// .tm__right {
+// background-color: rgb(217, 249, 255);
+// }
+// .tb__center {
+// background-color: rgb(217, 249, 255);
+// }
+
+// .tb__left {
+// background-color: slategray;
+// }
+// .tb__right {
+// background-color: lightsalmon;
+// }
+// .hd__left {
+// background-color: rosybrown;
+// }
+// .hd__right {
+// background-color: skyblue;
+// }
+// .tt__left {
+// background-color: slategray;
+// }
+// .tt__right {
+// background-color: lightsalmon;
+// }
// .tm__center {
// background-color: lightpink;
// }
-.tm__right {
- background-color: lightgreen;
-}
-.tb__left {
- background-color: slategray;
-}
-.tb__center {
- background-color: lightgreen;
-}
-.tb__right {
- background-color: lightsalmon;
-}
diff --git a/assets/components/CardTable.js b/assets/components/CardTable.js
@@ -4,6 +4,7 @@ import _ from 'lodash';
import {Button, Grid, Row, Column} from 'carbon-components-react';
import {Logout32} from '@carbon/icons-react';
import SeatPicker from './SeatPicker';
+import MainHand from './MainHand';
export default class CardTable extends React.Component {
@@ -11,7 +12,12 @@ export default class CardTable extends React.Component {
super(props);
this.state = {
playerNames: [],
- mySeat: -1
+ mySeat: -1,
+ phase: 'lobby',
+ left: { name: '', seat: -1 },
+ partner: { name: '', seat: -1 },
+ right: { name: '', seat: -1 },
+ myCards: []
};
};
@@ -22,25 +28,68 @@ export default class CardTable extends React.Component {
processResponse = (event) => {
let msg = JSON.parse(event.data);
- console.log(msg);
+ if ('pong' != msg.msg_type) {
+ console.log(msg);
+ }
if ('game_state' == msg.msg_type) {
- if ('lobby' == msg.game.phase){
- this.processLobby(msg);
+ if (msg.game) {
+ switch (msg.game.phase) {
+ case 'lobby':
+ this.processLobby(msg);
+ break;
+ case 'vote':
+ this.processVote(msg);
+ break;
+ default:
+ break;
+ }
}
};
};
processLobby = (msg) => {
- if (msg && msg.game && msg.game.players) {
+ if (msg.game.players) {
const plAr = msg.game.players;
const mySeat = plAr.findIndex( x => x == this.props.name );
this.setState({
playerNames: plAr,
- mySeat: mySeat
+ mySeat: mySeat,
+ phase: 'lobby'
})
};
};
+ processVote = (msg) => {
+ if (this.state.phase == 'lobby') {
+ this.gameStartSetup();
+ }
+ this.setState({
+ phase: 'vote',
+ myCards: msg.hand
+ });
+ };
+
+ gameStartSetup = () => {
+ const { playerNames, mySeat } = this.state;
+ const leftSeat = (mySeat + 1) % 4;
+ const partnerSeat = (mySeat + 2) % 4;
+ const rightSeat = (mySeat + 3) % 4;
+ this.setState ({
+ left : {
+ name: playerNames[leftSeat],
+ seat: leftSeat
+ },
+ partner : {
+ name: playerNames[partnerSeat],
+ seat: partnerSeat
+ },
+ right : {
+ name: playerNames[rightSeat],
+ seat: rightSeat
+ }
+ });
+ };
+
sendSit = (index) => {
const { client } = this.props;
client.send(JSON.stringify({
@@ -56,14 +105,28 @@ export default class CardTable extends React.Component {
}));
};
+ sendStart = (startDealer) => {
+ this.props.client.send(JSON.stringify({
+ action: 'start_game'
+ }))
+ console.log('start game, dealer = ', startDealer);
+ };
+
+ sendCard = (index) => {
+ console.log('card click ', index);
+ }
+
render () {
- const { playerNames, mySeat } = this.state;
+ const { playerNames, mySeat, phase, left, partner, right, myCards } = this.state;
const {name, tableName} = this.props;
+ const showSeatPicker = phase == 'lobby';
+ const showTrump = phase == 'vote';
const welcomeMsg = 'Welcome to the ' + tableName + ' table, ' + name + '!';
return (
<div id="table">
<Grid>
- <Row className="table__header">
+ {showSeatPicker && (
+ <Row className="table__header">
<Column className="hd__left" sm={3}>
<h3>{welcomeMsg}</h3>
</Column>
@@ -77,43 +140,46 @@ export default class CardTable extends React.Component {
</div>
</Column>
</Row>
+ )}
<Row className="table__top">
<Column className="tt__left" sm={1}>
- <div>yo!</div>
</Column>
<Column className="tt__center" sm={2}>
- <div>yo!</div>
+ <div className="player__name">{partner.name}</div>
</Column>
<Column className="tt__right" sm={1}>
- <div>yo!</div>
</Column>
</Row>
<Row className="table__mid">
<Column className="tm__left" sm={1}>
- <div>yo!</div>
+ <div className="player__name">{left.name}</div>
</Column>
<Column className="tm__center" sm={2}>
- {/* <div>yo!</div> */}
+ {showSeatPicker && (
<SeatPicker
names={playerNames}
handleSit={this.sendSit}
handleStand={this.sendStand}
mySeat={mySeat}
- />
+ handleStart={this.sendStart}
+ />)}
</Column>
<Column className="tm__right" sm={1}>
- <div>yo!</div>
+ <div className="player__name">{right.name}</div>
</Column>
</Row>
<Row className="table__bot">
<Column className="tb__left" sm={1}>
- <div>yo!</div>
</Column>
<Column className="tb__center" sm={2}>
- <div>yo!</div>
+ {!showSeatPicker && (
+ <MainHand
+ cards={myCards}
+ cardClick={this.sendCard}
+ />
+ )}
</Column>
<Column className="tb__right" sm={1}>
- <div>yo!</div>
</Column>
</Row>
</Grid>
diff --git a/assets/components/MainHand.js b/assets/components/MainHand.js
@@ -0,0 +1,41 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {Button, Link} from 'carbon-components-react';
+
+class MainHand extends React.Component {
+
+ cardButtons = (cards) => {
+ let buttons = [];
+ cards.map((card, index) => {
+ const cardSrc = 'cards/' + card + '.svg';
+ buttons.push(
+ <div
+ key={index}
+ className="mh__card__div">
+ <Link
+ className="mh__card__link"
+ href="javascript:void(0)"
+ onClick={()=> this.props.cardClick(index)}>
+ <img className="mh__card" src={cardSrc} />
+ </Link>
+ </div>
+ )
+ });
+ return buttons;
+ }
+
+ render () {
+ const { cards } = this.props;
+ const cardButtons = this.cardButtons(cards);
+ return (
+ <div className="mh__card__row">
+ {cardButtons}
+ </div>
+ );
+ };
+}
+MainHand.propTypes = {
+ cards: PropTypes.arrayOf(PropTypes.string),
+ cardClick: PropTypes.func
+}
+export default MainHand;
+\ No newline at end of file
diff --git a/assets/components/SeatPicker.js b/assets/components/SeatPicker.js
@@ -1,15 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';
-import {Button, Grid, Row, Column} from 'carbon-components-react';
-import {Package32, Export32} from '@carbon/icons-react';
+import {Button, Grid, Row, Column, Dropdown} from 'carbon-components-react';
+import {Package32, Export32, Play32} from '@carbon/icons-react';
class SeatPicker extends React.Component {
constructor(props) {
super(props);
- //this.state - unneeded?
- }
+ this.state = {
+ startDealer: -2
+ }
+ };
+
+ allSeated = names => {
+ const matchIndex = names.findIndex(name => name == 'Empty');
+ return matchIndex == -1;
+ };
+ dealerChange = (e) => {
+ const { names } = this.props;
+ const selectIndex = names.findIndex(name => e.selectedItem == name);
+ this.setState({
+ startDealer: selectIndex
+ });
+ };
tableSeat = (name, index) => {
const taken = name != 'Empty';
@@ -37,7 +51,11 @@ class SeatPicker extends React.Component {
}
render () {
- const {names} = this.props;
+ const { names } = this.props;
+ const { startDealer } = this.state;
+ const allSeated = this.allSeated(names);
+ const pickerNames = names.slice(0);
+ pickerNames.unshift('Random');
return (
<div id="seatPicker" className="seat__picker">
<Grid>
@@ -56,14 +74,36 @@ class SeatPicker extends React.Component {
{this.tableSeat(names[0], 0)}
</Row>
</Grid>
+ { allSeated && (
+ <div id="startGame" className="start__game">
+ <Dropdown
+ id="dealer__drop"
+ className="dealer__drop"
+ label="Choose Dealer..."
+ size="xl"
+ itemToElement={null}
+ items={pickerNames}
+ onChange={(event)=>this.dealerChange(event)}
+ />
+ <Button
+ className="start__game__button"
+ hasIconOnly={true}
+ iconDescription="set name"
+ tooltipPosition="bottom"
+ disabled={startDealer < -1}
+ onClick={()=>{this.props.handleStart(startDealer)}}
+ renderIcon={Play32}>Play! </Button>
+ </div>
+ )}
</div>
- )
+ );
}
}
SeatPicker.propTypes = {
mySeat: PropTypes.number,
names: PropTypes.arrayOf(PropTypes.string),
handleSit: PropTypes.func,
- handleStand: PropTypes.func
+ handleStand: PropTypes.func,
+ handleStart: PropTypes.func
}
export default SeatPicker;