Merge pull request #6333 from LenaBarinova/fix/streak-seems-broken-because-of-timezone

Fixed streak and completion dates to be showed using users timezone
This commit is contained in:
Berkeley Martinez
2016-01-30 11:47:38 -08:00
12 changed files with 181 additions and 111 deletions

View File

@@ -505,7 +505,8 @@ module.exports = function(app) {
id,
name,
challengeType,
solution
solution,
timezone
} = req.body;
const { alreadyCompleted } = updateUserProgress(
@@ -521,6 +522,10 @@ module.exports = function(app) {
}
);
if (timezone && (!req.user.timezone || req.user.timezone != timezone)) {
req.user.timezone = timezone;
}
let user = req.user;
saveUser(req.user)
.subscribe(

View File

@@ -1,6 +1,6 @@
import _ from 'lodash';
import dedent from 'dedent';
import moment from 'moment';
import moment from 'moment-timezone';
import { Observable } from 'rx';
import debugFactory from 'debug';
@@ -38,6 +38,8 @@ const certText = {
[certTypes.fullStack]: 'Full Stack Certified'
};
const dateFormat = 'MMM DD, YYYY';
function replaceScriptTags(value) {
return value
.replace(/<script>/gi, 'fccss')
@@ -183,6 +185,12 @@ module.exports = function(app) {
}
profileUser = profileUser.toJSON();
// timezone of signed-in account
// to show all date related components
// using signed-in account's timezone
// not of the profile she is viewing
const timezone = req.user && req.user.timezone ? req.user.timezone : 'UTC';
var cals = profileUser
.progressTimestamps
.map(objOrNum => {
@@ -192,8 +200,8 @@ module.exports = function(app) {
})
.sort();
profileUser.currentStreak = calcCurrentStreak(cals);
profileUser.longestStreak = calcLongestStreak(cals);
profileUser.currentStreak = calcCurrentStreak(cals, timezone);
profileUser.longestStreak = calcLongestStreak(cals, timezone);
const data = profileUser
.progressTimestamps
@@ -223,9 +231,20 @@ module.exports = function(app) {
+challenge.challengeType === 4;
}
const completedChallenges = profileUser.completedChallenges.filter(
({ name }) => typeof name === 'string'
);
const completedChallenges = profileUser.completedChallenges
.filter(({ name }) => typeof name === 'string')
.map(challenge => {
challenge = { ...challenge };
if (challenge.completedDate) {
challenge.completedDate =
moment.tz(challenge.completedDate, timezone).format(dateFormat);
}
if (challenge.lastUpdated) {
challenge.lastUpdated =
moment.tz(challenge.lastUpdated, timezone).format(dateFormat);
}
return challenge;
});
const projects = completedChallenges.filter(filterProjects);

View File

@@ -1,10 +1,10 @@
import moment from 'moment';
import moment from 'moment-timezone';
// day count between two epochs (inclusive)
export function dayCount([head, tail]) {
export function dayCount([head, tail], timezone = 'UTC') {
return Math.ceil(
moment(moment(head).endOf('day')).diff(
moment(tail).startOf('day'),
moment(moment(head).tz(timezone).endOf('day')).tz(timezone).diff(
moment(tail).tz(timezone).startOf('day'),
'days',
true)
);

View File

@@ -1,12 +1,12 @@
import moment from 'moment';
import moment from 'moment-timezone';
import { dayCount } from '../utils/date-utils';
const daysBetween = 1.5;
export function calcCurrentStreak(cals) {
export function calcCurrentStreak(cals, timezone = 'UTC') {
const revCals = cals.slice().reverse();
if (dayCount([moment(), revCals[0]]) > daysBetween) {
if (dayCount([moment().tz(timezone), revCals[0]], timezone) > daysBetween) {
return 0;
}
@@ -16,7 +16,7 @@ export function calcCurrentStreak(cals) {
const before = revCals[index === 0 ? 0 : index - 1];
if (
!streakBroken &&
moment(before).diff(cal, 'days', true) < daysBetween
moment(before).tz(timezone).diff(cal, 'days', true) < daysBetween
) {
return index;
}
@@ -25,22 +25,22 @@ export function calcCurrentStreak(cals) {
}, 0);
const lastTimestamp = revCals[lastDayInStreak];
return dayCount([moment(), lastTimestamp]);
return dayCount([moment().tz(timezone), lastTimestamp], timezone);
}
export function calcLongestStreak(cals) {
export function calcLongestStreak(cals, timezone = 'UTC') {
let tail = cals[0];
const longest = cals.reduce((longest, head, index) => {
const last = cals[index === 0 ? 0 : index - 1];
// is streak broken
if (moment(head).diff(last, 'days', true) > daysBetween) {
if (moment(head).tz(timezone).diff(last, 'days', true) > daysBetween) {
tail = head;
}
if (dayCount(longest) < dayCount([head, tail])) {
if (dayCount(longest, timezone) < dayCount([head, tail], timezone)) {
return [head, tail];
}
return longest;
}, [cals[0], cals[0]]);
return dayCount(longest);
return dayCount(longest, timezone);
}

View File

@@ -134,8 +134,8 @@ block content
tr
td.col-xs-5.hidden-xs
a(href='/challenges/' + removeOldTerms(challenge.name), target='_blank')= removeOldTerms(challenge.name)
td.col-xs-2.hidden-xs= challenge.completedDate ? moment(challenge.completedDate, 'x').format("MMM DD, YYYY") : 'Not Available'
td.col-xs-2.hidden-xs= challenge.lastUpdated ? moment(challenge.lastUpdated, 'x').format("MMM DD, YYYY") : ''
td.col-xs-2.hidden-xs= challenge.completedDate ? challenge.completedDate : 'Not Available'
td.col-xs-2.hidden-xs= challenge.lastUpdated ? challenge.lastUpdated : ''
td.col-xs-2.hidden-xs
a(href=challenge.solution, target='_blank') View my project
td.col-xs-12.visible-xs
@@ -152,8 +152,8 @@ block content
for challenge in algos
tr
td.col-xs-5.hidden-xs= removeOldTerms(challenge.name)
td.col-xs-2.hidden-xs= challenge.completedDate ? moment(challenge.completedDate, 'x').format("MMM DD, YYYY") : 'Not Available'
td.col-xs-2.hidden-xs= challenge.lastUpdated ? moment(challenge.lastUpdated, 'x').format("MMM DD, YYYY") : ''
td.col-xs-2.hidden-xs= challenge.completedDate ? challenge.completedDate : 'Not Available'
td.col-xs-2.hidden-xs= challenge.lastUpdated ? challenge.lastUpdated : ''
td.col-xs-2.hidden-xs
if (challenge.solution)
a(href='/challenges/' + removeOldTerms(challenge.name) + '?solution=' + encodeURIComponent(encodeFcc(challenge.solution)), target='_blank') View my solution
@@ -176,8 +176,8 @@ block content
for challenge in challenges
tr
td.col-xs-5.hidden-xs= removeOldTerms(challenge.name)
td.col-xs-2.hidden-xs= challenge.completedDate ?moment(challenge.completedDate, 'x').format("MMM DD, YYYY") : 'Not Available'
td.col-xs-2.hidden-xs= challenge.lastUpdated ? moment(challenge.lastUpdated, 'x').format("MMM DD, YYYY") : ''
td.col-xs-2.hidden-xs= challenge.completedDate ? challenge.completedDate : 'Not Available'
td.col-xs-2.hidden-xs= challenge.lastUpdated ? challenge.lastUpdated : ''
td.col-xs-2.hidden-xs
if (challenge.solution)
a(href='/challenges/' + removeOldTerms(challenge.name) + '?solution=' + encodeURIComponent(encodeFcc(challenge.solution)), target='_blank') View my solution