232 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			6.3 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
 | 
						|
      }));
 | 
						|
    });
 | 
						|
}
 |