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