242 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import _ from 'lodash';
 | |
| import { Observable } from 'rx';
 | |
| 
 | |
| import { unDasherize, nameify } from '../utils';
 | |
| import {
 | |
|   addNameIdMap as _addNameIdToMap,
 | |
|   checkMapData,
 | |
|   getFirstChallenge as _getFirstChallenge
 | |
| } from '../../common/utils/map.js';
 | |
| 
 | |
| const isDev = process.env.NODE_ENV !== 'production';
 | |
| const isBeta = !!process.env.BETA;
 | |
| const challengesRegex = /^(bonfire|waypoint|zipline|basejump|checkpoint)/i;
 | |
| const addNameIdMap = _.once(_addNameIdToMap);
 | |
| const getFirstChallenge = _.once(_getFirstChallenge);
 | |
| /*
 | |
|  * interface ChallengeMap {
 | |
|  *   result: {
 | |
|  *     superBlocks: [ ...superBlockDashedName: String ]
 | |
| *    },
 | |
|  *   entities: {
 | |
|  *     superBlock: {
 | |
|  *       [ ...superBlockDashedName ]: SuperBlock
 | |
|  *     },
 | |
|  *     block: {
 | |
|  *       [ ...blockDashedNameg ]: Block,
 | |
|  *     challenge: {
 | |
|  *       [ ...challengeDashedNameg ]: Challenge
 | |
|  *     }
 | |
|  *   }
 | |
|  * }
 | |
|  */
 | |
| export function _cachedMap({ Block, Challenge }) {
 | |
|   const challenges = Challenge.find$({
 | |
|     order: [ 'order ASC', 'suborder ASC' ],
 | |
|     where: { isPrivate: false }
 | |
|   });
 | |
|   const challengeMap = challenges
 | |
|     .map(
 | |
|       challenges => challenges
 | |
|         .map(challenge => challenge.toJSON())
 | |
|         .reduce((hash, challenge) => {
 | |
|           hash[challenge.dashedName] = challenge;
 | |
|           return hash;
 | |
|         }, {})
 | |
|     );
 | |
|   const blocks = Block.find$({
 | |
|     order: [ 'superOrder ASC', 'order ASC' ],
 | |
|     where: { isPrivate: false }
 | |
|   });
 | |
|   const blockMap = Observable.combineLatest(
 | |
|     blocks.map(
 | |
|       blocks => blocks
 | |
|         .map(block => block.toJSON())
 | |
|         .reduce((hash, block) => {
 | |
|           hash[block.dashedName] = block;
 | |
|           return hash;
 | |
|         }, {})
 | |
|     ),
 | |
|     challenges
 | |
|   )
 | |
|     .map(([ blocksMap, challenges ]) => {
 | |
|       return challenges.reduce((blocksMap, challenge) => {
 | |
|         if (blocksMap[challenge.block].challenges) {
 | |
|           blocksMap[challenge.block].challenges.push(challenge.dashedName);
 | |
|         } else {
 | |
|           blocksMap[challenge.block] = {
 | |
|             ...blocksMap[challenge.block],
 | |
|             challenges: [ challenge.dashedName ]
 | |
|           };
 | |
|         }
 | |
|         return blocksMap;
 | |
|       }, blocksMap);
 | |
|     });
 | |
|   const superBlockMap = blocks.map(blocks => blocks.reduce((map, block) => {
 | |
|     if (
 | |
|       map[block.superBlock] &&
 | |
|       map[block.superBlock].blocks
 | |
|     ) {
 | |
|       map[block.superBlock].blocks.push(block.dashedName);
 | |
|     } else {
 | |
|       map[block.superBlock] = {
 | |
|         title: _.startCase(block.superBlock),
 | |
|         order: block.superOrder,
 | |
|         name: nameify(_.startCase(block.superBlock)),
 | |
|         dashedName: block.superBlock,
 | |
|         blocks: [block.dashedName],
 | |
|         message: block.superBlockMessage
 | |
|       };
 | |
|     }
 | |
|     return map;
 | |
|   }, {}));
 | |
|   const superBlocks = superBlockMap.map(superBlockMap => {
 | |
|     return Object.keys(superBlockMap)
 | |
|       .map(key => superBlockMap[key])
 | |
|       .map(({ dashedName }) => dashedName);
 | |
|   });
 | |
|   return Observable.combineLatest(
 | |
|     superBlockMap,
 | |
|     blockMap,
 | |
|     challengeMap,
 | |
|     superBlocks,
 | |
|     (superBlock, block, challenge, superBlocks) => ({
 | |
|       entities: {
 | |
|         superBlock,
 | |
|         block,
 | |
|         challenge
 | |
|       },
 | |
|       result: {
 | |
|         superBlocks
 | |
|       }
 | |
|     })
 | |
|   )
 | |
|     .do(checkMapData)
 | |
|     .shareReplay();
 | |
| }
 | |
| 
 | |
| export const cachedMap = _.once(_cachedMap);
 | |
| 
 | |
| // type ObjectId: String;
 | |
| // getChallengeById(
 | |
| //   map: Observable[map],
 | |
| //   id: ObjectId
 | |
| // ) => Observable[Challenge] | Void;
 | |
| export function getChallengeById(map, id) {
 | |
|   return Observable.if(
 | |
|     () => !id,
 | |
|     map.map(getFirstChallenge),
 | |
|     map.map(addNameIdMap)
 | |
|       .map(map => {
 | |
|         const {
 | |
|           entities: { challenge: challengeMap, challengeIdToName }
 | |
|         } = map;
 | |
|         let finalChallenge;
 | |
|         const dashedName = challengeIdToName[id];
 | |
|         finalChallenge = challengeMap[dashedName];
 | |
|         if (!finalChallenge) {
 | |
|           finalChallenge = getFirstChallenge(map);
 | |
|         }
 | |
|         return finalChallenge;
 | |
|       })
 | |
|   );
 | |
| }
 | |
| 
 | |
| export function getChallengeInfo(map) {
 | |
|   return map.map(addNameIdMap)
 | |
|     .map(({
 | |
|       entities: {
 | |
|         challenge: challengeMap,
 | |
|         challengeIdToName
 | |
|       }
 | |
|     }) => ({
 | |
|       challengeMap,
 | |
|       challengeIdToName
 | |
|     }));
 | |
| }
 | |
| 
 | |
| // if challenge is not isComingSoon or isBeta => load
 | |
| // if challenge is ComingSoon we are in beta||dev => load
 | |
| // if challenge is beta and we are in beta||dev => load
 | |
| // else hide
 | |
| function loadComingSoonOrBetaChallenge({
 | |
|   isComingSoon,
 | |
|   isBeta: challengeIsBeta
 | |
| }) {
 | |
|   return !(isComingSoon || challengeIsBeta) || isDev || isBeta;
 | |
| }
 | |
| 
 | |
| // this is a hard search
 | |
| // falls back to soft search
 | |
| export function getChallenge(
 | |
|   challengeDashedName,
 | |
|   blockDashedName,
 | |
|   map) {
 | |
|   return map
 | |
|     .flatMap(({ entities, result: { superBlocks } }) => {
 | |
|       const superBlock = entities.superBlock;
 | |
|       const block = entities.block[blockDashedName];
 | |
|       const challenge = entities.challenge[challengeDashedName];
 | |
|       return Observable.if(
 | |
|         () => (
 | |
|           !blockDashedName ||
 | |
|           !block ||
 | |
|           !challenge ||
 | |
|           !loadComingSoonOrBetaChallenge(challenge)
 | |
|         ),
 | |
|         getChallengeByDashedName(challengeDashedName, map),
 | |
|         Observable.just({ block, challenge })
 | |
|       )
 | |
|         .map(({ challenge, block }) => ({
 | |
|           redirect: challenge.block !== blockDashedName ?
 | |
|             `/challenges/${block.dashedName}/${challenge.dashedName}` :
 | |
|             false,
 | |
|           entities: {
 | |
|             superBlock,
 | |
|             challenge: {
 | |
|               [challenge.dashedName]: challenge
 | |
|             }
 | |
|           },
 | |
|           result: {
 | |
|             block: block.dashedName,
 | |
|             challenge: challenge.dashedName,
 | |
|             superBlocks
 | |
|           }
 | |
|         }));
 | |
|     });
 | |
| }
 | |
| 
 | |
| export function getBlockForChallenge(map, challenge) {
 | |
|   return map.map(({ entities: { block } }) => block[challenge.block]);
 | |
| }
 | |
| 
 | |
| export function getChallengeByDashedName(dashedName, map) {
 | |
|   const challengeName = unDasherize(dashedName)
 | |
|     .replace(challengesRegex, '');
 | |
|   const testChallengeName = new RegExp(challengeName, 'i');
 | |
| 
 | |
|   return map
 | |
|     .map(({ entities }) => entities.challenge)
 | |
|     .flatMap(challengeMap => {
 | |
|       return Observable.from(Object.keys(challengeMap))
 | |
|         .map(key => challengeMap[key]);
 | |
|     })
 | |
|     .filter(challenge => {
 | |
|       return loadComingSoonOrBetaChallenge(challenge) &&
 | |
|         testChallengeName.test(challenge.name);
 | |
|     })
 | |
|     .last({ defaultValue: null })
 | |
|     .flatMap(challengeOrNull => {
 | |
|       return Observable.if(
 | |
|         () => !!challengeOrNull,
 | |
|         Observable.just(challengeOrNull),
 | |
|         map.map(getFirstChallenge)
 | |
|       );
 | |
|     })
 | |
|     .flatMap(challenge => {
 | |
|       return getBlockForChallenge(map, challenge)
 | |
|         .map(block => ({ challenge, block }));
 | |
|     });
 | |
| }
 | |
| 
 |