Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save linuxenko/d47cacc6a17a6791ad73 to your computer and use it in GitHub Desktop.
Save linuxenko/d47cacc6a17a6791ad73 to your computer and use it in GitHub Desktop.
Build a Camper Leaderboard [freeCodeCamp [Data Visualization]] (Challenge)
class Members extends React.Component {
openLink(link) {
let win = window.open(link, '_blank');
win.focus();
}
render() {
let memberLink = 'http://www.freecodecamp.com/' + this.props.data.username;
let updated = moment(this.props.data.lastUpdate).format('DD-MM-YY');
return (
<tr onClick={this.openLink.bind(this, memberLink)}>
<td>
<img src={this.props.data.img} />
{this.props.data.username}</td>
<td>{this.props.data.recent}</td>
<td>{this.props.data.alltime}</td>
<td>{updated}</td>
</tr>
)
}
}
class OrderedLink extends React.Component {
render() {
let link = '#/' + this.props.data.state +'?order=' + this.props.field + ':';
let icon = '';
let name = this.props.field.charAt(0).toUpperCase() +
this.props.field.split('').splice(1, this.props.field.length).join('');
if (this.props.data.order.name === this.props.field) {
if (this.props.data.order.dir === 'asc') {
icon = 'fa fa-caret-up';
link += 'desc';
} else {
icon = 'fa fa-caret-down';
link += 'asc';
}
} else {
link += 'desc';
}
return (
<a className="" href={link}>
{name} &nbsp;
<i className={icon}></i>
</a>
)
}
}
class Dashboard extends React.Component {
constructor() {
super();
this.dataURI = {
alltime : 'http://fcctop100.herokuapp.com/api/fccusers/top/alltime',
recent : 'http://fcctop100.herokuapp.com/api/fccusers/top/recent'
};
this.state = {
DATA : {state : null, data : null, order : null}
};
}
fetchData(hash) {
let name = hash.replace(/^\#\/(\w+)\??.*?$/, '$1');
let o = hash.match(/order/) ?
hash.replace(/^.*order\=(.+)$/g, '$1') :
'username:desc';
name = name.length < 1 ? 'recent' : name;
let data = this.state.DATA.data;
let order = {
name : o.split(':')[0],
dir : o.split(':')[1]
};
let orderify = function(a,b) {
let x = a[order.name];
let y = b[order.name];
if (order.name === 'username') {
x = x.toLowerCase().charCodeAt(0);
y = y.toLowerCase().charCodeAt(0);
}
if (order.name === 'lastUpdate') {
x = new Date(x).getTime();
y = new Date(y).getTime();
}
return order.dir === 'desc' ? x - y : y - x;
};
if (name !== this.state.DATA.state) {
// Displaying progress at the boot time
this.setState({DATA : { data : null }});
fetch(this.dataURI[name])
.then(response => response.json())
.then(json => {
this.setState({DATA : {
data : json.sort(orderify),
state : name,
order : order
}});
});
} else {
this.setState({DATA : {
data : this.state.DATA.data.sort(orderify),
state : name,
order : order
}});
}
}
componentDidMount() {
window.addEventListener('hashchange', () => {
this.fetchData(window.location.hash);
});
this.fetchData(window.location.hash);
}
render() {
return (
<div className="container">
<div clasName="header">
<h2>Leaderboard
{ this.state.DATA.state === 'alltime' ?
<span>
<small className="label label-info">All Time</small>
<a className="btn pull-right" href="#/recent?order=username:desc">Show Recent <i className="fa fa-clock-o"></i></a>
</span>
:
<span>
<small className="label label-info">Recent</small>
<a className="btn pull-right" href="#/alltime?order=username:desc">Show All Time <i className="fa fa-clock-o"></i>
</a></span>
}
</h2>
</div>
{ this.state.DATA.data ?
<table className="table table-hover">
<thead>
<tr>
<th><OrderedLink data={this.state.DATA} field="username"/></th>
<th><OrderedLink data={this.state.DATA} field="recent"/></th>
<th><OrderedLink data={this.state.DATA} field="alltime"/></th>
<th><OrderedLink data={this.state.DATA} field="lastUpdate"/></th>
</tr>
</thead>
<tbody>
{ this.state.DATA.data.map((d, i) => {
return <Members data={d} key={i} />
})
}
</tbody>
</table>
: <h4 className="text-center">Loading...</h4> }
<br />
<h6 className="text-center">
<a href="http://www.linuxenko.pro">&copy; Svetlana Linuxenko</a>
</h6>
</div>
)
}
}
React.render(<Dashboard />, document.body);
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.12.0/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fetch/0.11.0/fetch.min.js"></script>
$links-color : #441122
body
background-image: linear-gradient(transparent, #eee, transparent)
background-size: 4px 5px
.container
max-width: 500px
font-family: sans
padding: 0px
margin: 20px auto
background: #fff
box-shadow: 0px 1px 10px #444
h2
text-transform: uppercase
padding: 10px 20px
color: #444
text-shadow: 0px 0px 1px #999
.label
font-size: 12px
position: relative
top: -20px
left: 4px
.btn
position: relative
top: -14px
font-size: 14px
color: $links-color
.table
margin: 0px
max-width: 500px
font-family: 'Roboto', sans-serif
th
white-space: nowrap
text-align: center
a
color: $links-color
text-transform: uppercase
font-weight: normal
a:hover,a:focus
text-decoration: none
i
display: inline-block
width: 20px
tr
cursor: pointer
td
white-space: nowrap
text-align: center
td:first-child
text-align: left
img
width: 30px
margin: 0px 10px 0px 0px
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment