93 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			93 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import { Observable } from 'rx';
 | 
						|
import debug from 'debug';
 | 
						|
import { push } from 'react-router-redux';
 | 
						|
 | 
						|
import types from './types';
 | 
						|
import {
 | 
						|
  updateMyCurrentChallenge,
 | 
						|
  createErrorObservable
 | 
						|
} from './actions';
 | 
						|
import {
 | 
						|
  userSelector,
 | 
						|
  firstChallengeSelector
 | 
						|
} from './selectors';
 | 
						|
import { updateCurrentChallenge } from '../routes/challenges/redux/actions';
 | 
						|
import getActionsOfType from '../../utils/get-actions-of-type';
 | 
						|
import combineSagas from '../../utils/combine-sagas';
 | 
						|
import { postJSON$ } from '../../utils/ajax-stream';
 | 
						|
 | 
						|
const log = debug('fcc:app/redux/load-current-challenge-saga');
 | 
						|
export function updateMyCurrentChallengeSaga(actions, getState) {
 | 
						|
  const updateChallenge$ = getActionsOfType(
 | 
						|
    actions,
 | 
						|
    updateCurrentChallenge.toString()
 | 
						|
  )
 | 
						|
    .map(({ payload: { id } }) => id)
 | 
						|
    .filter(() => {
 | 
						|
      const { app: { user: username } } = getState();
 | 
						|
      return !!username;
 | 
						|
    })
 | 
						|
    .distinctUntilChanged();
 | 
						|
  const optimistic = updateChallenge$.map(id => {
 | 
						|
    const { app: { user: username } } = getState();
 | 
						|
    return updateMyCurrentChallenge(username, id);
 | 
						|
  });
 | 
						|
  const ajaxUpdate = updateChallenge$
 | 
						|
    .debounce(250)
 | 
						|
    .flatMapLatest(currentChallengeId => {
 | 
						|
      const { app: { csrfToken: _csrf } } = getState();
 | 
						|
      return postJSON$(
 | 
						|
        '/update-my-current-challenge',
 | 
						|
        { _csrf, currentChallengeId }
 | 
						|
      )
 | 
						|
        .map(({ message }) => log(message))
 | 
						|
        .catch(createErrorObservable);
 | 
						|
    });
 | 
						|
  return Observable.merge(optimistic, ajaxUpdate);
 | 
						|
}
 | 
						|
 | 
						|
export function loadCurrentChallengeSaga(actions, getState) {
 | 
						|
  return getActionsOfType(actions, types.loadCurrentChallenge)
 | 
						|
    .flatMap(() => {
 | 
						|
      let finalChallenge;
 | 
						|
      const state = getState();
 | 
						|
      const {
 | 
						|
        entities: { challenge: challengeMap, challengeIdToName },
 | 
						|
        challengesApp: { id: currentlyLoadedChallengeId },
 | 
						|
        locationBeforeTransition: { pathname } = {}
 | 
						|
      } = state;
 | 
						|
      const firstChallenge = firstChallengeSelector(state);
 | 
						|
      const { user: { currentChallengeId } } = userSelector(state);
 | 
						|
      const isOnAChallenge = (/^\/[^\/]{2,6}\/challenges/).test(pathname);
 | 
						|
 | 
						|
      if (!currentChallengeId) {
 | 
						|
        finalChallenge = firstChallenge;
 | 
						|
      } else {
 | 
						|
        finalChallenge = challengeMap[
 | 
						|
          challengeIdToName[ currentChallengeId ]
 | 
						|
        ];
 | 
						|
      }
 | 
						|
      if (
 | 
						|
        // data might not be there yet, ignore for now
 | 
						|
        !finalChallenge ||
 | 
						|
        // are we already on that challenge?
 | 
						|
        (isOnAChallenge && finalChallenge.id === currentlyLoadedChallengeId)
 | 
						|
      ) {
 | 
						|
        // don't reload if the challenge is already loaded.
 | 
						|
        // This may change to toast to avoid user confusion
 | 
						|
        return Observable.empty();
 | 
						|
      }
 | 
						|
      return Observable.of(
 | 
						|
        updateCurrentChallenge(finalChallenge),
 | 
						|
        push(
 | 
						|
          `/challenges/${finalChallenge.block}/${finalChallenge.dashedName}`
 | 
						|
        )
 | 
						|
      );
 | 
						|
    });
 | 
						|
}
 | 
						|
 | 
						|
export default combineSagas(
 | 
						|
  updateMyCurrentChallengeSaga,
 | 
						|
  loadCurrentChallengeSaga
 | 
						|
);
 |