* fix(files): Decouple files from challenges * feat(server/react): Remove action logger use redux remote devtools instead! * feat(Challenges): Disable js on edit, enable on execute * feat(Challenge/Preview): Show message when js is disabled * refactor(frameEpic): Reduce code by using lodash * feat(frameEpic): Disable js in preview by state * feat(frameEpic): Colocate epic in Challenges/redux * refactor(ExecuteChallengeEpic): CoLocated with Challenges * refactor(executeChallengesEpic): Separate tests from main logic * feat(Challenge/Preview): Update main on edit * feat(frameEpuc): Replace frame on edit/execute This allows for sandbox to work properly * fix(Challenges/Utils): Require utisl * revert(frameEpic): Hoist function to mount code in frame * fix(frameEpic): Ensure new frame is given classname * feat(executeChallenge): Update main on code unlocked * fix(frameEpic): Filter out empty test message * fix(Challenge/Preview): Remove unnessary quote in classname * feat(codeStorageEpic): Separate localstorage from solutions loading * fix(fetchUser): Merge user actions into one prefer many effects from one action over one action to one effect * fix(themes): Centralize theme utils and defs * fix(entities.user): Fix user reducer namespacing * feat(frame): Refactor frameEpic to util * feat(Challenges.redux): Should not attempt to update main from storage * fix(loadPreviousChallengeEpic): Refactor for RFR * fix(Challenges.Modern): Show preview plane
		
			
				
	
	
		
			59 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			59 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import _ from 'lodash';
 | |
| import { ofType } from 'redux-epic';
 | |
| 
 | |
| import { types } from './';
 | |
| import {
 | |
|   userSelector,
 | |
|   firstChallengeSelector,
 | |
|   challengeSelector
 | |
| } from '../../redux';
 | |
| import { onRouteChallenges } from '../../routes/Challenges/redux';
 | |
| import { entitiesSelector } from '../../entities';
 | |
| import { langSelector, pathnameSelector } from '../../Router/redux';
 | |
| 
 | |
| export default function loadCurrentChallengeEpic(actions, { getState }) {
 | |
|   return actions::ofType(types.clickOnLogo, types.clickOnMap)
 | |
|     .debounce(500)
 | |
|     .map(getState)
 | |
|     .map(state => {
 | |
|       let finalChallenge;
 | |
|       const lang = langSelector(state);
 | |
|       const { id: currentlyLoadedChallengeId } = challengeSelector(state);
 | |
|       const {
 | |
|         challenge: challengeMap,
 | |
|         challengeIdToName
 | |
|       } = entitiesSelector(state);
 | |
|       const pathname = pathnameSelector(state);
 | |
|       const firstChallenge = firstChallengeSelector(state);
 | |
|       const { currentChallengeId } = userSelector(state);
 | |
|       const isOnAChallenge = (/^\/[^\/]{2,6}\/challenges/).test(pathname);
 | |
| 
 | |
|       if (!currentChallengeId) {
 | |
|         finalChallenge = firstChallenge;
 | |
|       } else {
 | |
|         finalChallenge = challengeMap[
 | |
|           challengeIdToName[ currentChallengeId ]
 | |
|         ];
 | |
|       }
 | |
|       return {
 | |
|         ..._.pick(finalChallenge, ['id', 'block', 'dashedName']),
 | |
|         lang,
 | |
|         isOnAChallenge,
 | |
|         currentlyLoadedChallengeId
 | |
|       };
 | |
|     })
 | |
|     .filter(({
 | |
|       id,
 | |
|       isOnAChallenge,
 | |
|       currentlyLoadedChallengeId
 | |
|     }) => (
 | |
|       // data might not be there yet, filter out for now
 | |
|       !!id &&
 | |
|       // are we already on that challenge? if not load challenge
 | |
|       (!isOnAChallenge || id !== currentlyLoadedChallengeId)
 | |
|       // don't reload if the challenge is already loaded.
 | |
|       // This may change to toast to avoid user confusion
 | |
|     ))
 | |
|     .map(onRouteChallenges);
 | |
| }
 |