| 
									
										
										
										
											2016-08-01 16:54:33 -07:00
										 |  |  | 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] || {}; | 
					
						
							| 
									
										
										
										
											2016-11-06 10:41:37 +00:00
										 |  |  |   const isTranslated = Object.keys(translation).length > 0; | 
					
						
							| 
									
										
										
										
											2016-08-01 16:54:33 -07:00
										 |  |  |   if (lang !== 'en') { | 
					
						
							|  |  |  |     challenge = { | 
					
						
							|  |  |  |       ...challenge, | 
					
						
							| 
									
										
										
										
											2016-11-06 10:41:37 +00:00
										 |  |  |       ...translation, | 
					
						
							|  |  |  |       isTranslated | 
					
						
							| 
									
										
										
										
											2016-08-01 16:54:33 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-11-06 10:41:37 +00:00
										 |  |  |   return { | 
					
						
							|  |  |  |     ...challenge, | 
					
						
							|  |  |  |     isTranslated | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2016-08-01 16:54:33 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } |