feat(client): improve SuperBlock cert claiming UX (#41147)

* feat(client): improve SuperBlock cert claiming UX

* broken: add certCard foundation

* broken: add TODO comments for scatter-brain

* restructure stepsToClaimSelector

* add api-server verifyCanClaimCert logic

* temp: correct verifyCanClaim URL

* move GET logic to CertificationCard, remove console.logs

* add error handling, and navigation logic

* correct verification logical flow

* fix completion-epic updates, fix cert verify

* update widget to button, disable button unless verified

* working: refactor CertChallenge with hook state

* add StepsType

* update Honesty snapshot

* add DonationModal to SuperBlockIntro

* disable Claim Cert button unless also isHonest

* prevent warning when viewing cert

* test: use navigate in Modal to return to hash

* test: replace gatsby.navigate with reach/router.navigate

* add propTypes

* fix: rename propTypes -> prop-types

* use react-scrollable-anchor to squash modal bug

* update location parser type

* open-source Oliver's suggestion

* fix superblock title

* add claim-cert-from-learn tests

* use larger tests

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* fix some cypress stuff

* fix ShowCertification cypress test

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Shaun Hamilton
2021-07-15 15:51:27 +01:00
committed by GitHub
parent 5a52c229f5
commit 6ca6d9950c
17 changed files with 634 additions and 253 deletions

View File

@ -19,7 +19,8 @@ import {
certTypeTitleMap,
certTypeIdMap,
certIds,
oldDataVizId
oldDataVizId,
superBlockCertTypeMap
} from '../../../../config/certification-settings';
const {
@ -49,9 +50,11 @@ export default function bootCertificate(app) {
const certTypeIds = createCertTypeIds(getChallenges());
const showCert = createShowCert(app);
const verifyCert = createVerifyCert(certTypeIds, app);
const verifyCanClaimCert = createVerifyCanClaim(certTypeIds, app);
api.put('/certificate/verify', ifNoUser401, ifNoSuperBlock404, verifyCert);
api.get('/certificate/showCert/:username/:certSlug', showCert);
api.get('/certificate/verify-can-claim-cert', verifyCanClaimCert);
app.use(api);
}
@ -494,3 +497,76 @@ function createShowCert(app) {
}, next);
};
}
function createVerifyCanClaim(certTypeIds, app) {
const { User } = app.models;
function findUserByUsername$(username, fields) {
return observeQuery(User, 'findOne', {
where: { username },
fields
});
}
return function verifyCert(req, res, next) {
const { superBlock, username } = req.query;
log(superBlock);
let certType = superBlockCertTypeMap[superBlock];
log(certType);
return findUserByUsername$(username, {
isFrontEndCert: true,
isBackEndCert: true,
isFullStackCert: true,
isRespWebDesignCert: true,
isFrontEndLibsCert: true,
isJsAlgoDataStructCert: true,
isDataVisCert: true,
is2018DataVisCert: true,
isApisMicroservicesCert: true,
isInfosecQaCert: true,
isQaCertV7: true,
isInfosecCertV7: true,
isSciCompPyCertV7: true,
isDataAnalysisPyCertV7: true,
isMachineLearningPyCertV7: true,
username: true,
name: true,
isHonest: true,
completedChallenges: true
}).subscribe(user => {
return Observable.of(certTypeIds[certType])
.flatMap(challenge => {
const certName = certTypeTitleMap[certType];
const { tests = [] } = challenge;
const { isHonest, completedChallenges } = user;
const isProjectsCompleted = canClaim(tests, completedChallenges);
let result = 'incomplete-requirements';
let status = false;
if (isHonest && isProjectsCompleted) {
status = true;
result = 'requirements-met';
} else if (isProjectsCompleted) {
result = 'projects-completed';
} else if (isHonest) {
result = 'is-honest';
}
return Observable.just({
type: 'success',
message: { status, result },
variables: { name: certName }
});
})
.subscribe(message => {
return res.status(200).json({
response: message,
isCertMap: getUserIsCertMap(user),
// send back the completed challenges
// NOTE: we could just send back the latest challenge, but this
// ensures the challenges are synced.
completedChallenges: user.completedChallenges
});
}, next);
});
};
}