...
 
Commits (2)
DATABASE_URL=mongodb://rq-leaderboard-user:31nRYPYllppXPQIx58Uz@ds147421.mlab.com:47421/resource-quest-leaderboard
web: react-scripts start
api: nodemon server.js
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var LeaderboardSchema = new Schema({
name: String,
score: Number
});
//export our module to use in server.js
module.exports = mongoose.model('Leaderboard', LeaderboardSchema);
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -2,12 +2,21 @@
"name": "resource-quest",
"version": "0.1.0",
"dependencies": {
"classnames": "^2.2.5",
"axios": "^0.17.1",
"body-parser": "^1.18.2",
"express": "^4.16.2",
"foreman": "^2.0.0",
"marked": "^0.3.6",
"mongoose": "^4.13.1",
"node-env-file": "^0.1.8",
"nodemon": "^1.12.1",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-scripts": "1.0.13"
"react-scripts": "1.0.13",
"classnames": "^2.2.5"
},
"scripts": {
"start": "react-scripts start"
"start": "react-scripts start",
"start-dev": "nf start -p 3000"
}
}
......@@ -12,7 +12,6 @@
</noscript>
<div class="top">
<div id="root"></div>
<div id="rules"></div>
</div>
</body>
</html>
'use strict'
// first we import our dependencies…
var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var Leaderboard = require('./model/leaderboard-schema');
var env = require('node-env-file');
env(__dirname + '/.env');
var app = express();
var router = express.Router();
var port = process.env.API_PORT || 3001;
mongoose.connect(process.env.DATABASE_URL, {'useMongoClient': true, });
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// To prevent errors from Cross Origin Resource Sharing,
// set headers to allow CORS with middleware:
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,OPTIONS,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
// remove cacheing to get most recent entries
res.setHeader('Cache-Control', 'no-cache');
next();
});
// set root route
router.get('/', function(req, res) {
res.json({ message: 'API Initialized!'});
});
router.route('/leaderboard')
.get(function(req, res) {
Leaderboard.find(function(err, entries) {
if (err) {
res.send(err);
}
res.json(entries)
});
})
.post(function(req, res) {
var leaderboard = new Leaderboard();
leaderboard.name = req.body.name;
leaderboard.score = req.body.score;
leaderboard.save(function(err) {
if (err) {
res.send(err);
}
res.json({ message: 'Leaderboard successfully added!' });
});
});
app.use('/api', router);
app.listen(port, function() {
console.log('api running on port ' + port);
});
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);
}
handleNameChange(e) {
this.setState({ name: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
let name = this.state.name.trim();
if (!name) {
return;
}
this.props.onLeaderboardSubmit({ name: name });
this.setState({ name: '' });
}
render() {
return (
<form style={ style.leaderboardForm } onSubmit={ this.handleSubmit }>
<input
type='text'
placeholder='Your name...'
style={ style.leaderboardFormName}
value={ this.state.name }
onChange={ this.handleNameChange } />
<input
type='submit'
style={ style.leaderboardFormPost }
value='Post' />
</form>
)
}
}
export default LeaderboardForm;
import React, { Component } from 'react';
import Leaderboard from './leaderboard';
import style from './style';
class LeaderboardList extends Component {
render() {
let leaderboardNodes = this.props.data.map(leaderboard => {
return (
<Leaderboard name={ leaderboard.name } key={ leaderboard['_id'] }>
{ leaderboard.score}
</Leaderboard>
)
})
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;
......@@ -7,7 +7,7 @@ export class Log extends React.Component {
render = () => {
return <div className="info">
<div className="log">
{ this.props.log.map( logEntry => <Message message={logEntry} /> ) }
{ this.props.log.map( logEntry => <Message message={logEntry} key={Math.random(Date.now())} /> ) }
</div>
</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'
},
leaderboardForm: {
margin:'10px',
display:'flex',
flexFlow:'row wrap',
justifyContent:'space-between'
},
leaderboardFormAuthor: {
minWidth:'150px',
margin:'3px',
padding:'0 10px',
borderRadius:'3px',
height:'40px',
flex:'2'
},
leaderboardFormText: {
flex:'4',
minWidth:'400px',
margin:'3px',
padding:'0 10px',
height:'40px',
borderRadius:'3px'
},
leaderboardFormPost: {
minWidth:'75px',
flex:'1',
height:'40px',
margin:'5px 3px',
fontSize:'1rem',
backgroundColor:'#A3CDFD',
borderRadius:'3px',
color:'#fff',
textTransform:'uppercase',
letterSpacing:'.055rem',
border:'none'
}
}
module.exports = style;
......@@ -3,6 +3,7 @@ import React from 'react';
import { Log } from './log';
import { VillageManagement } from './village-management';
import { Score } from './score';
import LeaderboardBox from './leaderboard-box';
export class Village extends React.Component {
......@@ -54,6 +55,12 @@ export class Village extends React.Component {
});
}
updateAllVillagers = (villagers) => {
this.setState({
villagers: villagers,
});
}
updateTheVillageStore = (villageStore) => {
this.setState({
villageStore: villageStore,
......@@ -69,6 +76,12 @@ export class Village extends React.Component {
});
}
setVillagerStatus = (villagerStatus) => {
this.setState({
villagerStatus: villagerStatus,
});
}
//----- cycle management functions -----//
......@@ -291,7 +304,11 @@ export class Village extends React.Component {
villager.assignment !== 'IDLE' ? this.removeVillager(villager) : null;
villager.assignment = 'DEAD';
this.updateLog('a villager has ' + reason + ' to death');
this.state.villagerStatus.dead.count += 1;
let villagerStatus = this.state.villagerStatus;
villagerStatus.dead.count += 1;
this.setState({
villagerStatus: villagerStatus,
});
}
bringOutYourDead = (villager) => {
......@@ -308,12 +325,6 @@ export class Village extends React.Component {
}
}
updateAllVillagers = (villagers) => {
this.setState({
villagers: villagers,
});
}
manageVillagerConditions = () => {
const villagers = this.state.villagers.slice();
villagers.map( villager => {
......@@ -329,7 +340,9 @@ export class Village extends React.Component {
}
setBadThingClass = (thing) => {
this.state.villagerStatus[thing].classNames.badThingHappened = true;
let villagerStatus = this.state.villagerStatus;
villagerStatus[thing].classNames.badThingHappened = true;
this.setVillagerStatus(villagerStatus);
}
captureGameStatusInfo = () => {
......@@ -362,10 +375,12 @@ export class Village extends React.Component {
}
resetStatusClassNames = () => {
let villagerStatus = this.state.villagerStatus;
Array.from(Object.keys(this.state.villagerStatus)).map( key => {
this.state.villagerStatus[key].classNames.goodThingHappened = false;
this.state.villagerStatus[key].classNames.badThingHappened = false;
villagerStatus[key].classNames.goodThingHappened = false;
villagerStatus[key].classNames.badThingHappened = false;
});
this.setVillagerStatus(villagerStatus);
}
resetStoreClassNames = () => {
......@@ -379,7 +394,6 @@ export class Village extends React.Component {
const villagerStatus = this.state.villagerStatus;
Array.from(Object.keys(villagerStatus)).map(status => {
villagerStatus[status].count > 0 ? this.updateLog(villagerStatus[status].count + ' villagers are ' + status) : null;
console.log(status);
});
}
......@@ -427,6 +441,10 @@ 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>
)
}
......