Merge pull request #7921 from FreeCodeCamp/feature/add-stats

Feature add stats to about page
This commit is contained in:
Quincy Larson
2016-04-05 23:51:29 -07:00
3 changed files with 77 additions and 17 deletions

View File

@ -1,32 +1,59 @@
import { Observable } from 'rx';
import dedent from 'dedent'; import dedent from 'dedent';
import moment from 'moment'; import moment from 'moment';
import { observeMethod } from '../utils/rx'; import { timeCache, observeMethod } from '../utils/rx';
function numberWithCommas(x) { function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
} }
// userCount(where: Object) => Observable[Number]
// getCertCount(userCount: userCount, cert: String) => Observable[Number]
function getCertCount(userCount, cert) {
return userCount({ [cert]: true })
// using This-Bind operator
::timeCache(2, 'hours');
}
export default function about(app) { export default function about(app) {
const router = app.loopback.Router(); const router = app.loopback.Router();
const User = app.models.User; const User = app.models.User;
const userCount$ = observeMethod(User, 'count'); const userCount = observeMethod(User, 'count');
const frontEndCount$ = getCertCount(userCount, 'isFrontEndCert');
const dataVisCount$ = getCertCount(userCount, 'isDataVisCert');
const backEndCount$ = getCertCount(userCount, 'isBackEndCert');
function showAbout(req, res, next) { function showAbout(req, res, next) {
const daysRunning = moment().diff(new Date('10/15/2014'), 'days'); const daysRunning = moment().diff(new Date('10/15/2014'), 'days');
userCount$() Observable.combineLatest(
.map(camperCount => numberWithCommas(camperCount)) frontEndCount$,
.doOnNext(camperCount => { dataVisCount$,
backEndCount$,
(frontEndCount = 0, dataVisCount = 0, backEndCount = 0) => ({
frontEndCount,
dataVisCount,
backEndCount
})
)
.doOnNext(({ frontEndCount, dataVisCount, backEndCount }) => {
res.render('resources/about', { res.render('resources/about', {
camperCount, frontEndCount: numberWithCommas(frontEndCount),
dataVisCount: numberWithCommas(dataVisCount),
backEndCount: numberWithCommas(backEndCount),
daysRunning, daysRunning,
title: dedent` title: dedent`
About our Open Source Community, our social media presence, About our Open Source Community, our social media presence,
and how to contact us`.split('\n').join(' '), and how to contact us
`.split('\n').join(' '),
globalCompletedCount: numberWithCommas( globalCompletedCount: numberWithCommas(
5612952 + (Math.floor((Date.now() - 1446268581061) / 1800)) 5612952 + (Math.floor((Date.now() - 1446268581061) / 1800))
) ),
globalPledgedAmount: numberWithCommas(Math.floor(
28000 +
((Date.now() - 1456207176902) / (2629746000 / 2000) * 8.30)
))
}); });
}) })
.subscribe(() => {}, next); .subscribe(() => {}, next);

View File

@ -1,4 +1,5 @@
import Rx from 'rx'; import Rx, { AsyncSubject, Observable } from 'rx';
import moment from 'moment';
import debugFactory from 'debug'; import debugFactory from 'debug';
const debug = debugFactory('fcc:rxUtils'); const debug = debugFactory('fcc:rxUtils');
@ -31,3 +32,22 @@ export function observeQuery(Model, method, query) {
export function observeMethod(context, methodName) { export function observeMethod(context, methodName) {
return Rx.Observable.fromNodeCallback(context[methodName], context); return Rx.Observable.fromNodeCallback(context[methodName], context);
} }
// timeChache(amount: Number, unit: String) => Observable
export function timeCache(time, unit) {
const source = this;
let cache;
let expireCacheAt;
return Observable.create(observable => {
// if there is no expire time set
// or if expireCacheAt is smaller than now,
// set new expire time in MS and create new subscription to source
if (!expireCacheAt || expireCacheAt < Date.now()) {
// set expire in ms;
expireCacheAt = moment().add(time, unit).valueOf();
cache = new AsyncSubject();
source.subscribe(cache);
}
return cache.subscribe(observable);
});
}

View File

@ -9,18 +9,31 @@ block content
span.tag Established:&#9; span.tag Established:&#9;
span.text-primary #{daysRunning} span.text-primary #{daysRunning}
| days ago | days ago
li
span.tag Population:&#9;
span.text-primary #{camperCount}
| campers
li
span.tag Completed:&#9;
span.text-primary #{globalCompletedCount}
| challenges
li.nowrap li.nowrap
span.tag Donated:&#9; span.tag Donated:&#9;
span.text-primary $850,000 span.text-primary $850,000
| in pro-bono code | in pro-bono code
li.nowrap
span.tag Pledged:&#9;
span.text-primary $#{globalPledgedAmount}
| to nonprofits
.row
.col-xs-12.col-sm-10.col-sm-offset-1.col-md-6.col-md-offset-3
h2.text-center Certifications
hr
ul.population-table
li.nowrap
span.tag Front End:&#9;
span.text-primary #{frontEndCount}
| earned
li.nowrap
span.tag Data Viz:&#9;
span.text-primary #{dataVisCount}
| earned
li.nowrap
span.tag Back End:&#9;
span.text-primary #{backEndCount}
| earned
.spacer .spacer
.row .row
.col-xs-12.col-sm-10.col-sm-offset-1.col-md-6.col-md-offset-3 .col-xs-12.col-sm-10.col-sm-offset-1.col-md-6.col-md-offset-3