Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
scrodde committed Mar 8, 2017
0 parents commit cd9cff1
Show file tree
Hide file tree
Showing 13 changed files with 5,288 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
~
.DS_Store
config/database.yml
config/secrets.yml
node_modules/
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: node index.js
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Tech stack


# Commands

## Data layer
* yarn sequelize
105 changes: 105 additions & 0 deletions app/components/App/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import _ from 'lodash';

import styles from './styles.scss';

const divisionTitles = {
1: 'Individual men',
2: 'Individual women',
9: 'Masters men (60+)',
12: 'Masters men (40-44)',
13: 'Masters women (40-44)',
18: 'Masters men (35-39)',
};

class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true
};
}

componentWillMount() {
const { apiBaseUrl, affiliate } = this.props;
axios.get(`${apiBaseUrl}/affiliate/${affiliate}`)
.then((response) => {
const athletes = _.get(response, 'data.athletes');
const athletesByDivision = _.groupBy(athletes, 'divisionid');
console.log(athletesByDivision);
this.setState({
isLoading: false,
athletesByDivision: athletesByDivision,
});
})
.catch((error) => {
this.setState({
isError: true
});
});
}

openAthleteDetails(id) {
window.open(`https://games.crossfit.com/athlete/${id}`);
}

render() {
const { athletesByDivision } = this.state;
const linkToWod = (name) => `https://games.crossfit.com/workouts/open/2017/${name}?division=2`;
const linkToAthlete = (name) => `https://games.crossfit.com/workouts/open/2017/${name}?division=2`;

const lists = _.map(athletesByDivision, (group, ix) => {
const groupTitle = divisionTitles[ix];
const items = _.map(group, (athlete, ix) => {
const rankInGroup = ix + 1;
return (
<tr key={ix} onClick={this.openAthleteDetails.bind(this, athlete.userid)}>
<td className="col1 center bold bigger">{rankInGroup}</td>
<td className="col2"><img src={_.get(athlete, 'profilepic')} className="avatar hide-mobile"/><span>{athlete.name}</span></td>
<td className="col3 center">{athlete.overallscore}</td>
<td className="col4">{`${_.get(athlete, 'scores[0].workoutrank')}(${_.get(athlete, 'scores[0].scoredisplay')})`}</td>
<td className="col5">{`${_.get(athlete, 'scores[1].workoutrank')}(${_.get(athlete, 'scores[1].scoredisplay')})`}</td>
<td className="col6">{`${_.get(athlete, 'scores[2].workoutrank')}(${_.get(athlete, 'scores[2].scoredisplay')})`}</td>
<td className="col7">{`${_.get(athlete, 'scores[3].workoutrank')}(${_.get(athlete, 'scores[3].scoredisplay')})`}</td>
<td className="col8">{`${_.get(athlete, 'scores[4].workoutrank')}(${_.get(athlete, 'scores[4].scoredisplay')})`}</td>
</tr>
)
});
return (
<div key={ix} className="division">
<div className="division__heading">
<h2>{groupTitle}</h2>
</div>
<table >
<thead><tr>
<th className="col1">Pos</th>
<th className="col2">Name</th>
<th className="col3">TTL PTS</th>
<th className="col4"><a href={linkToWod('17.1')} target="_blank">17.1</a></th>
<th className="col5"><a href={linkToWod('17.2')} target="_blank">17.2</a></th>
<th className="col6"><a href={linkToWod('17.3')} target="_blank">17.3</a></th>
<th className="col7"><a href={linkToWod('17.4')} target="_blank">17.4</a></th>
<th className="col8"><a href={linkToWod('17.5')} target="_blank">17.5</a></th>
</tr></thead>
<tbody>{items}</tbody>
</table>
</div>
);
});

return (
<div>
<header>
<h1>Open 2017<span>Crossfit Lauttasaari</span></h1>
</header>
<section>
{lists}
</section>
</div>
);
}
}

export default App;
174 changes: 174 additions & 0 deletions app/components/App/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
$red: #dc1d25;

* {
box-sizing: border-box;
font-smoothing: antialiased;
}

body {
font-family: 'Ubuntu', sans-serif;
background-color: black;
color: #fff;
font-size: 100%;
}

h1, h2 {
font-family: 'Raleway', sans-serif;
}

/**
* UTILITIES
*/
.center {
text-align: center;
}

.bold {
font-weight: 700;
}

.bigger {
font-size: 1.2em;
}

#container {
max-width: 1150px;
margin: 0 auto;
}

h1 {
font-size: 7em;
line-height: 0.8em;
text-transform: uppercase;
letter-spacing: 0.1em;
font-weight: 900;

span {
position: relative;
top: -0.5em;
display: block;
letter-spacing: 0.1em;
font-size: 0.2em;
}
}

header .logo {
overflow: hidden;
border-radius: 50%;
max-width: 150px;

img {
width: 100%;
height: auto;
}
}

.division__heading {
h2 {
position: relative;
left: 1px;
bottom: -1px;
font-size: 1em;
font-weight: normal;
letter-spacing: 0.1em;
font-family: 'Ubuntu', sans-serif;
text-transform: uppercase;
display: inline-block;
padding: 1em 2em;
margin: 0;
border: 3px solid $red;
border-bottom: 0 none;
}
}

.division {
margin-bottom: 5em;
width: 100%;
overflow: hidden;
}

table, th, td {
border-collapse: collapse;
border: 1px solid #101016;
}

table {
width: 100%;
border-top: 0 none;
thead {
background-color: $red;
}
th {
text-align: center;
text-transform: uppercase;
padding: 1em;

a, a:visited {
font-weight: normal;
text-decoration: none;
color: white;
border-bottom: 1px solid white;
}
}
tr {
cursor: pointer;

&:nth-child(even) {
background-color: #101016;
}
}
tbody tr:hover {
background-color: rgb(23, 23, 31);
}
td {
text-transform: uppercase;
padding: 0.5em;

img {
display: inline-block;
vertical-align: middle;
border-radius: 50%;
border: 2px solid red;
max-height: 50px;
width: auto;
margin-right: 1em;
}
}
}

@mixin hideColumn {
display:none;
width:0;
height:0;
opacity:0;
visibility: collapse;
}

@media only screen and (max-width: 800px) {
body {
font-size: 10px;
}
// .hide-mobile {
// display: none;
// visibility: hidden;
// width: 0; height: 0;
// }
.col4, .col5, .col6, .col7, .col8 {
// @include hideColumn();
}
}


@media only screen and (max-width: 400px) {
body {
font-size: 10px;
}
.hide-mobile {
display: none;
visibility: hidden;
width: 0; height: 0;
}
.col4, .col5, .col6, .col7, .col8 {
@include hideColumn();
}
}
14 changes: 14 additions & 0 deletions app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, maximum-scale=1.0" />
<link rel="icon" type="image/png" sizes="16x16" href="/assets/images/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon-32x32.png">
<link rel="shortcut icon" type="image/ico" href="/assets/images/favicon.ico">
<link href="https://fonts.googleapis.com/css?family=Raleway:400,500,600,900|Ubuntu:400,700"" rel="stylesheet">
</head>
<body>
<script type="text/javascript" src="/assets/js/app.js"></script>
<div id="container"></div>
</body>
</html>
8 changes: 8 additions & 0 deletions app/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import "babel-polyfill";
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';

document.addEventListener("DOMContentLoaded", () => {
ReactDOM.render(<App apiBaseUrl="http://scrodde-mbp.local:8000/api" affiliate="7508" />, document.getElementById('container'));
});
74 changes: 74 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
const _ = require('lodash');
const fs = require('fs');
const Hapi = require('hapi');
const parseArgs = require('minimist');
const path = require('path');
const yaml = require('js-yaml');
const rp = require('request-promise');
const cors = require('hapi-cors-headers');

/**
* Configuration
*/
const argv = parseArgs(process.argv.slice(2));
const port = process.env.PORT || 8000;
const host = process.env.HOST || '0.0.0.0';
const env = process.env.NODE_ENV || 'development';

const server = new Hapi.Server();
server.connection({
host: host,
port: port,
});

/**
* EXTENSIONS
*/
server.ext('onPreResponse', cors);


/**
* Routes
*/
server.route({
method: 'GET',
path: '/api/affiliate/{id}',
handler: function (request, reply) {
rp(`https://games.crossfit.com/competitions/api/v1/competitions/open/2017/leaderboards?affiliate=${request.params.id}&page=1`)
.then((body) => {
json = JSON.parse(body);
reply(json);
})
.catch((err) => {
throw err;
});
}
});

server.register(require('vision'), (err) => {
if (err) { throw err; }

server.views({
engines: {
html: require('handlebars')
},
relativeTo: __dirname,
path: 'templates'
});

server.route({
method: 'GET',
path: '/',
handler: (request, reply) => {
reply.view('index');
}
});
});

/**
* Startup
*/
server.start((err) => {
if (err) { throw err };
console.log(`Server running at: ${server.info.uri}`);
});
Loading

0 comments on commit cd9cff1

Please sign in to comment.