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 }));
 | 
						|
    });
 | 
						|
}
 | 
						|
 |