Commit 5e21f21c authored by Matthew Odle's avatar Matthew Odle

add leaderboard submit modal

it works, but the input focus does not, so each character typed causes the input to lose focus
parent 23f7cfc7
......@@ -751,9 +751,9 @@
"integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q=="
},
"binary-extensions": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz",
"integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA="
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz",
"integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU="
},
"bluebird": {
"version": "3.5.1",
......@@ -850,9 +850,9 @@
"integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg="
},
"browserify-zlib": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
"integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0="
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
"integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA=="
},
"browserslist": {
"version": "2.9.0",
......@@ -949,14 +949,14 @@
}
},
"caniuse-db": {
"version": "1.0.30000760",
"resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000760.tgz",
"integrity": "sha1-PqKUc+t4psywny63Osnh3r/sUo0="
"version": "1.0.30000766",
"resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000766.tgz",
"integrity": "sha1-TJEao3R/ATiEUvpLknt4/PFDBoA="
},
"caniuse-lite": {
"version": "1.0.30000760",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000760.tgz",
"integrity": "sha1-7HIDlXQvHH7IlH/W3SYE53qPmP8="
"version": "1.0.30000766",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000766.tgz",
"integrity": "sha1-iglcxeuZI8JwCM5NDbI+ZaPiiEM="
},
"capture-stack-trace": {
"version": "1.0.0",
......@@ -983,15 +983,20 @@
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
"integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q=="
},
"chardet": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.0.tgz",
"integrity": "sha1-C74TVaxE16PtSpJXB8TvcPgZD2w="
},
"chokidar": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
"integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg="
},
"ci-info": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.1.tgz",
"integrity": "sha512-vHDDF/bP9RYpTWtUhpJRhCFdvvp3iDWvEbuDbWgvjUrNGV1MXJrE0MPcwGtEled04m61iwdBLUIHZtDgzWS4ZQ=="
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.2.tgz",
"integrity": "sha512-uTGIPNx/nSpBdsF6xnseRXLLtfr9VLqkz8ZqHXr3Y7b6SftyRxBGjwMtJj1OhNbmlc1wZzLNAlAcvyIiE8a6ZA=="
},
"cipher-base": {
"version": "1.0.4",
......@@ -2062,9 +2067,9 @@
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
},
"external-editor": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.5.tgz",
"integrity": "sha512-Msjo64WT5W+NhOpQXh0nOHm+n0RfU1QUwDnKYvJ8dEJ8zlwLrqXNTv5mSUTJpepf41PDJGyhueTw2vNZW+Fr/w=="
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz",
"integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA=="
},
"extglob": {
"version": "0.3.2",
......@@ -3156,9 +3161,9 @@
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE="
},
"https-browserify": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz",
"integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI="
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
},
"iconv-lite": {
"version": "0.4.19",
......@@ -3960,11 +3965,6 @@
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"optional": true
},
"jschardet": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.6.0.tgz",
"integrity": "sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ=="
},
"jsdom": {
"version": "9.12.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz",
......@@ -4242,9 +4242,9 @@
"integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M="
},
"loglevel": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.5.1.tgz",
"integrity": "sha1-GJB4yUq5BT7iFaCs2/JCROoPZQI="
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.0.tgz",
"integrity": "sha1-rgyqVhERSYxboTcj1vtjHSQAOTQ="
},
"longest": {
"version": "1.0.1",
......@@ -4431,9 +4431,9 @@
"integrity": "sha1-pBizN6FKFJkPtRC5I97mqBMXPfg="
},
"mongoose": {
"version": "4.13.2",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-4.13.2.tgz",
"integrity": "sha512-IG8BbR35d6tX565rWgdz76LrXhQ4A9QjVnmcLVWUez1xK1/jPNstMegOx9WTh0Vwon50lpvO9KdnDbkcZCARBw=="
"version": "4.13.4",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-4.13.4.tgz",
"integrity": "sha512-MYS9qWVmWz0PJ1tewtGisKT3/61ctcgX05w9epcy2WQ+1IH4HIPFO5hToR4u+ro7fyBWpSsTlUPMBJblzRLCzQ=="
},
"mpath": {
"version": "0.3.0",
......@@ -4488,9 +4488,9 @@
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
},
"nan": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
"integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz",
"integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=",
"optional": true
},
"natural-compare": {
......@@ -4534,14 +4534,14 @@
"integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs="
},
"node-libs-browser": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.0.0.tgz",
"integrity": "sha1-o6WeyXAkmFtG6Vg3lkb5bEthZkY=",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz",
"integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==",
"dependencies": {
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
"readable-stream": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ=="
}
}
},
......@@ -4712,9 +4712,9 @@
}
},
"os-browserify": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz",
"integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8="
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
"integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="
},
"os-homedir": {
"version": "1.0.2",
......@@ -4762,9 +4762,9 @@
"integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0="
},
"pako": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
"integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU="
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
"integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg=="
},
"param-case": {
"version": "2.1.1",
......@@ -8559,9 +8559,9 @@
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
},
"worker-farm": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.5.1.tgz",
"integrity": "sha512-T5NH6Wqsd8MwGD4AK8BBllUy6LmHaqjEOyo/YIUEegZui6/v5Bqde//3jwyE3PGiGYMmWi06exFBi5LNhhPFNw=="
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.5.2.tgz",
"integrity": "sha512-XxiQ9kZN5n6mmnW+mFJ+wXjNNI/Nx4DIdaAKLX1Bn6LYBWlN/zaBhu34DQYPZ1AJobQuu67S2OfDdNSVULvXkQ=="
},
"wrap-ansi": {
"version": "2.1.0",
......
......@@ -16,7 +16,6 @@
"classnames": "^2.2.5"
},
"scripts": {
"start": "react-scripts start",
"start-dev": "nf start -p 3000"
"start": "react-scripts start"
}
}
......@@ -20,7 +20,7 @@ const knobsAndLevers = {
warmthReplenishThreshold: 10,
warmthPerFirewood: 80,
baseEnergyDegradeRate: 1,
baseEnergyDegradeRate: 100,
assignmentEnergyMultiplier: 2,
energyReplenishThreshold: 10,
energyPerFood: 80,
......@@ -29,10 +29,14 @@ const knobsAndLevers = {
defaultCapacity: 20,
defaultProductionRate: 1,
defaultToolStores: 25,
defaultFirewoodStores: 50,
defaultFoodStores: 50,
defaultClothingStores: 25,
defaultToolStores: 0,
defaultFirewoodStores: 0,
defaultFoodStores: 0,
defaultClothingStores: 0,
// defaultToolStores: 25,
// defaultFirewoodStores: 50,
// defaultFoodStores: 50,
// defaultClothingStores: 25,
defaultHideStores: 0,
defaultIronStores: 0,
......
const leaderboardIndexUrl = "https://resource-quest-leaderboard.herokuapp.com";
export default leaderboardIndexUrl;
import React, { Component } from 'react';
import axios from 'axios';
import LeaderboardList from './leaderboard-list';
import LeaderboardForm from './leaderboard-form';
import style from './style';
class LeaderboardBox extends Component {
constructor(props) {
super(props);
this.state = { data: [] };
this.loadLeaderboardsFromServer = this.loadLeaderboardsFromServer.bind(this);
this.handleLeaderboardSubmit = this.handleLeaderboardSubmit.bind(this);
}
loadLeaderboardsFromServer() {
axios.get(this.props.url)
.then(res => {
this.setState({ data: res.data });
})
}
handleLeaderboardSubmit(leaderboard) {
leaderboard.score = this.props.score;
console.log(leaderboard);
let leaderboards = this.state.data;
leaderboard.id = Date.now();
let newLeaderboards = leaderboards.concat([leaderboard]);
this.setState({ data: newLeaderboards });
axios.post(this.props.url, leaderboard)
.catch(err => {
console.error(err);
this.setState({ data: leaderboards });
});
}
componentDidMount() {
this.loadLeaderboardsFromServer();
setInterval(this.loadLeaderboardsFromServer, this.props.pollInterval);
}
render() {
return (
<div style={ style.leaderboardBox }>
<h2>Leaderboards:</h2>
<LeaderboardList data={ this.state.data }/>
<LeaderboardForm onLeaderboardSubmit={ this.handleLeaderboardSubmit }/>
</div>
)
}
}
export default LeaderboardBox;
import React, { Component } from 'react';
import style from './style';
class LeaderboardForm extends Component {
constructor(props) {
super(props);
this.state = { name: '', score: this.props.score };
this.handleNameChange = this.handleNameChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
import React from 'react';
handleNameChange(e) {
this.setState({ name: e.target.value });
}
import style from './style';
handleSubmit(e) {
e.preventDefault();
let name = this.state.name.trim();
if (!name) {
return;
}
this.props.onLeaderboardSubmit({ name: name });
this.setState({ name: '' });
export class LeaderboardForm extends React.Component {
componentDidUpdate = () => {
this.refs.field_name.focus();
console.log(this.nameInput);
}
// ref={input => input && input.focus()}
render() {
return (
<form style={ style.leaderboardForm } onSubmit={ this.handleSubmit }>
render = () => {
return <div>
<div style={ style.title }>Submit your name to the leaderboard!</div>
<div style={ style.regularText }>Nobody left to stack the corpses... Surely you could do better.</div>
<div style={ style.regularText }>Your score: { this.props.score }</div>
<form style={ style.leaderboardForm } onSubmit={ this.props.handleSubmit }>
<input
type='text'
placeholder='Your name...'
style={ style.leaderboardFormName}
value={ this.state.name }
onChange={ this.handleNameChange } />
style={ style.leaderboardFormName }
value={ this.props.name }
onChange={ this.props.handleNameChange }
ref='field_name'
autoFocus />
<input
type='submit'
style={ style.leaderboardFormPost }
style={ style.leaderboardFormButton }
value='Post' />
<button type="button" style={ style.leaderboardFormButton } onClick={() => this.props.hideModal()} >Cancel</button>
</form>
)
</div>
}
}
export default LeaderboardForm;
import React, { Component } from 'react';
import Leaderboard from './leaderboard';
import style from './style';
class LeaderboardList extends Component {
sortLeaderboard = (leaderboard) => {
leaderboard.sort((a, b) => a.score < b.score);
}
render() {
const leaderboardData = this.props.data.slice();
this.sortLeaderboard(leaderboardData);
let leaderboardNodes = leaderboardData.map(leaderboard => {
return (
<Leaderboard name={ leaderboard.name } key={ leaderboard['_id'] }>
{ leaderboard.score}
</Leaderboard>
)
});
this.sortLeaderboard(leaderboardNodes);
return (
<div style={ style.leaderboardList }>
{ leaderboardNodes }
</div>
)
}
}
export default LeaderboardList;
import React, { Component } from 'react';
import style from './style';
import marked from 'marked';
class Comment extends Component {
rawMarkup() {
let rawMarkup = marked(this.props.children.toString());
return { __html: rawMarkup };
}
render() {
return (
<div style={ style.leaderboard }>
<h3>{this.props.name}</h3>
<span dangerouslySetInnerHTML={ this.rawMarkup() } />
</div>
)
}
}
export default Comment;
import React from 'react';
import LEADERBOARD_URL from './defaults/leaderboard-url';
export class LinksContainer extends React.Component {
render(props) {
return <div className="linksContainer">
<a href={LEADERBOARD_URL} target="_blank">leaderboard</a>
</div>
}
}
const style = {
leaderboardBox: {
width:'80vw',
margin:'0 auto',
fontFamily:'Helvetica, sans-serif',
display: 'inline'
},
title: {
textAlign:'center',
textTransform:'uppercase'
},
leaderboardList: {
border:'1px solid #f1f1f1',
padding:'0 12px',
maxHeight:'70vh',
overflow:'scroll'
},
leaderboard: {
backgroundColor:'#fafafa',
margin:'10px',
padding:'3px 10px',
fontSize:'.85rem'
fontWeight:'bold',
fontSize:'22px'
},
leaderboardForm: {
margin:'10px',
display:'flex',
flexFlow:'row wrap',
justifyContent:'space-between'
justifyContent:'spacebetween'
},
leaderboardFormAuthor: {
leaderboardFormName: {
minWidth:'150px',
margin:'3px',
padding:'0 10px',
......@@ -35,15 +18,7 @@ const style = {
height:'40px',
flex:'2'
},
leaderboardFormText: {
flex:'4',
minWidth:'400px',
margin:'3px',
padding:'0 10px',
height:'40px',
borderRadius:'3px'
},
leaderboardFormPost: {
leaderboardFormButton: {
minWidth:'75px',
flex:'1',
height:'40px',
......@@ -55,6 +30,10 @@ const style = {
textTransform:'uppercase',
letterSpacing:'.055rem',
border:'none'
},
regularText: {
textAlign:'center',
fontSize:'15px',
}
}
......
/* eslint react/prop-types: 0 */
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import style from './style';
export class SubmitScoreDialog extends React.Component {
constructor(props) {
super(props);
this.screenBlockDiv = document.createElement('div');
this.screenBlockDiv.classList.add('screen-block');
this.modalDiv = document.createElement('div');
this.modalDiv.classList.add('modal-dialog');
}
displayModal = () => {
if (this.props.showModal) {
document.body.appendChild(this.screenBlockDiv);
document.body.appendChild(this.modalDiv);
} else {
this.screenBlockDiv.remove();
this.modalDiv.remove();
}
}
componentWillMount() {
this.displayModal();
}
componentDidUpdate() {
this.displayModal();
}
componentWillUnmount() {
this.screenBlockDiv.remove();
this.screenBlockDiv = null;
this.modalDiv.remove();
this.modalDiv = null;
}
render() {
return ReactDOM.createPortal(this.props.children, this.modalDiv);
}
}
import React from 'react';
import axios from 'axios';
import { Log } from './log';
import { VillageManagement } from './village-management';
import { Score } from './score';
import LeaderboardBox from './leaderboard-box';
import { SubmitScoreDialog } from './submit-score-dialog';
import { LeaderboardForm } from './leaderboard-form';
import THE_BUILDINGS from './defaults/generate-buildings';
import THE_VILLAGERS from './defaults/generate-villagers';
import KNOBS_AND_LEVERS from './defaults/knobs-and-levers';
import VILLAGE_STORE from './defaults/village-store';
import VILLAGER_STATUS from './defaults/villager-status';
import LEADERBOARD_URL from './defaults/leaderboard-url';
export class Village extends React.Component {
......@@ -21,9 +26,40 @@ export class Village extends React.Component {
villagers: THE_VILLAGERS.slice(),
log: [],
villagerStatus: VILLAGER_STATUS,
showModal: false,
name: '',
};
this.handleNameChange = this.handleNameChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
showModal = () => {
this.setState({ showModal : true });
};
hideModal = (canDelete) => {
this.setState({ name : '', showModal: false });
};
handleNameChange = (e) => {
this.setState({ name: e.target.value });
}
handleLeaderboardSubmit = (leaderboard) => {
leaderboard.score = this.state.score;
axios.post(LEADERBOARD_URL + '/leaderboard', leaderboard)
.catch(err => {
console.error(err);
});
}
handleSubmit = (e) => {
e.preventDefault();
let name = this.state.name.trim();
if (!name) {
return;
}
this.handleLeaderboardSubmit({ name: name });
this.hideModal();
}
//----- state update functions -----//
......@@ -402,6 +438,7 @@ export class Village extends React.Component {
this.checkGameEndConditions();
if (this.state.gameOver) {
clearInterval(this.timer);
this.showModal();
}
this.setState({
score: this.state.score + 1,
......@@ -423,6 +460,12 @@ export class Village extends React.Component {
const villagerStatus = this.state.villagerStatus;
return (
<div className="village">
<SubmitScoreDialog key='saveme' showModal={this.state.showModal}>
<LeaderboardForm handleSubmit={this.handleSubmit} name={this.state.name}
handleNameChange={this.handleNameChange} hideModal={this.hideModal}
score={this.state.score}
/>
</SubmitScoreDialog>
<Score score={this.state.score} />
<VillageManagement
buildings={buildings} villageStore={villageStore}
......@@ -431,10 +474,6 @@ export class Village extends React.Component {
updateTheVillagers={this.updateTheVillagers}
/>
<Log log={this.state.log} score={this.state.score} />
<LeaderboardBox
url='http://localhost:3001/api/leaderboard'
pollInterval={2000}
score={this.state.score} />
</div>
)
}
......
......@@ -202,3 +202,27 @@ button {
top: 0px;
}
}
.modal-dialog {
position: absolute;
top:50%;
left:50%;
height: 300px;
width: 500px;
margin-top:-150px;
margin-left:-250px;
border: 2px solid black;
background: white;
z-index: 1000;
}
.screen-block {
position:fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: gray;
opacity: 0.8;
z-index: 900;
}
......@@ -5,11 +5,13 @@ import './index.css';
import { Village } from './components/village';
import { Rules } from './components/rules';
import { LinksContainer } from './components/links-container';
const Game = () => {
return <div className="game">
<Village start={Date.now()} />
<Rules />
<LinksContainer />
</div>
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment