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
137 lines
3.6 KiB
JavaScript
137 lines
3.6 KiB
JavaScript
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 };
|
|
};
|
|
}
|
|
|