141 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			3.7 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] || {};
 | |
|   const isTranslated = Object.keys(translation).length > 0;
 | |
|   if (lang !== 'en') {
 | |
|     challenge = {
 | |
|       ...challenge,
 | |
|       ...translation,
 | |
|       isTranslated
 | |
|     };
 | |
|   }
 | |
|   return {
 | |
|     ...challenge,
 | |
|     isTranslated
 | |
|   };
 | |
| }
 | |
| 
 | |
| 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 };
 | |
|   };
 | |
| }
 |