Fix(accounts): show challenge info on user profile

This changes the behavior of the user profile page to pull the current
challenge info from our challenge map and overwrite the user challenge.
This should also make name changes point to the correct challenge
regardless of the info saved to the user profile
This commit is contained in:
Berkeley Martinez
2016-08-01 16:54:33 -07:00
parent 7f22c59239
commit 606bfd7c88
6 changed files with 197 additions and 179 deletions

136
server/utils/map.js Normal file
View File

@ -0,0 +1,136 @@
import _ from 'lodash';
import { Observable } from 'rx';
import { Schema, valuesOf, arrayOf, normalize } from 'normalizr';
import { nameify } from '../utils';
import supportedLanguages from '../../common/utils/supported-languages';
const challenge = new Schema('challenge', { idAttribute: 'dashedName' });
const block = new Schema('block', { idAttribute: 'dashedName' });
const superBlock = new Schema('superBlock', { idAttribute: 'dashedName' });
block.define({
challenges: arrayOf(challenge)
});
superBlock.define({
blocks: arrayOf(block)
});
const mapSchema = valuesOf(superBlock);
let mapObservableCache;
/*
* interface ChallengeMap {
* result: [superBlockDashedName: String]
* entities: {
* superBlock: {
* [superBlockDashedName: String]: {
* blocks: [blockDashedName: String]
* }
* },
* block: {
* [blockDashedName: String]: {
* challenges: [challengeDashedName: String]
* }
* },
* challenge: {
* [challengeDashedName: String]: Challenge
* }
* }
* }
*/
export function cachedMap(Block) {
if (mapObservableCache) {
return mapObservableCache;
}
const query = {
include: 'challenges',
order: ['superOrder ASC', 'order ASC']
};
const map$ = Block.find$(query)
.flatMap(blocks => Observable.from(blocks.map(block => block.toJSON())))
.reduce((map, block) => {
if (map[block.superBlock]) {
map[block.superBlock].blocks.push(block);
} else {
map[block.superBlock] = {
title: _.startCase(block.superBlock),
order: block.superOrder,
name: nameify(_.startCase(block.superBlock)),
dashedName: block.superBlock,
blocks: [block],
message: block.superBlockMessage
};
}
return map;
}, {})
.map(map => normalize(map, mapSchema))
.map(map => {
// make sure challenges are in the right order
map.entities.block = Object.keys(map.entities.block)
// turn map into array
.map(key => map.entities.block[key])
// perform re-order
.map(block => {
block.challenges = block.challenges.reduce((accu, dashedName) => {
const index = map.entities.challenge[dashedName].suborder;
accu[index - 1] = dashedName;
return accu;
}, []);
return block;
})
// turn back into map
.reduce((blockMap, block) => {
blockMap[block.dashedName] = block;
return blockMap;
}, {});
return map;
})
.map(map => {
// re-order superBlocks result
const result = Object.keys(map.result).reduce((result, supName) => {
const index = map.entities.superBlock[supName].order;
result[index] = supName;
return result;
}, []);
return {
...map,
result
};
})
.shareReplay();
mapObservableCache = map$;
return map$;
}
export function mapChallengeToLang(
{ translations = {}, ...challenge },
lang
) {
if (!supportedLanguages[lang]) {
lang = 'en';
}
const translation = translations[lang] || {};
if (lang !== 'en') {
challenge = {
...challenge,
...translation
};
}
return challenge;
}
export function getMapForLang(lang) {
return ({ entities: { challenge: challengeMap, ...entities }, result }) => {
entities.challenge = Object.keys(challengeMap)
.reduce((translatedChallengeMap, key) => {
translatedChallengeMap[key] = mapChallengeToLang(
challengeMap[key],
lang
);
return translatedChallengeMap;
}, {});
return { result, entities };
};
}