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:
@@ -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(
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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)
|
||||
);
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user