2021-04-28 23:11:20 +02:00
|
|
|
import { uniqBy } from 'lodash-es';
|
2021-08-02 15:39:40 +02:00
|
|
|
import { createAction, handleActions } from 'redux-actions';
|
2019-08-30 19:15:26 +02:00
|
|
|
import store from 'store';
|
2018-08-23 16:29:26 +01:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
import { actionTypes as challengeTypes } from '../templates/Challenges/redux/action-types';
|
|
|
|
import { CURRENT_CHALLENGE_KEY } from '../templates/Challenges/redux/current-challenge-saga';
|
2018-08-25 00:24:19 +01:00
|
|
|
import { createAcceptTermsSaga } from './accept-terms-saga';
|
2021-08-02 15:39:40 +02:00
|
|
|
import { actionTypes, ns } from './action-types';
|
2018-08-30 15:27:53 +01:00
|
|
|
import { createAppMountSaga } from './app-mount-saga';
|
2019-12-02 15:48:53 +03:00
|
|
|
import { createDonationSaga } from './donation-saga';
|
2021-08-02 15:39:40 +02:00
|
|
|
import failedUpdatesEpic from './failed-updates-epic';
|
|
|
|
import { createFetchUserSaga } from './fetch-user-saga';
|
2020-02-04 08:43:56 +03:00
|
|
|
import { createGaSaga } from './ga-saga';
|
2018-08-23 16:29:26 +01:00
|
|
|
|
2018-09-30 11:37:19 +01:00
|
|
|
import hardGoToEpic from './hard-go-to-epic';
|
2021-08-02 15:39:40 +02:00
|
|
|
import { createReportUserSaga } from './report-user-saga';
|
2018-09-30 11:37:19 +01:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
import { actionTypes as settingsTypes } from './settings/action-types';
|
|
|
|
import { createShowCertSaga } from './show-cert-saga';
|
|
|
|
import updateCompleteEpic from './update-complete-epic';
|
2018-09-30 11:37:19 +01:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export { ns };
|
2018-08-23 16:29:26 +01:00
|
|
|
|
2018-11-29 12:12:15 +00:00
|
|
|
export const defaultFetchState = {
|
2018-09-04 14:54:23 +01:00
|
|
|
pending: true,
|
|
|
|
complete: false,
|
|
|
|
errored: false,
|
|
|
|
error: null
|
|
|
|
};
|
|
|
|
|
2020-10-14 13:23:26 +03:00
|
|
|
export const defaultDonationFormState = {
|
2021-04-02 09:33:34 +03:00
|
|
|
redirecting: false,
|
2020-10-14 13:23:26 +03:00
|
|
|
processing: false,
|
|
|
|
success: false,
|
2021-08-19 22:47:25 +03:00
|
|
|
error: '',
|
|
|
|
loading: {
|
|
|
|
stripe: true,
|
|
|
|
paypal: true
|
|
|
|
}
|
2020-10-14 13:23:26 +03:00
|
|
|
};
|
|
|
|
|
2018-08-23 16:29:26 +01:00
|
|
|
const initialState = {
|
|
|
|
appUsername: '',
|
2021-02-08 10:28:36 +03:00
|
|
|
recentlyClaimedBlock: null,
|
2019-12-09 17:30:24 +01:00
|
|
|
canRequestProgressDonation: true,
|
2018-09-30 11:37:19 +01:00
|
|
|
completionCount: 0,
|
2019-08-30 19:15:26 +02:00
|
|
|
currentChallengeId: store.get(CURRENT_CHALLENGE_KEY),
|
2018-09-04 14:54:23 +01:00
|
|
|
showCert: {},
|
|
|
|
showCertFetchState: {
|
|
|
|
...defaultFetchState
|
2018-08-23 16:29:26 +01:00
|
|
|
},
|
2018-09-04 14:54:23 +01:00
|
|
|
user: {},
|
|
|
|
userFetchState: {
|
|
|
|
...defaultFetchState
|
2018-09-30 11:37:19 +01:00
|
|
|
},
|
2018-11-07 18:15:27 +00:00
|
|
|
userProfileFetchState: {
|
|
|
|
...defaultFetchState
|
|
|
|
},
|
2019-05-08 23:48:10 +05:30
|
|
|
sessionMeta: { activeDonations: 0 },
|
2018-09-30 11:37:19 +01:00
|
|
|
showDonationModal: false,
|
2020-10-14 13:23:26 +03:00
|
|
|
isOnline: true,
|
2021-10-06 15:18:02 +02:00
|
|
|
isServerOnline: true,
|
2020-10-14 13:23:26 +03:00
|
|
|
donationFormState: {
|
|
|
|
...defaultDonationFormState
|
|
|
|
}
|
2018-08-23 16:29:26 +01:00
|
|
|
};
|
|
|
|
|
2018-11-07 18:15:27 +00:00
|
|
|
export const epics = [hardGoToEpic, failedUpdatesEpic, updateCompleteEpic];
|
2018-09-30 11:37:19 +01:00
|
|
|
|
2018-08-25 00:24:19 +01:00
|
|
|
export const sagas = [
|
2021-08-02 15:39:40 +02:00
|
|
|
...createAcceptTermsSaga(actionTypes),
|
|
|
|
...createAppMountSaga(actionTypes),
|
|
|
|
...createDonationSaga(actionTypes),
|
|
|
|
...createGaSaga(actionTypes),
|
|
|
|
...createFetchUserSaga(actionTypes),
|
|
|
|
...createShowCertSaga(actionTypes),
|
2021-10-13 11:00:00 +02:00
|
|
|
...createReportUserSaga(actionTypes)
|
2018-08-25 00:24:19 +01:00
|
|
|
];
|
2018-08-23 16:29:26 +01:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export const appMount = createAction(actionTypes.appMount);
|
2018-08-23 16:29:26 +01:00
|
|
|
|
2019-12-02 15:48:53 +03:00
|
|
|
export const tryToShowDonationModal = createAction(
|
2021-08-02 15:39:40 +02:00
|
|
|
actionTypes.tryToShowDonationModal
|
2019-12-02 15:48:53 +03:00
|
|
|
);
|
2020-02-04 08:43:56 +03:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export const executeGA = createAction(actionTypes.executeGA);
|
2020-02-04 08:43:56 +03:00
|
|
|
|
2019-12-09 17:30:24 +01:00
|
|
|
export const allowBlockDonationRequests = createAction(
|
2021-08-02 15:39:40 +02:00
|
|
|
actionTypes.allowBlockDonationRequests
|
2019-12-09 17:30:24 +01:00
|
|
|
);
|
2021-08-02 15:39:40 +02:00
|
|
|
export const closeDonationModal = createAction(actionTypes.closeDonationModal);
|
|
|
|
export const openDonationModal = createAction(actionTypes.openDonationModal);
|
2019-12-09 17:30:24 +01:00
|
|
|
export const preventBlockDonationRequests = createAction(
|
2021-08-02 15:39:40 +02:00
|
|
|
actionTypes.preventBlockDonationRequests
|
2019-12-09 17:30:24 +01:00
|
|
|
);
|
|
|
|
export const preventProgressDonationRequests = createAction(
|
2021-08-02 15:39:40 +02:00
|
|
|
actionTypes.preventProgressDonationRequests
|
2019-12-02 15:48:53 +03:00
|
|
|
);
|
2020-10-14 13:23:26 +03:00
|
|
|
export const updateDonationFormState = createAction(
|
2021-08-02 15:39:40 +02:00
|
|
|
actionTypes.updateDonationFormState
|
2020-10-14 13:23:26 +03:00
|
|
|
);
|
2018-09-30 11:37:19 +01:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export const onlineStatusChange = createAction(actionTypes.onlineStatusChange);
|
2021-10-06 15:18:02 +02:00
|
|
|
export const serverStatusChange = createAction(actionTypes.serverStatusChange);
|
2018-09-30 11:37:19 +01:00
|
|
|
|
2020-03-06 17:51:58 +01:00
|
|
|
// TODO: re-evaluate this since /internal is no longer used.
|
2018-10-24 00:24:48 +01:00
|
|
|
// `hardGoTo` is used to hit the API server directly
|
|
|
|
// without going through /internal
|
|
|
|
// used for things like /signin and /signout
|
2021-08-02 15:39:40 +02:00
|
|
|
export const hardGoTo = createAction(actionTypes.hardGoTo);
|
2018-10-24 00:24:48 +01:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export const submitComplete = createAction(actionTypes.submitComplete);
|
|
|
|
export const updateComplete = createAction(actionTypes.updateComplete);
|
|
|
|
export const updateFailed = createAction(actionTypes.updateFailed);
|
2018-09-30 11:37:19 +01:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export const acceptTerms = createAction(actionTypes.acceptTerms);
|
|
|
|
export const acceptTermsComplete = createAction(
|
|
|
|
actionTypes.acceptTermsComplete
|
|
|
|
);
|
|
|
|
export const acceptTermsError = createAction(actionTypes.acceptTermsError);
|
2018-08-25 00:24:19 +01:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export const fetchUser = createAction(actionTypes.fetchUser);
|
|
|
|
export const fetchUserComplete = createAction(actionTypes.fetchUserComplete);
|
|
|
|
export const fetchUserError = createAction(actionTypes.fetchUserError);
|
2018-08-30 15:27:53 +01:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export const addDonation = createAction(actionTypes.addDonation);
|
|
|
|
export const addDonationComplete = createAction(
|
|
|
|
actionTypes.addDonationComplete
|
|
|
|
);
|
|
|
|
export const addDonationError = createAction(actionTypes.addDonationError);
|
2020-10-14 13:23:26 +03:00
|
|
|
|
2021-08-08 23:22:25 +03:00
|
|
|
export const postChargeStripe = createAction(actionTypes.postChargeStripe);
|
|
|
|
export const postChargeStripeComplete = createAction(
|
|
|
|
actionTypes.postChargeStripeComplete
|
|
|
|
);
|
|
|
|
export const postChargeStripeError = createAction(
|
|
|
|
actionTypes.postChargeStripeError
|
|
|
|
);
|
2021-09-17 22:15:56 +03:00
|
|
|
export const postChargeStripeCard = createAction(
|
|
|
|
actionTypes.postChargeStripeCard
|
|
|
|
);
|
|
|
|
export const postChargeStripeCardComplete = createAction(
|
|
|
|
actionTypes.postChargeStripeCardComplete
|
|
|
|
);
|
|
|
|
export const postChargeStripeCardError = createAction(
|
|
|
|
actionTypes.postChargeStripeCardError
|
|
|
|
);
|
2021-08-08 23:22:25 +03:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export const fetchProfileForUser = createAction(
|
|
|
|
actionTypes.fetchProfileForUser
|
|
|
|
);
|
2018-11-07 18:15:27 +00:00
|
|
|
export const fetchProfileForUserComplete = createAction(
|
2021-08-02 15:39:40 +02:00
|
|
|
actionTypes.fetchProfileForUserComplete
|
2018-11-07 18:15:27 +00:00
|
|
|
);
|
|
|
|
export const fetchProfileForUserError = createAction(
|
2021-08-02 15:39:40 +02:00
|
|
|
actionTypes.fetchProfileForUserError
|
2018-11-07 18:15:27 +00:00
|
|
|
);
|
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export const reportUser = createAction(actionTypes.reportUser);
|
|
|
|
export const reportUserComplete = createAction(actionTypes.reportUserComplete);
|
|
|
|
export const reportUserError = createAction(actionTypes.reportUserError);
|
2018-09-07 13:32:38 +01:00
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export const resetUserData = createAction(actionTypes.resetUserData);
|
2019-02-26 22:24:08 +05:30
|
|
|
|
2021-08-02 15:39:40 +02:00
|
|
|
export const showCert = createAction(actionTypes.showCert);
|
|
|
|
export const showCertComplete = createAction(actionTypes.showCertComplete);
|
|
|
|
export const showCertError = createAction(actionTypes.showCertError);
|
2018-09-04 14:54:23 +01:00
|
|
|
|
2019-08-30 19:15:26 +02:00
|
|
|
export const updateCurrentChallengeId = createAction(
|
2021-08-02 15:39:40 +02:00
|
|
|
actionTypes.updateCurrentChallengeId
|
2019-08-30 19:15:26 +02:00
|
|
|
);
|
|
|
|
|
2018-09-30 11:37:19 +01:00
|
|
|
export const completedChallengesSelector = state =>
|
|
|
|
userSelector(state).completedChallenges || [];
|
|
|
|
export const completionCountSelector = state => state[ns].completionCount;
|
2019-08-30 19:15:26 +02:00
|
|
|
export const currentChallengeIdSelector = state => state[ns].currentChallengeId;
|
2021-07-15 15:51:27 +01:00
|
|
|
export const stepsToClaimSelector = state => {
|
|
|
|
const user = userSelector(state);
|
|
|
|
const currentCerts = certificatesByNameSelector(user.username)(
|
|
|
|
state
|
|
|
|
).currentCerts;
|
|
|
|
return {
|
|
|
|
currentCerts: currentCerts,
|
|
|
|
isHonest: user?.isHonest,
|
|
|
|
isShowName: user?.profileUI?.showName,
|
|
|
|
isShowCerts: user?.profileUI?.showCerts,
|
|
|
|
isShowProfile: !user?.profileUI?.isLocked
|
|
|
|
};
|
|
|
|
};
|
2019-12-02 15:48:53 +03:00
|
|
|
export const isDonatingSelector = state => userSelector(state).isDonating;
|
2018-09-30 11:37:19 +01:00
|
|
|
export const isOnlineSelector = state => state[ns].isOnline;
|
2021-10-06 15:18:02 +02:00
|
|
|
export const isServerOnlineSelector = state => state[ns].isServerOnline;
|
2018-09-30 11:37:19 +01:00
|
|
|
export const isSignedInSelector = state => !!state[ns].appUsername;
|
|
|
|
export const isDonationModalOpenSelector = state => state[ns].showDonationModal;
|
2021-02-08 10:28:36 +03:00
|
|
|
export const recentlyClaimedBlockSelector = state =>
|
|
|
|
state[ns].recentlyClaimedBlock;
|
2020-10-14 13:23:26 +03:00
|
|
|
export const donationFormStateSelector = state => state[ns].donationFormState;
|
2018-09-13 18:28:23 +01:00
|
|
|
export const signInLoadingSelector = state =>
|
|
|
|
userFetchStateSelector(state).pending;
|
2018-09-04 14:54:23 +01:00
|
|
|
export const showCertSelector = state => state[ns].showCert;
|
|
|
|
export const showCertFetchStateSelector = state => state[ns].showCertFetchState;
|
2019-12-09 17:30:24 +01:00
|
|
|
export const shouldRequestDonationSelector = state => {
|
|
|
|
const completedChallenges = completedChallengesSelector(state);
|
|
|
|
const completionCount = completionCountSelector(state);
|
|
|
|
const canRequestProgressDonation = state[ns].canRequestProgressDonation;
|
|
|
|
const isDonating = isDonatingSelector(state);
|
2021-02-08 10:28:36 +03:00
|
|
|
const recentlyClaimedBlock = recentlyClaimedBlockSelector(state);
|
2019-12-09 17:30:24 +01:00
|
|
|
|
|
|
|
// don't request donation if already donating
|
|
|
|
if (isDonating) return false;
|
|
|
|
|
|
|
|
// a block has been completed
|
2021-02-08 10:28:36 +03:00
|
|
|
if (recentlyClaimedBlock) return true;
|
2019-12-09 17:30:24 +01:00
|
|
|
|
|
|
|
// a donation has already been requested
|
|
|
|
if (!canRequestProgressDonation) return false;
|
|
|
|
|
|
|
|
// donations only appear after the user has completed ten challenges (i.e.
|
|
|
|
// not before the 11th challenge has mounted)
|
|
|
|
if (completedChallenges.length < 10) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// this will mean we have completed 3 or more challenges this browser session
|
|
|
|
// and enough challenges overall to not be new
|
|
|
|
return completionCount >= 3;
|
|
|
|
};
|
2019-12-06 08:43:23 +03:00
|
|
|
|
2018-09-04 14:54:23 +01:00
|
|
|
export const userByNameSelector = username => state => {
|
|
|
|
const { user } = state[ns];
|
2021-10-07 03:05:05 +08:00
|
|
|
// return initial state empty user empty object instead of empty
|
|
|
|
// object litteral to prevent components from re-rendering unnecessarily
|
|
|
|
return user[username] ?? initialState.user;
|
2018-09-04 14:54:23 +01:00
|
|
|
};
|
2020-01-03 07:02:31 +01:00
|
|
|
|
|
|
|
export const certificatesByNameSelector = username => state => {
|
|
|
|
const {
|
|
|
|
isRespWebDesignCert,
|
|
|
|
is2018DataVisCert,
|
|
|
|
isFrontEndLibsCert,
|
|
|
|
isJsAlgoDataStructCert,
|
|
|
|
isApisMicroservicesCert,
|
|
|
|
isInfosecQaCert,
|
2020-06-18 00:00:31 +09:00
|
|
|
isQaCertV7,
|
|
|
|
isInfosecCertV7,
|
2020-01-03 07:02:31 +01:00
|
|
|
isFrontEndCert,
|
|
|
|
isBackEndCert,
|
|
|
|
isDataVisCert,
|
2020-02-25 00:10:32 +05:30
|
|
|
isFullStackCert,
|
2020-06-18 00:00:31 +09:00
|
|
|
isSciCompPyCertV7,
|
|
|
|
isDataAnalysisPyCertV7,
|
2021-06-15 10:37:13 -05:00
|
|
|
isMachineLearningPyCertV7,
|
|
|
|
isRelationalDatabasesCertV8
|
2020-01-03 07:02:31 +01:00
|
|
|
} = userByNameSelector(username)(state);
|
|
|
|
return {
|
|
|
|
hasModernCert:
|
|
|
|
isRespWebDesignCert ||
|
|
|
|
is2018DataVisCert ||
|
|
|
|
isFrontEndLibsCert ||
|
|
|
|
isJsAlgoDataStructCert ||
|
|
|
|
isApisMicroservicesCert ||
|
2020-06-18 00:00:31 +09:00
|
|
|
isQaCertV7 ||
|
|
|
|
isInfosecCertV7 ||
|
2020-02-25 00:10:32 +05:30
|
|
|
isFullStackCert ||
|
2020-06-18 00:00:31 +09:00
|
|
|
isSciCompPyCertV7 ||
|
|
|
|
isDataAnalysisPyCertV7 ||
|
2021-06-15 10:37:13 -05:00
|
|
|
isMachineLearningPyCertV7 ||
|
|
|
|
isRelationalDatabasesCertV8,
|
2020-04-23 09:08:50 -04:00
|
|
|
hasLegacyCert:
|
|
|
|
isFrontEndCert || isBackEndCert || isDataVisCert || isInfosecQaCert,
|
2020-06-16 01:21:30 +09:00
|
|
|
isFullStackCert,
|
2020-01-03 07:02:31 +01:00
|
|
|
currentCerts: [
|
|
|
|
{
|
|
|
|
show: isRespWebDesignCert,
|
|
|
|
title: 'Responsive Web Design Certification',
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'responsive-web-design'
|
2020-01-03 07:02:31 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
show: isJsAlgoDataStructCert,
|
|
|
|
title: 'JavaScript Algorithms and Data Structures Certification',
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'javascript-algorithms-and-data-structures'
|
2020-01-03 07:02:31 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
show: isFrontEndLibsCert,
|
2021-08-14 03:57:13 +01:00
|
|
|
title: 'Front End Development Libraries Certification',
|
|
|
|
certSlug: 'front-end-development-libraries'
|
2020-01-03 07:02:31 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
show: is2018DataVisCert,
|
|
|
|
title: 'Data Visualization Certification',
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'data-visualization'
|
2020-01-03 07:02:31 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
show: isApisMicroservicesCert,
|
2021-08-14 03:57:13 +01:00
|
|
|
title: 'Back End Development and APIs Certification',
|
|
|
|
certSlug: 'back-end-development-and-apis'
|
2020-01-03 07:02:31 +01:00
|
|
|
},
|
2020-04-06 14:49:56 -04:00
|
|
|
{
|
2020-06-18 00:00:31 +09:00
|
|
|
show: isQaCertV7,
|
2020-04-06 14:49:56 -04:00
|
|
|
title: ' Quality Assurance Certification',
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'quality-assurance-v7'
|
2020-04-06 14:49:56 -04:00
|
|
|
},
|
|
|
|
{
|
2020-06-18 00:00:31 +09:00
|
|
|
show: isInfosecCertV7,
|
2020-04-06 14:49:56 -04:00
|
|
|
title: 'Information Security Certification',
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'information-security-v7'
|
2020-04-06 14:49:56 -04:00
|
|
|
},
|
2020-02-25 00:10:32 +05:30
|
|
|
{
|
2020-06-18 00:00:31 +09:00
|
|
|
show: isSciCompPyCertV7,
|
2020-02-25 00:10:32 +05:30
|
|
|
title: 'Scientific Computing with Python Certification',
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'scientific-computing-with-python-v7'
|
2020-02-25 00:10:32 +05:30
|
|
|
},
|
|
|
|
{
|
2020-06-18 00:00:31 +09:00
|
|
|
show: isDataAnalysisPyCertV7,
|
2020-02-25 00:10:32 +05:30
|
|
|
title: 'Data Analysis with Python Certification',
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'data-analysis-with-python-v7'
|
2020-02-25 00:10:32 +05:30
|
|
|
},
|
|
|
|
{
|
2020-06-18 00:00:31 +09:00
|
|
|
show: isMachineLearningPyCertV7,
|
2020-02-25 00:10:32 +05:30
|
|
|
title: 'Machine Learning with Python Certification',
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'machine-learning-with-python-v7'
|
2021-06-15 10:37:13 -05:00
|
|
|
},
|
|
|
|
{
|
|
|
|
show: isRelationalDatabasesCertV8,
|
|
|
|
title: 'Relational Databases Certification',
|
|
|
|
certSlug: 'relational-databases-v8'
|
2020-01-03 07:02:31 +01:00
|
|
|
}
|
|
|
|
],
|
|
|
|
legacyCerts: [
|
|
|
|
{
|
|
|
|
show: isFrontEndCert,
|
|
|
|
title: 'Front End Certification',
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'legacy-front-end'
|
2020-01-03 07:02:31 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
show: isBackEndCert,
|
|
|
|
title: 'Back End Certification',
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'legacy-back-end'
|
2020-01-03 07:02:31 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
show: isDataVisCert,
|
|
|
|
title: 'Data Visualization Certification',
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'legacy-data-visualization'
|
2020-04-23 09:08:50 -04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
show: isInfosecQaCert,
|
|
|
|
title: 'Information Security and Quality Assurance Certification',
|
2020-06-16 01:21:30 +09:00
|
|
|
// Keep the current public profile cert slug
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'information-security-and-quality-assurance'
|
2020-06-16 01:21:30 +09:00
|
|
|
},
|
|
|
|
{
|
|
|
|
show: isFullStackCert,
|
|
|
|
title: 'Full Stack Certification',
|
|
|
|
// Keep the current public profile cert slug
|
2021-04-23 20:29:17 +01:00
|
|
|
certSlug: 'full-stack'
|
2020-01-03 07:02:31 +01:00
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2018-09-04 14:54:23 +01:00
|
|
|
export const userFetchStateSelector = state => state[ns].userFetchState;
|
2018-11-07 18:15:27 +00:00
|
|
|
export const userProfileFetchStateSelector = state =>
|
|
|
|
state[ns].userProfileFetchState;
|
2018-08-23 16:29:26 +01:00
|
|
|
export const usernameSelector = state => state[ns].appUsername;
|
2018-09-13 18:28:23 +01:00
|
|
|
export const userSelector = state => {
|
|
|
|
const username = usernameSelector(state);
|
|
|
|
|
|
|
|
return state[ns].user[username] || {};
|
|
|
|
};
|
2018-08-23 16:29:26 +01:00
|
|
|
|
2018-11-29 14:24:17 +00:00
|
|
|
export const sessionMetaSelector = state => state[ns].sessionMeta;
|
|
|
|
|
2018-09-20 10:22:45 +01:00
|
|
|
function spreadThePayloadOnUser(state, payload) {
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
user: {
|
|
|
|
...state.user,
|
|
|
|
[state.appUsername]: {
|
|
|
|
...state.user[state.appUsername],
|
|
|
|
...payload
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-08-23 16:29:26 +01:00
|
|
|
export const reducer = handleActions(
|
|
|
|
{
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.acceptTermsComplete]: (state, { payload }) => {
|
2020-07-29 19:09:20 +02:00
|
|
|
const { appUsername } = state;
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
user: {
|
|
|
|
...state.user,
|
|
|
|
[appUsername]: {
|
|
|
|
...state.user[appUsername],
|
|
|
|
// TODO: the user accepts the privacy terms in practice during auth
|
|
|
|
// however, it's currently being used to track if they've accepted
|
|
|
|
// or rejected the newsletter. Ideally this should be migrated,
|
|
|
|
// since they can't sign up without accepting the terms.
|
|
|
|
acceptedPrivacyTerms: true,
|
|
|
|
sendQuincyEmail:
|
|
|
|
payload === null
|
|
|
|
? state.user[appUsername].sendQuincyEmail
|
|
|
|
: payload
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.allowBlockDonationRequests]: (state, { payload }) => {
|
2021-02-08 10:28:36 +03:00
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
recentlyClaimedBlock: payload
|
|
|
|
};
|
|
|
|
},
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.updateDonationFormState]: (state, { payload }) => ({
|
2020-10-14 13:23:26 +03:00
|
|
|
...state,
|
|
|
|
donationFormState: { ...state.donationFormState, ...payload }
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.addDonation]: state => ({
|
2020-10-14 13:23:26 +03:00
|
|
|
...state,
|
|
|
|
donationFormState: { ...defaultDonationFormState, processing: true }
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.addDonationComplete]: state => {
|
2020-10-14 13:23:26 +03:00
|
|
|
const { appUsername } = state;
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
user: {
|
|
|
|
...state.user,
|
|
|
|
[appUsername]: {
|
|
|
|
...state.user[appUsername],
|
|
|
|
isDonating: true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
donationFormState: { ...defaultDonationFormState, success: true }
|
|
|
|
};
|
|
|
|
},
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.addDonationError]: (state, { payload }) => ({
|
2020-10-14 13:23:26 +03:00
|
|
|
...state,
|
|
|
|
donationFormState: { ...defaultDonationFormState, error: payload }
|
|
|
|
}),
|
2021-08-08 23:22:25 +03:00
|
|
|
[actionTypes.postChargeStripe]: state => ({
|
|
|
|
...state,
|
|
|
|
donationFormState: { ...defaultDonationFormState, processing: true }
|
|
|
|
}),
|
|
|
|
[actionTypes.postChargeStripeComplete]: state => {
|
|
|
|
const { appUsername } = state;
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
user: {
|
|
|
|
...state.user,
|
|
|
|
[appUsername]: {
|
|
|
|
...state.user[appUsername],
|
|
|
|
isDonating: true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
donationFormState: { ...defaultDonationFormState, success: true }
|
|
|
|
};
|
|
|
|
},
|
|
|
|
[actionTypes.postChargeStripeError]: (state, { payload }) => ({
|
|
|
|
...state,
|
|
|
|
donationFormState: { ...defaultDonationFormState, error: payload }
|
|
|
|
}),
|
2021-09-17 22:15:56 +03:00
|
|
|
[actionTypes.postChargeStripeCard]: state => ({
|
|
|
|
...state,
|
|
|
|
donationFormState: { ...defaultDonationFormState, processing: true }
|
|
|
|
}),
|
|
|
|
[actionTypes.postChargeStripeCardComplete]: state => {
|
|
|
|
const { appUsername } = state;
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
user: {
|
|
|
|
...state.user,
|
|
|
|
[appUsername]: {
|
|
|
|
...state.user[appUsername],
|
|
|
|
isDonating: true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
donationFormState: { ...defaultDonationFormState, success: true }
|
|
|
|
};
|
|
|
|
},
|
|
|
|
[actionTypes.postChargeStripeCardError]: (state, { payload }) => ({
|
|
|
|
...state,
|
|
|
|
donationFormState: { ...defaultDonationFormState, error: payload }
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.fetchUser]: state => ({
|
2018-08-23 16:29:26 +01:00
|
|
|
...state,
|
2018-09-04 14:54:23 +01:00
|
|
|
userFetchState: { ...defaultFetchState }
|
2018-08-23 16:29:26 +01:00
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.fetchProfileForUser]: state => ({
|
2018-11-07 18:15:27 +00:00
|
|
|
...state,
|
|
|
|
userProfileFetchState: { ...defaultFetchState }
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.fetchUserComplete]: (
|
2018-11-29 14:24:17 +00:00
|
|
|
state,
|
|
|
|
{ payload: { user, username, sessionMeta } }
|
|
|
|
) => ({
|
2018-08-23 16:29:26 +01:00
|
|
|
...state,
|
2018-09-13 18:28:23 +01:00
|
|
|
user: {
|
|
|
|
...state.user,
|
2018-11-07 18:15:27 +00:00
|
|
|
[username]: { ...user, sessionUser: true }
|
2018-09-13 18:28:23 +01:00
|
|
|
},
|
2018-08-23 16:29:26 +01:00
|
|
|
appUsername: username,
|
2019-08-30 19:15:26 +02:00
|
|
|
currentChallengeId: user.currentChallengeId,
|
2018-09-04 14:54:23 +01:00
|
|
|
userFetchState: {
|
2018-08-23 16:29:26 +01:00
|
|
|
pending: false,
|
|
|
|
complete: true,
|
|
|
|
errored: false,
|
|
|
|
error: null
|
2018-11-29 14:24:17 +00:00
|
|
|
},
|
|
|
|
sessionMeta: {
|
|
|
|
...state.sessionMeta,
|
|
|
|
...sessionMeta
|
2018-08-23 16:29:26 +01:00
|
|
|
}
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.fetchUserError]: (state, { payload }) => ({
|
2018-08-23 16:29:26 +01:00
|
|
|
...state,
|
2018-09-04 14:54:23 +01:00
|
|
|
userFetchState: {
|
|
|
|
pending: false,
|
|
|
|
complete: false,
|
|
|
|
errored: true,
|
|
|
|
error: payload
|
|
|
|
}
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.fetchProfileForUserComplete]: (
|
2018-11-07 18:15:27 +00:00
|
|
|
state,
|
|
|
|
{ payload: { user, username } }
|
|
|
|
) => {
|
|
|
|
const previousUserObject =
|
|
|
|
username in state.user ? state.user[username] : {};
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
user: {
|
|
|
|
...state.user,
|
|
|
|
[username]: { ...previousUserObject, ...user }
|
|
|
|
},
|
|
|
|
userProfileFetchState: {
|
2018-11-29 12:12:15 +00:00
|
|
|
...defaultFetchState,
|
2018-11-07 18:15:27 +00:00
|
|
|
pending: false,
|
2018-11-29 12:12:15 +00:00
|
|
|
complete: true
|
2018-11-07 18:15:27 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.fetchProfileForUserError]: (state, { payload }) => ({
|
2018-11-07 18:15:27 +00:00
|
|
|
...state,
|
2018-11-29 12:12:15 +00:00
|
|
|
userProfileFetchState: {
|
2018-11-07 18:15:27 +00:00
|
|
|
pending: false,
|
|
|
|
complete: false,
|
|
|
|
errored: true,
|
|
|
|
error: payload
|
|
|
|
}
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.onlineStatusChange]: (state, { payload: isOnline }) => ({
|
2018-09-30 11:37:19 +01:00
|
|
|
...state,
|
|
|
|
isOnline
|
|
|
|
}),
|
2021-10-06 15:18:02 +02:00
|
|
|
[actionTypes.serverStatusChange]: (state, { payload: isServerOnline }) => ({
|
|
|
|
...state,
|
|
|
|
isServerOnline
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.closeDonationModal]: state => ({
|
2019-01-31 23:40:23 +05:30
|
|
|
...state,
|
|
|
|
showDonationModal: false
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.openDonationModal]: state => ({
|
2019-12-09 17:30:24 +01:00
|
|
|
...state,
|
2021-02-08 10:28:36 +03:00
|
|
|
showDonationModal: true
|
2019-12-09 17:30:24 +01:00
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.preventBlockDonationRequests]: state => ({
|
2019-02-07 02:39:32 +05:30
|
|
|
...state,
|
2021-02-08 10:28:36 +03:00
|
|
|
recentlyClaimedBlock: null
|
2019-02-07 02:39:32 +05:30
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.preventProgressDonationRequests]: state => ({
|
2019-08-22 03:29:13 -04:00
|
|
|
...state,
|
2019-12-09 17:30:24 +01:00
|
|
|
canRequestProgressDonation: false
|
2019-08-22 03:29:13 -04:00
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.resetUserData]: state => ({
|
2019-02-26 22:24:08 +05:30
|
|
|
...state,
|
|
|
|
appUsername: '',
|
|
|
|
user: {}
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.showCert]: state => ({
|
2018-09-04 14:54:23 +01:00
|
|
|
...state,
|
|
|
|
showCert: {},
|
|
|
|
showCertFetchState: { ...defaultFetchState }
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.showCertComplete]: (state, { payload }) => ({
|
2018-09-04 14:54:23 +01:00
|
|
|
...state,
|
|
|
|
showCert: payload,
|
|
|
|
showCertFetchState: {
|
2018-11-29 12:12:15 +00:00
|
|
|
...defaultFetchState,
|
2018-09-04 14:54:23 +01:00
|
|
|
pending: false,
|
2018-11-29 12:12:15 +00:00
|
|
|
complete: true
|
2018-09-04 14:54:23 +01:00
|
|
|
}
|
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.showCertError]: (state, { payload }) => ({
|
2018-09-04 14:54:23 +01:00
|
|
|
...state,
|
|
|
|
showCert: {},
|
|
|
|
showCertFetchState: {
|
2018-08-23 16:29:26 +01:00
|
|
|
pending: false,
|
|
|
|
complete: false,
|
|
|
|
errored: true,
|
|
|
|
error: payload
|
|
|
|
}
|
2018-09-13 18:28:23 +01:00
|
|
|
}),
|
2021-08-02 15:39:40 +02:00
|
|
|
[actionTypes.submitComplete]: (state, { payload }) => {
|
2020-06-10 08:54:19 +02:00
|
|
|
let submittedchallenges = [{ ...payload, completedDate: Date.now() }];
|
|
|
|
if (payload.challArray) {
|
|
|
|
submittedchallenges = payload.challArray;
|
2019-03-26 17:54:18 +03:00
|
|
|
}
|
|
|
|
const { appUsername } = state;
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
completionCount: state.completionCount + 1,
|
|
|
|
user: {
|
|
|
|
...state.user,
|
|
|
|
[appUsername]: {
|
|
|
|
...state.user[appUsername],
|
|
|
|
completedChallenges: uniqBy(
|
|
|
|
[
|
2019-10-17 22:51:08 +02:00
|
|
|
...submittedchallenges,
|
2019-03-26 17:54:18 +03:00
|
|
|
...state.user[appUsername].completedChallenges
|
|
|
|
],
|
|
|
|
'id'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
2019-08-30 19:15:26 +02:00
|
|
|
[challengeTypes.challengeMounted]: (state, { payload }) => ({
|
|
|
|
...state,
|
|
|
|
currentChallengeId: payload
|
|
|
|
}),
|
2019-03-28 11:18:26 +03:00
|
|
|
[settingsTypes.updateLegacyCertComplete]: (state, { payload }) => {
|
2018-09-30 11:37:19 +01:00
|
|
|
const { appUsername } = state;
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
completionCount: state.completionCount + 1,
|
|
|
|
user: {
|
|
|
|
...state.user,
|
|
|
|
[appUsername]: {
|
|
|
|
...state.user[appUsername],
|
|
|
|
completedChallenges: uniqBy(
|
2019-03-26 17:54:18 +03:00
|
|
|
[...state.user[appUsername].completedChallenges, payload],
|
2018-09-30 11:37:19 +01:00
|
|
|
'id'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
2018-09-13 18:28:23 +01:00
|
|
|
[settingsTypes.submitNewUsernameComplete]: (state, { payload }) =>
|
|
|
|
payload
|
|
|
|
? {
|
|
|
|
...state,
|
|
|
|
user: {
|
|
|
|
...state.user,
|
|
|
|
[state.appUsername]: {
|
|
|
|
...state.user[state.appUsername],
|
|
|
|
username: payload
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-09-14 13:18:31 +01:00
|
|
|
: state,
|
2018-09-14 14:00:43 +01:00
|
|
|
[settingsTypes.submitNewAboutComplete]: (state, { payload }) =>
|
2018-09-20 10:22:45 +01:00
|
|
|
payload ? spreadThePayloadOnUser(state, payload) : state,
|
|
|
|
[settingsTypes.updateMyEmailComplete]: (state, { payload }) =>
|
|
|
|
payload ? spreadThePayloadOnUser(state, payload) : state,
|
2018-09-14 14:00:43 +01:00
|
|
|
[settingsTypes.updateUserFlagComplete]: (state, { payload }) =>
|
2018-09-25 12:51:17 +01:00
|
|
|
payload ? spreadThePayloadOnUser(state, payload) : state,
|
|
|
|
[settingsTypes.verifyCertComplete]: (state, { payload }) =>
|
2019-10-09 20:31:20 +02:00
|
|
|
payload ? spreadThePayloadOnUser(state, payload) : state,
|
|
|
|
[settingsTypes.submitProfileUIComplete]: (state, { payload }) =>
|
|
|
|
payload
|
|
|
|
? {
|
|
|
|
...state,
|
|
|
|
user: {
|
|
|
|
...state.user,
|
|
|
|
[state.appUsername]: {
|
|
|
|
...state.user[state.appUsername],
|
|
|
|
profileUI: { ...payload }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
: state
|
2018-08-23 16:29:26 +01:00
|
|
|
},
|
|
|
|
initialState
|
|
|
|
);
|