euchre-live

Euchre web-app for the socially distant family
git clone git://git.alexkarle.com/euchre-live.git
Log | Files | Refs | README | LICENSE

commit 0ca87da278c7abe78c68f1cf2b354365b695f65d (patch)
parent dd8eacbbc87ff296669cfb98aa30edd271122aea
Author: Chris Karle <chriskarle@hotmail.com>
Date:   Fri, 22 May 2020 01:41:30 -0400

CardTable, ChatPanel

Implement chat functionality by building out ChatPanel.

Fix the known margin problems introduced by refactoring layout to
two, side-by-side Grid comps... likely be one or two more
discovered in play testing.

Diffstat:
Massets/app.scss | 40++++++++++++++++++++++++++++++++++------
Massets/components/CardTable.js | 37+++++++++++++++++++++++++++++++------
Aassets/components/ChatPanel.js | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 177 insertions(+), 12 deletions(-)

diff --git a/assets/app.scss b/assets/app.scss @@ -36,10 +36,13 @@ } .table__main { - margin-top: 2rem; + // margin-top: 2rem; min-width: 950px; min-height: 650px; } +.banner { + padding-top: 1rem; +} .og { padding-left: 0; @@ -52,6 +55,7 @@ display: flex; flex-direction: column; align-items: flex-end; + padding-top: 1rem; } .exit__row { @@ -62,6 +66,10 @@ .leave__button { font-size: 1.3rem; } +.menu__holder { + padding-top: 1rem; + padding-left: 2rem; +} .seat__picker { height: 46vh; margin-top: 2vh; @@ -110,6 +118,7 @@ display: flex; flex-direction: column; align-items: center; + padding-top: 1rem; } .partner__info { width: 100%; @@ -145,8 +154,27 @@ // background-color: cadetblue; } -.chat__tile { +.chat__panel { width: 100%; + display: flex; + flex-direction: column; + border: 1px solid; +} +.chat__holder { + flex: auto; + max-height: 207px; +} +.chat__tile { + height: 100%; + overflow: auto; + background-color: whitesmoke; +} +.chat__input__row { + display: flex; +} +.chat__post { + padding-right: 0.3rem; + padding-left: 0.3rem; } .hid__card { width: 30px; @@ -272,6 +300,7 @@ } .table__bot { height: 20vh; + margin-left: 0; } .tt__right { height: 20vh; @@ -282,11 +311,10 @@ height: 35vh; // background-color: lightsalmon; } +.tb__left { + padding-left: 2rem; +} - -// .tb__left { -// background-color: slategray; -// } // .hd__left { // background-color: rosybrown; // } diff --git a/assets/components/CardTable.js b/assets/components/CardTable.js @@ -1,12 +1,13 @@ import React from 'react'; import PropTypes from 'prop-types'; import _ from 'lodash'; -import {Button, Grid, Row, Column, OverflowMenu, OverflowMenuItem, Tile} from 'carbon-components-react'; +import {Button, Grid, Row, Column, OverflowMenu, OverflowMenuItem} from 'carbon-components-react'; import {Logout32, Redo32, Package32} from '@carbon/icons-react'; import SeatPicker from './SeatPicker'; import MainHand from './MainHand'; import HiddenHand from './HiddenHand'; import TrumpPicker from './TrumpPicker'; +import ChatPanel from './ChatPanel'; const trumpPlacement = ['me', 'left', 'partner', 'right']; const suit = { @@ -56,7 +57,8 @@ export default class CardTable extends React.Component { innerWinMsg: '', onlyAlone: false, noPick: false, - amSpectator: false + amSpectator: false, + latestPost: '' }; }; @@ -95,9 +97,20 @@ export default class CardTable extends React.Component { } else { this.processLobby(msg); } - }; + } else if ('chat' == msg.msg_type) { + this.processChat(msg); + } }; + processChat = msg => { + let post = msg.msg; + if (post && post != '') { + this.setState({ + latestPost: post + }); + } + } + processResponseSwitch = msg => { switch (msg.game.phase) { case 'lobby': @@ -518,6 +531,16 @@ export default class CardTable extends React.Component { })); } + sendChat = post => { + console.log(post); + if (post && post != ''){ + this.props.client.send(JSON.stringify({ + action: 'chat', + msg: post + })); + } + } + genGameOver = () => { const {innerWinMsg, amSpectator} = this.state; let retVal = []; @@ -644,7 +667,7 @@ export default class CardTable extends React.Component { const { playerNames, mySeat, phase, myCards, myTurnInfo, amSpectator, partnerHandInfo, partnerTurnInfo, partnerSeat, leftTurnInfo, leftHandInfo, leftSeat, rightHandInfo, rightTurnInfo, rightSeat, trumpPlace, trumpNom, turnSeat, - dealSeat, trump, handLengths, score, trickWinner, bannerMsg, noPick, onlyAlone } = this.state; + dealSeat, trump, handLengths, score, trickWinner, bannerMsg, noPick, onlyAlone, latestPost } = this.state; const showSeatPicker = phase == 'lobby'; const showGameOver = phase == 'end'; const showTrump = (phase == 'vote') || (phase == 'vote2') || (phase == 'swap'); @@ -666,7 +689,7 @@ export default class CardTable extends React.Component { <Grid className="inner__left"> {(showSeatPicker || showGameOver) && ( <Row className="table__header"> - <h3>{bannerMsg}</h3> + <h3 className="banner">{bannerMsg}</h3> </Row> )} <Row className="table__top"> @@ -807,7 +830,9 @@ export default class CardTable extends React.Component { </div>)} </Row> <Row className="tb__right"> - <Tile className="chat__tile">Coming Soon! future chat area here</Tile> + <ChatPanel + receivedChat={latestPost} + sendChat={this.sendChat} /> </Row> </Grid> </Column> diff --git a/assets/components/ChatPanel.js b/assets/components/ChatPanel.js @@ -0,0 +1,111 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Tile, TextInput, Button } from 'carbon-components-react'; +import {SendFilled16} from '@carbon/icons-react'; + +const MAX_POSTS = 40; + +class ChatPanel extends React.Component { + + constructor(props) { + super(props); + this.state = { + post: '', + numPosts: 0, + postArray: [] + } + }; + + componentDidUpdate (prevProps) { + const { receivedChat } = this.props; + const { postArray, numPosts } = this.state; + let nextArray = postArray; + if (receivedChat && (receivedChat != prevProps.receivedChat)){ + const nextNum = numPosts + 1; + const id = 'post-' + nextNum; + nextArray.push( + <p className="chat__post" + key={nextNum} + id={id}>{receivedChat}</p> + ); + if (nextArray.length > MAX_POSTS){ + nextArray = nextArray.slice(1); + } + this.setState({ + postArray: nextArray, + numPosts: nextNum + }, () => { + const element = document.getElementById(id); + if (element) { + console.log(element); + setTimeout(()=>{ + element.scrollIntoView(); + }, 100); + } + }); + // document.getElementById("chat__tile").scrollIntoView(false); + // if (this.chatTile) { + // console.log(this.chatTile); + // this.chatTile.scrollIntoView(false); + // } + } + } + + handleChatIn = event => { + const val = event.target.value; + console.log(val); + this.setState({ post: val}); + } + + handleSendPost = () => { + const { post } = this.state; + if (post && post != ''){ + this.props.sendChat(post); + } + this.setState({ + post: '' + }); + this.chatIn.value = ''; + this.postButton.blur(); + } + + render () { + const { post, postArray } = this.state; + return ( + <div className="chat__panel"> + <div className="chat__holder"> + <div className="chat__tile"> + {postArray} + </div> + </div> + <div className="chat__input__row"> + <TextInput + id="chat__in" + light + className="chat__in__input" + placeholder="enter chat posts here" + size="sm" + onChange={this.handleChatIn} + ref={(input) => {this.chatIn = input;}} + /> + <Button + className="post__button" + size="small" + hasIconOnly={true} + onClick={this.handleSendPost} + renderIcon={SendFilled16} + iconDescription="send chat" + tooltipPosition="bottom" + ref={(button) => {this.postButton = button;}} + /> + </div> + </div> + ) + } + +} +ChatPanel.propTypes = { + receivedChat: PropTypes.string, + sendChat: PropTypes.func +} +export default ChatPanel; +\ No newline at end of file