diff --git a/common/app/redux/actions.js b/common/app/redux/actions.js index 5407e521f7..734f568f99 100644 --- a/common/app/redux/actions.js +++ b/common/app/redux/actions.js @@ -38,6 +38,11 @@ export const updateUserPoints = createAction( types.updateUserPoints, (username, points) => ({ username, points }) ); +// updateCompletedChallenges(username: String) => Action +export const updateCompletedChallenges = createAction( + types.updateCompletedChallenges +); + // used when server needs client to redirect export const delayedRedirect = createAction(types.delayedRedirect); diff --git a/common/app/redux/entities-reducer.js b/common/app/redux/entities-reducer.js index 8ba8dc5ab0..8bb0a508a0 100644 --- a/common/app/redux/entities-reducer.js +++ b/common/app/redux/entities-reducer.js @@ -1,4 +1,7 @@ -import { updateUserPoints } from './types'; +import { + updateUserPoints, + updateCompletedChallenges +} from './types'; const initialState = { superBlock: {}, @@ -9,6 +12,22 @@ const initialState = { export default function entities(state = initialState, action) { const { type, payload: { username, points } = {} } = action; + if (type === updateCompletedChallenges) { + const username = action.payload; + const completedChallengeMap = state.user[username].challengeMap || {}; + return { + ...state, + challenge: Object.keys(state.challenge) + .reduce((map, key) => { + const challenge = state.challenge[key]; + map[key] = { + ...challenge, + isCompleted: !!completedChallengeMap[challenge.id] + }; + return map; + }, {}) + }; + } if (type === updateUserPoints) { return { ...state, diff --git a/common/app/redux/fetch-user-saga.js b/common/app/redux/fetch-user-saga.js index db3bd88a29..3bcaf28f43 100644 --- a/common/app/redux/fetch-user-saga.js +++ b/common/app/redux/fetch-user-saga.js @@ -3,6 +3,7 @@ import { fetchUser } from './types'; import { addUser, updateThisUser, + updateCompletedChallenges, createErrorObservable, showSignIn } from './actions'; @@ -18,7 +19,8 @@ export default function getUserSaga(action$, getState, { services }) { } return Observable.of( addUser(entities), - updateThisUser(result) + updateThisUser(result), + updateCompletedChallenges(result) ); }) .catch(createErrorObservable); diff --git a/common/app/redux/types.js b/common/app/redux/types.js index 5a5dd84883..46a8307270 100644 --- a/common/app/redux/types.js +++ b/common/app/redux/types.js @@ -7,6 +7,7 @@ export default createTypes([ 'addUser', 'updateThisUser', 'updateUserPoints', + 'updateCompletedChallenges', 'showSignIn', 'makeToast', diff --git a/common/app/routes/challenges/components/map/Block.jsx b/common/app/routes/challenges/components/map/Block.jsx index 6f41a714dd..57837f68a1 100644 --- a/common/app/routes/challenges/components/map/Block.jsx +++ b/common/app/routes/challenges/components/map/Block.jsx @@ -24,13 +24,20 @@ export class Block extends PureComponent { return
No Challenges Found
; } return challenges.map(challenge => { - const { title, dashedName, isLocked, isRequired } = challenge; + const { + title, + dashedName, + isLocked, + isRequired, + isCompleted + } = challenge; const challengeClassName = classnames({ 'text-primary': true, 'padded-ionic-icon': true, 'negative-15': true, 'challenge-title': true, - 'ion-checkmark-circled': !isLocked, + 'ion-checkmark-circled faded': !isLocked && isCompleted, + 'ion-ios-circle-outline': !isLocked && !isCompleted, 'ion-locked': isLocked, disabled: isLocked });