| 
									
										
										
										
											2016-08-03 12:56:00 -07:00
										 |  |  | import { Observable } from 'rx'; | 
					
						
							| 
									
										
										
										
											2016-08-03 15:26:05 -07:00
										 |  |  | import debug from 'debug'; | 
					
						
							| 
									
										
										
										
											2016-08-03 12:56:00 -07:00
										 |  |  | import { push } from 'react-router-redux'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import types from './types'; | 
					
						
							| 
									
										
										
										
											2016-08-03 15:26:05 -07:00
										 |  |  | import { | 
					
						
							|  |  |  |   updateMyCurrentChallenge, | 
					
						
							|  |  |  |   createErrorObservable | 
					
						
							|  |  |  | } from './actions'; | 
					
						
							| 
									
										
										
										
											2016-08-03 12:56:00 -07:00
										 |  |  | import { | 
					
						
							|  |  |  |   userSelector, | 
					
						
							|  |  |  |   firstChallengeSelector | 
					
						
							|  |  |  | } from './selectors'; | 
					
						
							|  |  |  | import { updateCurrentChallenge } from '../routes/challenges/redux/actions'; | 
					
						
							| 
									
										
										
										
											2016-08-03 15:26:05 -07:00
										 |  |  | 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; | 
					
						
							| 
									
										
										
										
											2016-08-04 15:18:51 -07:00
										 |  |  |     }) | 
					
						
							|  |  |  |     .distinctUntilChanged(); | 
					
						
							| 
									
										
										
										
											2016-08-03 15:26:05 -07:00
										 |  |  |   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); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-08-03 12:56:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-03 15:26:05 -07:00
										 |  |  | export function loadCurrentChallengeSaga(actions, getState) { | 
					
						
							| 
									
										
										
										
											2016-08-03 12:56:00 -07:00
										 |  |  |   return getActionsOfType(actions, types.loadCurrentChallenge) | 
					
						
							|  |  |  |     .flatMap(() => { | 
					
						
							|  |  |  |       let finalChallenge; | 
					
						
							|  |  |  |       const state = getState(); | 
					
						
							|  |  |  |       const { | 
					
						
							|  |  |  |         entities: { challenge: challengeMap, challengeIdToName }, | 
					
						
							| 
									
										
										
										
											2016-08-04 15:16:55 -07:00
										 |  |  |         challengesApp: { id: currentlyLoadedChallengeId }, | 
					
						
							|  |  |  |         locationBeforeTransition: { pathname } = {} | 
					
						
							| 
									
										
										
										
											2016-08-03 12:56:00 -07:00
										 |  |  |       } = state; | 
					
						
							|  |  |  |       const firstChallenge = firstChallengeSelector(state); | 
					
						
							|  |  |  |       const { user: { currentChallengeId } } = userSelector(state); | 
					
						
							| 
									
										
										
										
											2016-08-04 15:16:55 -07:00
										 |  |  |       const isOnAChallenge = (/^\/[^\/]{2,6}\/challenges/).test(pathname); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-03 12:56:00 -07:00
										 |  |  |       if (!currentChallengeId) { | 
					
						
							|  |  |  |         finalChallenge = firstChallenge; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         finalChallenge = challengeMap[ | 
					
						
							|  |  |  |           challengeIdToName[ currentChallengeId ] | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-08-04 15:16:55 -07:00
										 |  |  |       if ( | 
					
						
							|  |  |  |         // data might not be there yet, ignore for now
 | 
					
						
							|  |  |  |         !finalChallenge || | 
					
						
							|  |  |  |         // are we already on that challenge?
 | 
					
						
							|  |  |  |         (isOnAChallenge && finalChallenge.id === currentlyLoadedChallengeId) | 
					
						
							|  |  |  |       ) { | 
					
						
							| 
									
										
										
										
											2016-08-03 12:56:00 -07:00
										 |  |  |         // 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}` | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-08-03 15:26:05 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | export default combineSagas( | 
					
						
							|  |  |  |   updateMyCurrentChallengeSaga, | 
					
						
							|  |  |  |   loadCurrentChallengeSaga | 
					
						
							|  |  |  | ); |