Using sqlite database, mt proctor animation.
This commit is contained in:
@@ -34,9 +34,9 @@ class Chrome extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className='flex-fullcenter'>
|
||||
<div className='background-heading'><h1>Alpha Centauri Farming</h1></div>
|
||||
{this.props.children}
|
||||
<Tractor spikes={this.props.spikes} className={this.props.tractorClass} />
|
||||
<div className='background-heading'><h1>Alpha Centauri Farming</h1></div>
|
||||
{this.props.children}
|
||||
<Tractor spikes={this.props.spikes} className={this.props.tractorClass} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -49,31 +49,43 @@ class App extends React.Component {
|
||||
case SCREENS.intro:
|
||||
view = (<Chrome spikes={true} tractorClass='intro'><Welcome /></Chrome>);
|
||||
break;
|
||||
case SCREENS.start:
|
||||
view = (<Chrome><CreateOrJoin /></Chrome>);
|
||||
break;
|
||||
case SCREENS.newGame:
|
||||
view = (<Chrome>
|
||||
case SCREENS.start:
|
||||
view = (<Chrome><CreateOrJoin signOut={this.props.logout} /></Chrome>);
|
||||
break;
|
||||
case SCREENS.newGame:
|
||||
view = (<Chrome>
|
||||
<div className='view-container'>
|
||||
<NewGame colors={['green', 'red', 'blue', 'yellow', 'black']}
|
||||
button={'Start'}
|
||||
title={'New Game'}
|
||||
type={'new-game'}
|
||||
showGameName={true} />
|
||||
<NewGame colors={['green', 'red', 'blue', 'yellow', 'black']}
|
||||
button={'Start'}
|
||||
title={'New Game'}
|
||||
type={'new-game'}
|
||||
showGameName={true}
|
||||
createAccount={this.props.createAccount}
|
||||
login={this.props.login}
|
||||
errors={this.props.errors}
|
||||
/>
|
||||
</div>
|
||||
</Chrome>);
|
||||
break;
|
||||
case SCREENS.joinGame:
|
||||
view = (
|
||||
<Chrome>
|
||||
<div className='view-container'>
|
||||
<JoinGame createAccount={this.props.createAccount}
|
||||
login={this.props.login}
|
||||
errors={this.props.errors}
|
||||
/>
|
||||
</div>
|
||||
</Chrome>);
|
||||
break;
|
||||
case SCREENS.joinGame:
|
||||
view = (<Chrome><div className='view-container'><JoinGame /></div></Chrome>);
|
||||
break;
|
||||
case SCREENS.play:
|
||||
view = (<Board />);
|
||||
break;
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
{view}
|
||||
<div id={messagePanelId}><MessagePanel /></div>
|
||||
{view}
|
||||
<div id={messagePanelId}><MessagePanel /></div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
108
src/components/create-account/CreateAccount.jsx
Normal file
108
src/components/create-account/CreateAccount.jsx
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright 2020 Thomas Hintz
|
||||
//
|
||||
// This file is part of the Alpha Centauri Farming project.
|
||||
//
|
||||
// The Alpha Centauri Farming project is free software: you can
|
||||
// redistribute it and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software Foundation, either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// The Alpha Centauri Farming project is distributed in the hope that
|
||||
// it will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Alpha Centauri Farming project. If not, see
|
||||
// <https://www.gnu.org/licenses/>.
|
||||
|
||||
import React from 'react'
|
||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||
|
||||
export default class CreateAccount extends React.Component {
|
||||
state = {
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
loading: false
|
||||
}
|
||||
onChange = (e) => {
|
||||
const target = e.target,
|
||||
value = target.value,
|
||||
name = target.name;
|
||||
|
||||
this.setState({
|
||||
[name]: value
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
this.setState({ loading: true });
|
||||
this.props.createAccount(this.state);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.state.loading && prevProps.errors !== this.props.errors) {
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<GroupBox title="Create Account">
|
||||
<form onSubmit={this.onSubmit}>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
<label>
|
||||
Username
|
||||
<input onChange={this.onChange} required name="username" type="text" />
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
<label>
|
||||
Email (optional)
|
||||
<input onChange={this.onChange} name="email" type="email" />
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
<label>
|
||||
Password
|
||||
<input onChange={this.onChange} required name="password" type="password" />
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
<label>
|
||||
Confirm Password
|
||||
<input onChange={this.onChange} required name="confirmPassword" type="password" />
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
{!this.state.loading ? (
|
||||
<>
|
||||
{this.props.errors.map((err, i) => (
|
||||
<p key={i}>
|
||||
Error: {err}
|
||||
</p>
|
||||
))}
|
||||
<Button type="submit">Create Account</Button>
|
||||
</>
|
||||
) : (
|
||||
<span>Creating Account...</span>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</form>
|
||||
</GroupBox>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -19,21 +19,34 @@
|
||||
import React, { Fragment } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import Cookies from 'cookies-js'
|
||||
|
||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||
import { showNewGame, showJoinGame } from '../app/actions.js'
|
||||
|
||||
class CreateOrJoin extends React.Component {
|
||||
signOut = (e) => {
|
||||
e.preventDefault();
|
||||
this.props.signOut();
|
||||
Cookies.expire('awful-cookie');
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Fragment>
|
||||
<Button size='large' className='shadow' onClick={this.props.showNewGame}>
|
||||
New Game
|
||||
</Button>
|
||||
{this.props.start.start.games.length > 0 ? (
|
||||
<Button size='large' className='shadow' onClick={this.props.showJoinGame}>
|
||||
Join Game
|
||||
</Button>
|
||||
) : (<Fragment />)}
|
||||
<Button size='large' className='shadow' onClick={this.props.showNewGame}>
|
||||
New Game
|
||||
</Button>
|
||||
{(this.props.start.start.games.length > 0) || (this.props.start.start.openGames.length > 0) ? (
|
||||
<Button size='large' className='shadow' onClick={this.props.showJoinGame}>
|
||||
Join Game
|
||||
</Button>
|
||||
) : (<Fragment />)}
|
||||
{this.props.start.start.user ? (
|
||||
<Button size='large' className='shadow sign-out-button' onClick={this.signOut}>
|
||||
Sign Out
|
||||
</Button>
|
||||
) : (<></>)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import WheatImg from './../../../assets/img/wheat.svg'
|
||||
import TractorImg from './../../../assets/img/tractor-icon.svg'
|
||||
import TractorFullImg from './../../../assets/img/tractor-with-spikes.svg'
|
||||
import HarvesterImg from './../../../assets/img/harvester.svg'
|
||||
import VolcanoImg from './../../../assets/img/volcano2.gif'
|
||||
|
||||
import React, { Fragment } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
@@ -45,21 +46,21 @@ import { setSelectedCard, setMessagePanelSpace, setMPDims, movePlayer,
|
||||
setMovingSkip } from './actions.js'
|
||||
import { buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||
submitTradeDeny, submitTradeCancel, audit,
|
||||
buyUncleBert, skip, endAiTurn } from './interface.js'
|
||||
buyUncleBert, skip, endAiTurn, startGame } from './interface.js'
|
||||
|
||||
function netWorth(player) {
|
||||
return ((player.assets.hay + player.assets.grain) * 2000) +
|
||||
(player.assets.fruit * 5000) +
|
||||
(player.assets.cows * 500) +
|
||||
((player.assets.harvester + player.assets.tractor) * 10000) +
|
||||
(player.assets.fruit * 5000) +
|
||||
(player.assets.cows * 500) +
|
||||
((player.assets.harvester + player.assets.tractor) * 10000) +
|
||||
player.displayCash - player.debt;
|
||||
}
|
||||
|
||||
function assetsValue(player) {
|
||||
return ((player.assets.hay + player.assets.grain) * 2000) +
|
||||
(player.assets.fruit * 5000) +
|
||||
(player.assets.cows * 500) +
|
||||
((player.assets.harvester + player.assets.tractor) * 10000);
|
||||
(player.assets.fruit * 5000) +
|
||||
(player.assets.cows * 500) +
|
||||
((player.assets.harvester + player.assets.tractor) * 10000);
|
||||
}
|
||||
|
||||
function getElementValue(id) {
|
||||
@@ -464,20 +465,20 @@ class FarmsContainer extends React.Component {
|
||||
return (
|
||||
<GroupBox title='Farms'>
|
||||
<b>Ridges</b>:
|
||||
{ridgeNames.map((ridge, idx) => (
|
||||
<div key={idx} className={"farms-ridge player-" + ridges['ridge' + (idx + 1)]}>
|
||||
<span>{ridge}</span>
|
||||
<span className='num-cows'>{'(' + ((idx + 2) * 10) + ' cows)'}</span>
|
||||
</div>
|
||||
))}
|
||||
<br />
|
||||
{this.props.otherPlayers
|
||||
.map(p => (
|
||||
<div key={p.player.name}>
|
||||
<PlayerColorIcon color={p.player.color} />{'\u00A0'}
|
||||
<b>{p.player.name}</b> <PlayerResources player={p.player} />
|
||||
<br /> <br />
|
||||
</div>))}
|
||||
{ridgeNames.map((ridge, idx) => (
|
||||
<div key={idx} className={"farms-ridge player-" + ridges['ridge' + (idx + 1)]}>
|
||||
<span>{ridge}</span>
|
||||
<span className='num-cows'>{'(' + ((idx + 2) * 10) + ' cows)'}</span>
|
||||
</div>
|
||||
))}
|
||||
<br />
|
||||
{this.props.otherPlayers
|
||||
.map(p => (
|
||||
<div key={p.player.name}>
|
||||
<PlayerColorIcon color={p.player.color} />{'\u00A0'}
|
||||
<b>{p.player.name}</b> <PlayerResources player={p.player} />
|
||||
<br /> <br />
|
||||
</div>))}
|
||||
</GroupBox>
|
||||
);
|
||||
}
|
||||
@@ -521,11 +522,11 @@ const makeDefaultToTrade = () => {
|
||||
|
||||
class TradeContainer2 extends React.Component {
|
||||
resources = [{ img: HayImg,
|
||||
h: '120',
|
||||
s: '100',
|
||||
label: 'acres of Hay',
|
||||
key: 'hay',
|
||||
amount: 10
|
||||
h: '120',
|
||||
s: '100',
|
||||
label: 'acres of Hay',
|
||||
key: 'hay',
|
||||
amount: 10
|
||||
}, {
|
||||
img: WheatImg,
|
||||
h: '41',
|
||||
@@ -859,7 +860,7 @@ class CCBY extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Fragment>
|
||||
License Creative Commons <a href='https://creativecommons.org/licenses/by/3.0/us/legalcode'>CCBY</a>
|
||||
License Creative Commons <a href={`https://creativecommons.org/licenses/by/${this.props.version ? this.props.version : 3}.0/us/legalcode`}>CCBY</a>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
@@ -880,6 +881,9 @@ class Misc extends React.Component {
|
||||
<li>
|
||||
<img src={TractorFullImg} /> <img src={TractorImg} /> Copyright Nick Roach with modifications by Thomas Hintz - License <a href='GPL http://www.gnu.org/copyleft/gpl.html'>GPL</a>
|
||||
</li>
|
||||
<li>
|
||||
<img src={VolcanoImg} /> Copyright <a href="https://thenounproject.com/Maludk/">Laymik</a> - <CCBY />
|
||||
</li>
|
||||
<li>
|
||||
<img src={CornImg} /> <img src={FruitImg} /> Copyright <a href='https://madexmade.com/'>Made</a> - <CCBY />
|
||||
</li>
|
||||
@@ -1090,6 +1094,7 @@ class Die extends React.Component {
|
||||
trigger = 0;
|
||||
decayFactorPct = 0.4;
|
||||
showScreenTimerId = false;
|
||||
rollIndex = 0;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -1107,12 +1112,16 @@ class Die extends React.Component {
|
||||
}
|
||||
|
||||
roll() {
|
||||
let roll = random(6);
|
||||
while (roll === this.lastRoll) {
|
||||
roll = random(6);
|
||||
if (!this.props.rolls) {
|
||||
let roll = random(6);
|
||||
while (roll === this.lastRoll) {
|
||||
roll = random(6);
|
||||
}
|
||||
this.lastRoll = roll;
|
||||
return roll;
|
||||
} else {
|
||||
return this.props.rolls[++this.rollIndex];
|
||||
}
|
||||
this.lastRoll = roll;
|
||||
return roll;
|
||||
}
|
||||
|
||||
tick = () => {
|
||||
@@ -1272,6 +1281,7 @@ class Rolling extends React.Component {
|
||||
return (
|
||||
<GroupBox title={this.props.name + ' is rolling!'}>
|
||||
<Die decay={true} num={this.props.num} ms={2000} roll={true}
|
||||
rolls={this.props.rolls}
|
||||
showScreen={this.props.showScreen}
|
||||
skip={this.props.skip}
|
||||
autoSkip={this.props.autoSkip}
|
||||
@@ -1354,6 +1364,7 @@ class Harvest extends React.Component {
|
||||
break;
|
||||
case 'roll':
|
||||
view = (<Die decay={true} num={this.props.rolled} ms={2000} roll={true}
|
||||
rolls={this.props.rolls}
|
||||
showScreen={() => this.nextView('income')}
|
||||
skip={this.props.player.name === this.props.game.currentPlayer}
|
||||
autoSkip={this.props.autoSkip === 'die'}
|
||||
@@ -1569,6 +1580,7 @@ class Action extends React.Component {
|
||||
break;
|
||||
case 'harvest':
|
||||
view = (<Harvest rolled={this.props.ui.actionValue.rolled}
|
||||
rolls={this.props.ui.actionValue.rolls}
|
||||
player={this.props.player}
|
||||
currentPlayer={currentPlayer}
|
||||
harvestMult={this.props.ui.actionValue.harvestMult}
|
||||
@@ -1635,6 +1647,7 @@ class Action extends React.Component {
|
||||
(this.props.ui.actionValue.to < this.props.ui.actionValue.from ?
|
||||
this.props.ui.actionValue.from - 49 : this.props.ui.actionValue.from);
|
||||
view = (<Rolling num={roll}
|
||||
rolls={this.props.ui.actionValue.rolls}
|
||||
name={this.props.game.currentPlayer}
|
||||
showScreen={(this.props.player.name === this.props.game.currentPlayer ||
|
||||
currentPlayer.ai)
|
||||
@@ -1764,14 +1777,16 @@ class AlertOverlay extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className={'alert-overlay' + (this.state.visible ? '' : ' hidden') }>
|
||||
<div onClick={this.hide} className='alert-overlay-hide'>
|
||||
<FontAwesomeIcon icon={faTimes} />
|
||||
</div>
|
||||
{!this.props.preventHiding ? (
|
||||
<div onClick={this.hide} className='alert-overlay-hide'>
|
||||
<FontAwesomeIcon icon={faTimes} />
|
||||
</div>
|
||||
) : (<></>)}
|
||||
<div className='alert-overlay-contents'>
|
||||
{this.props.children}
|
||||
<br />
|
||||
<Button onClick={this.buttonClick}>{this.props.buttonText}</Button>
|
||||
<a onClick={this.hide}>close</a>
|
||||
{!this.props.preventHiding ? (<a onClick={this.hide}>close</a>) : (<></>)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -2015,6 +2030,30 @@ class BoardApp extends React.Component {
|
||||
</Fragment>
|
||||
</AlertOverlay>
|
||||
);
|
||||
} else if (alert && alert.type === ALERTS.preGame) {
|
||||
alertOverlay = (
|
||||
<AlertOverlay visible={true}
|
||||
id={alert.id}
|
||||
alertHandled={this.props.alertHandled}
|
||||
buttonText='Start Game'
|
||||
hideHandler={() => 'nothing'}
|
||||
preventHiding={true}
|
||||
handler={startGame}>
|
||||
<Fragment>
|
||||
<h1>Pre Game</h1>
|
||||
<p>When all players have joined click 'Start Game'!</p>
|
||||
<h3>Players</h3>
|
||||
<ul>
|
||||
<li>{this.props.player.name}</li>
|
||||
{this.props.game.otherPlayers.map((p, i) => (
|
||||
<li key={i}>
|
||||
{p.player.name}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Fragment>
|
||||
</AlertOverlay>
|
||||
);
|
||||
} else if (alert && alert.type === ALERTS.proposedTrade) {
|
||||
alertOverlay = (
|
||||
<AlertOverlay visible={true}
|
||||
|
||||
@@ -30,7 +30,8 @@ import { itemCard, fateCard } from 'game.js'
|
||||
|
||||
export { initialize, buy, roll, endTurn, loan, trade, submitTradeAccept,
|
||||
submitTradeDeny, submitTradeCancel, audit, handleMessage,
|
||||
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn }
|
||||
nextAction, buyUncleBert, actionsFinished, skip, endAiTurn,
|
||||
startGame }
|
||||
|
||||
let store;
|
||||
let movingTimer = 0;
|
||||
@@ -44,6 +45,13 @@ function handleMessage(evt) {
|
||||
return;
|
||||
}
|
||||
batch(() => {
|
||||
if (data.game.state === GAME_STATES.preGame) {
|
||||
store.dispatch(alert(ALERTS.preGame, '', 'pre-game'));
|
||||
}
|
||||
if (store.getState().farm.game.state === GAME_STATES.preGame &&
|
||||
data.game.state === GAME_STATES.preTurn) {
|
||||
store.dispatch(alertHandled('pre-game'));
|
||||
}
|
||||
if (data.player.state === GAME_STATES.preTurn &&
|
||||
data.game.otherPlayers.length > 0 &&
|
||||
store.getState().farm.player.state !== GAME_STATES.preTurn) {
|
||||
@@ -186,6 +194,10 @@ function skip(component) {
|
||||
sendCommand({ type: 'skip', component });
|
||||
}
|
||||
|
||||
function startGame() {
|
||||
sendCommand({ type: 'start-game' });
|
||||
}
|
||||
|
||||
// TODO share with Board.jsx
|
||||
// http://stackoverflow.com/questions/149055
|
||||
function formatMoney(n) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||
|
||||
import { startOrJoinGame } from '../start/actions.js'
|
||||
import { start } from '../app/actions.js'
|
||||
import LoginOrCreateAccount from '../login-or-create-account/LoginOrCreateAccount.jsx';
|
||||
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faArrowCircleLeft } from '@fortawesome/free-solid-svg-icons'
|
||||
@@ -36,14 +37,15 @@ class JoinGame extends React.Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
screen: JoinGameScreens.list,
|
||||
game: null
|
||||
game: null,
|
||||
showSignIn: false
|
||||
};
|
||||
}
|
||||
|
||||
handleClickGame = game => {
|
||||
this.setState({ screen: JoinGameScreens.details,
|
||||
game: game
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
handleBack = e => {
|
||||
@@ -54,59 +56,82 @@ class JoinGame extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleJoinAsExisting = e => {
|
||||
handleJoinAsExisting = (e, id) => {
|
||||
e.preventDefault();
|
||||
this.props.startOrJoinGame({ type: 'join-as-existing',
|
||||
playerName: e.target.text,
|
||||
gameId: this.state.game.id,
|
||||
gameName: this.state.game.name });
|
||||
gameId: id });
|
||||
}
|
||||
|
||||
showSignIn = (e) => {
|
||||
e.preventDefault();
|
||||
this.setState(state => { return { showSignIn: !state.showSignIn }; });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<GroupBox title={(
|
||||
<Fragment>
|
||||
<a href="#" onClick={this.handleBack}>
|
||||
<FontAwesomeIcon icon={faArrowCircleLeft} />
|
||||
</a>
|
||||
Join Game
|
||||
<a href="#" onClick={this.handleBack}>
|
||||
<FontAwesomeIcon icon={faArrowCircleLeft} />
|
||||
</a>
|
||||
Join Game
|
||||
</Fragment>
|
||||
)}>
|
||||
<Row>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
{this.state.screen === JoinGameScreens.list ?
|
||||
(<ul>
|
||||
{this.state.screen === JoinGameScreens.list ?
|
||||
(<>
|
||||
<h3>My Games</h3>
|
||||
{(!this.props.user && !this.state.showSignIn) ? (
|
||||
<a onClick={this.showSignIn}>Sign In to see your games</a>
|
||||
) : (<></>)}
|
||||
{(!this.props.user && this.state.showSignIn) ? (
|
||||
<>
|
||||
<hr />
|
||||
<LoginOrCreateAccount login={this.props.login}
|
||||
createAccount={this.props.createAccount}
|
||||
errors={this.props.errors}
|
||||
showLogin={true}
|
||||
/>
|
||||
<hr />
|
||||
</>
|
||||
) : (<></>)}
|
||||
<ul>
|
||||
{this.props.games
|
||||
.map((g, i) =>
|
||||
(<li key={i}>
|
||||
<a onClick={e => {
|
||||
e.preventDefault();
|
||||
this.handleClickGame(g); }}>{g.name}</a>
|
||||
</li>))}
|
||||
</ul>)
|
||||
: (
|
||||
<Fragment>
|
||||
<h3><b>Game:</b> {this.state.game.name}</h3>
|
||||
<h4>Join as existing player:</h4>
|
||||
<ul>
|
||||
{this.state.game.players.map((p, i) =>
|
||||
(<li key={i}>
|
||||
<a onClick={this.handleJoinAsExisting}>
|
||||
{p}
|
||||
</a>
|
||||
</li>))}
|
||||
</ul>
|
||||
<NewGame colors={this.state.game.colors}
|
||||
button={'Join'}
|
||||
showGameName={false}
|
||||
gameName={this.state.game.name}
|
||||
gameId={this.state.game.id}
|
||||
type={'join-game'}
|
||||
hideBack={true}
|
||||
title={'Join as New Player'} />
|
||||
</Fragment>)}
|
||||
</Col>
|
||||
</Row>
|
||||
.map((g, i) =>
|
||||
(<li key={i}>
|
||||
<a onClick={(e) => this.handleJoinAsExisting(e, g.id)}>{g.name}</a>
|
||||
</li>))}
|
||||
</ul>
|
||||
<h3>Open Games</h3>
|
||||
<ul>
|
||||
{this.props.openGames
|
||||
.map((g, i) =>
|
||||
(<li key={i}>
|
||||
<a onClick={e => {
|
||||
e.preventDefault();
|
||||
this.handleClickGame(g); }}>{g.name}</a>
|
||||
</li>))}
|
||||
</ul>
|
||||
</>
|
||||
)
|
||||
: (
|
||||
<Fragment>
|
||||
<h3><b>Game:</b> {this.state.game.name}</h3>
|
||||
<NewGame colors={this.state.game.colors}
|
||||
button={'Join'}
|
||||
showGameName={false}
|
||||
gameName={this.state.game.name}
|
||||
gameId={this.state.game.id}
|
||||
type={'join-game'}
|
||||
hideBack={true}
|
||||
createAccount={this.props.createAccount}
|
||||
login={this.props.login}
|
||||
errors={this.props.errors}
|
||||
title={'Join as New Player'} />
|
||||
</Fragment>)}
|
||||
</Col>
|
||||
</Row>
|
||||
</GroupBox>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2020 Thomas Hintz
|
||||
//
|
||||
// This file is part of the Alpha Centauri Farming project.
|
||||
//
|
||||
// The Alpha Centauri Farming project is free software: you can
|
||||
// redistribute it and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software Foundation, either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// The Alpha Centauri Farming project is distributed in the hope that
|
||||
// it will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Alpha Centauri Farming project. If not, see
|
||||
// <https://www.gnu.org/licenses/>.
|
||||
|
||||
import React from 'react'
|
||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||
|
||||
import CreateAccount from '../create-account/CreateAccount.jsx';
|
||||
import Login from '../login/Login.jsx';
|
||||
|
||||
export default class LoginOrCreateAccount extends React.Component {
|
||||
state = {
|
||||
showLogin: !!this.props.showLogin
|
||||
}
|
||||
|
||||
toggleLogin = (e) => {
|
||||
e.preventDefault();
|
||||
this.setState(state => { return { showLogin: !state.showLogin }; });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
{this.state.showLogin ? (
|
||||
<Login errors={this.props.errors} login={this.props.login} />
|
||||
) : (
|
||||
<CreateAccount errors={this.props.errors}
|
||||
createAccount={this.props.createAccount} />
|
||||
)}
|
||||
<div className="center">
|
||||
<a onClick={this.toggleLogin}>{this.state.showLogin ? 'Create Account' : 'Login'}</a>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
90
src/components/login/Login.jsx
Normal file
90
src/components/login/Login.jsx
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright 2020 Thomas Hintz
|
||||
//
|
||||
// This file is part of the Alpha Centauri Farming project.
|
||||
//
|
||||
// The Alpha Centauri Farming project is free software: you can
|
||||
// redistribute it and/or modify it under the terms of the GNU General
|
||||
// Public License as published by the Free Software Foundation, either
|
||||
// version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// The Alpha Centauri Farming project is distributed in the hope that
|
||||
// it will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
// PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Alpha Centauri Farming project. If not, see
|
||||
// <https://www.gnu.org/licenses/>.
|
||||
|
||||
import React from 'react'
|
||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||
|
||||
export default class Login extends React.Component {
|
||||
state = {
|
||||
username: '',
|
||||
password: '',
|
||||
loading: false
|
||||
}
|
||||
onChange = (e) => {
|
||||
const target = e.target,
|
||||
value = target.value,
|
||||
name = target.name;
|
||||
|
||||
this.setState({
|
||||
[name]: value
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
this.setState({ loading: true });
|
||||
this.props.login(this.state);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.state.loading && prevProps.errors !== this.props.errors) {
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<GroupBox title="Login">
|
||||
<form onSubmit={this.onSubmit}>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
<label>
|
||||
Username
|
||||
<input onChange={this.onChange} required name="username" type="text" />
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
<label>
|
||||
Password
|
||||
<input onChange={this.onChange} required name="password" type="password" />
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width="12">
|
||||
{!this.state.loading ? (
|
||||
<>
|
||||
{this.props.errors.map((err, i) => (
|
||||
<p key={i}>
|
||||
Error: {err}
|
||||
</p>
|
||||
))}
|
||||
<Button type="submit">Login</Button>
|
||||
</>
|
||||
) : (
|
||||
<span>Logging in...</span>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</form>
|
||||
</GroupBox>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import React, { Fragment } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import { GroupBox, Row, Col, Button } from '../widgets.jsx'
|
||||
import LoginOrCreateAccount from '../login-or-create-account/LoginOrCreateAccount.jsx';
|
||||
|
||||
import { startOrJoinGame } from '../start/actions.js'
|
||||
import { start } from '../app/actions.js'
|
||||
@@ -53,7 +54,6 @@ class NewGame extends React.Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
showSettings: false,
|
||||
playerName: '',
|
||||
checkedColor: props.colors[0],
|
||||
gameId: typeof props.gameId === 'undefined' ? -1 : props.gameId,
|
||||
gameName: props.gameName || '',
|
||||
@@ -63,7 +63,8 @@ class NewGame extends React.Component {
|
||||
auditThreshold: 250000,
|
||||
startingCash: 5000,
|
||||
startingDebt: 5000,
|
||||
trade: true
|
||||
trade: true,
|
||||
showLogin: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -96,8 +97,7 @@ class NewGame extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let playerNameInput,
|
||||
titleBar = !this.props.hideBack ? (
|
||||
let titleBar = !this.props.hideBack ? (
|
||||
<Fragment>
|
||||
<a onClick={this.handleBack}>
|
||||
<FontAwesomeIcon icon={faArrowCircleLeft} />
|
||||
@@ -129,97 +129,97 @@ class NewGame extends React.Component {
|
||||
mainScreenClass = !this.state.showSettings ? '' : 'hidden';
|
||||
return (
|
||||
<GroupBox title={titleBar}>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className={mainScreenClass}>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>Your Name
|
||||
<input type='text' name='playerName'
|
||||
required
|
||||
value={this.state.playerName}
|
||||
onChange={this.handleInputChange} />
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>Your Color</label>
|
||||
{colors}
|
||||
<br /><br />
|
||||
</Col>
|
||||
</Row>
|
||||
{gameName}
|
||||
</div>
|
||||
<div className={settingsClass}>
|
||||
<InputRow label='Down Payment'
|
||||
name='downPayment'
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
value={this.state.downPayment}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Loan Interest'
|
||||
name='loanInterest'
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
value={this.state.loanInterest}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Maximum Debt'
|
||||
name='maxDebt'
|
||||
min={0}
|
||||
step={5000}
|
||||
value={this.state.maxDebt}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Audit Threshold'
|
||||
name='auditThreshold'
|
||||
min={0}
|
||||
step={25000}
|
||||
value={this.state.auditThreshold}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Starting Cash'
|
||||
name='startingCash'
|
||||
min={0}
|
||||
step={1000}
|
||||
value={this.state.startingCash}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Starting Debt'
|
||||
name='startingDebt'
|
||||
min={0}
|
||||
step={1000}
|
||||
value={this.state.startingDebt}
|
||||
onChange={this.handleInputChange} />
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>
|
||||
<input type='checkbox'
|
||||
checked={this.state.trade}
|
||||
onChange={this.handleInputChange}
|
||||
name='trade' />
|
||||
Enable Trading
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<div className='new-game-submit-container'>
|
||||
<Button type='submit'>{this.props.button} Game</Button>
|
||||
{this.props.showGameName ? (
|
||||
<a onClick={this.toggleSettings}>
|
||||
<FontAwesomeIcon icon={faCog} size='lg' />
|
||||
</a>
|
||||
) : (<Fragment />)}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</form>
|
||||
{this.props.user ? (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className={mainScreenClass}>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>Your Color</label>
|
||||
{colors}
|
||||
<br /><br />
|
||||
</Col>
|
||||
</Row>
|
||||
{gameName}
|
||||
</div>
|
||||
<div className={settingsClass}>
|
||||
<InputRow label='Down Payment'
|
||||
name='downPayment'
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
value={this.state.downPayment}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Loan Interest'
|
||||
name='loanInterest'
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.1}
|
||||
value={this.state.loanInterest}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Maximum Debt'
|
||||
name='maxDebt'
|
||||
min={0}
|
||||
step={5000}
|
||||
value={this.state.maxDebt}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Audit Threshold'
|
||||
name='auditThreshold'
|
||||
min={0}
|
||||
step={25000}
|
||||
value={this.state.auditThreshold}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Starting Cash'
|
||||
name='startingCash'
|
||||
min={0}
|
||||
step={1000}
|
||||
value={this.state.startingCash}
|
||||
onChange={this.handleInputChange} />
|
||||
<InputRow label='Starting Debt'
|
||||
name='startingDebt'
|
||||
min={0}
|
||||
step={1000}
|
||||
value={this.state.startingDebt}
|
||||
onChange={this.handleInputChange} />
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<label>
|
||||
<input type='checkbox'
|
||||
checked={this.state.trade}
|
||||
onChange={this.handleInputChange}
|
||||
name='trade' />
|
||||
Enable Trading
|
||||
</label>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
<Row>
|
||||
<Col width='12'>
|
||||
<div className='new-game-submit-container'>
|
||||
<Button type='submit'>{this.props.button} Game</Button>
|
||||
{this.props.showGameName ? (
|
||||
<a onClick={this.toggleSettings}>
|
||||
<FontAwesomeIcon icon={faCog} size='lg' />
|
||||
</a>
|
||||
) : (<Fragment />)}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</form>
|
||||
) : (
|
||||
<>
|
||||
<span>Sign in or create account to continue</span>
|
||||
<LoginOrCreateAccount login={this.props.login}
|
||||
createAccount={this.props.createAccount}
|
||||
errors={this.props.errors}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</GroupBox>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
state => state.start.start,
|
||||
{ startOrJoinGame, start }
|
||||
)(NewGame)
|
||||
|
||||
@@ -17,4 +17,7 @@
|
||||
// <https://www.gnu.org/licenses/>.
|
||||
|
||||
export const SET_START_GAMES = 'set-start-games';
|
||||
export const SET_OPEN_GAMES = 'set-open-games';
|
||||
export const SET_USER = 'set-user';
|
||||
export const SET_ERRORS = 'set-errors';
|
||||
export const START_OR_JOIN_GAME = 'start-or-join-game';
|
||||
|
||||
@@ -16,16 +16,32 @@
|
||||
// along with the Alpha Centauri Farming project. If not, see
|
||||
// <https://www.gnu.org/licenses/>.
|
||||
|
||||
import { SET_START_GAMES, START_OR_JOIN_GAME } from './actionTypes.js'
|
||||
import { SET_START_GAMES, START_OR_JOIN_GAME, SET_USER, SET_OPEN_GAMES,
|
||||
SET_ERRORS } from './actionTypes.js'
|
||||
|
||||
export { setStartGames, startOrJoinGame }
|
||||
export { setStartGames, startOrJoinGame, setUser, setOpenGames, setErrors }
|
||||
|
||||
function setStartGames(games) {
|
||||
return { type: SET_START_GAMES,
|
||||
games };
|
||||
}
|
||||
|
||||
function setOpenGames(games) {
|
||||
return { type: SET_OPEN_GAMES,
|
||||
games };
|
||||
}
|
||||
|
||||
function setUser(user) {
|
||||
return { type: SET_USER,
|
||||
user };
|
||||
}
|
||||
|
||||
function startOrJoinGame(msg) {
|
||||
return { type: START_OR_JOIN_GAME,
|
||||
msg };
|
||||
}
|
||||
|
||||
function setErrors(errors) {
|
||||
return { type: SET_ERRORS,
|
||||
errors };
|
||||
}
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
// along with the Alpha Centauri Farming project. If not, see
|
||||
// <https://www.gnu.org/licenses/>.
|
||||
|
||||
import { SET_START_GAMES, START_OR_JOIN_GAME } from './actionTypes.js'
|
||||
import { SET_START_GAMES, START_OR_JOIN_GAME, SET_USER, SET_OPEN_GAMES,
|
||||
SET_ERRORS } from './actionTypes.js'
|
||||
import { SCREENS } from '../../constants.js'
|
||||
|
||||
const initialState = {
|
||||
start: { games: [] },
|
||||
start: { games: [],
|
||||
openGames: [],
|
||||
errors: [],
|
||||
user: false },
|
||||
msg: null
|
||||
};
|
||||
|
||||
@@ -28,6 +32,12 @@ export default function(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case SET_START_GAMES:
|
||||
return { ...state, start: { ...state.start, games: action.games }};
|
||||
case SET_OPEN_GAMES:
|
||||
return { ...state, start: { ...state.start, openGames: action.games }};
|
||||
case SET_USER:
|
||||
return { ...state, start: { ...state.start, user: action.user }};
|
||||
case SET_ERRORS:
|
||||
return { ...state, start: { ...state.start, errors: action.errors }};
|
||||
case START_OR_JOIN_GAME:
|
||||
return { ...state, msg: action.msg };
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user