feat(full-stack): Full Stack Certification
This commit is contained in:
committed by
mrugesh mohapatra
parent
903e28ee6a
commit
3518ff9e8e
@ -119,6 +119,14 @@ export function projectsSelector(state) {
|
|||||||
]),
|
]),
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
blocks['full-stack-projects'] = {
|
||||||
|
dashedName: 'full-stack',
|
||||||
|
title: 'Full Stack Certification',
|
||||||
|
time: '1800 hours',
|
||||||
|
challenges: [],
|
||||||
|
superBlock: 'full-stack'
|
||||||
|
};
|
||||||
return Object.keys(blocks)
|
return Object.keys(blocks)
|
||||||
.filter(key =>
|
.filter(key =>
|
||||||
key.includes('projects') && !(
|
key.includes('projects') && !(
|
||||||
|
@ -37,34 +37,41 @@ const mapStateToProps = createSelector(
|
|||||||
isFrontEndCert,
|
isFrontEndCert,
|
||||||
isBackEndCert,
|
isBackEndCert,
|
||||||
isDataVisCert,
|
isDataVisCert,
|
||||||
|
isFullStackCert,
|
||||||
username
|
username
|
||||||
},
|
},
|
||||||
projects
|
projects
|
||||||
) => ({
|
) => {
|
||||||
allProjects: projects,
|
let modernProjects = projects.filter(p => !p.superBlock.includes('legacy'));
|
||||||
legacyProjects: projects.filter(p => p.superBlock.includes('legacy')),
|
modernProjects.push(modernProjects.shift());
|
||||||
modernProjects: projects.filter(p => !p.superBlock.includes('legacy')),
|
|
||||||
userProjects: projects
|
return {
|
||||||
.map(block => buildUserProjectsMap(block, completedChallenges))
|
allProjects: projects,
|
||||||
.reduce((projects, current) => ({
|
legacyProjects: projects.filter(p => p.superBlock.includes('legacy')),
|
||||||
...projects,
|
modernProjects: modernProjects,
|
||||||
...current
|
userProjects: projects
|
||||||
}), {}),
|
.map(block => buildUserProjectsMap(block, completedChallenges))
|
||||||
blockNameIsCertMap: {
|
.reduce((projects, current) => ({
|
||||||
'Responsive Web Design Projects': isRespWebDesignCert,
|
...projects,
|
||||||
/* eslint-disable max-len */
|
...current
|
||||||
'JavaScript Algorithms and Data Structures Projects': isJsAlgoDataStructCert,
|
}), {}),
|
||||||
/* eslint-enable max-len */
|
blockNameIsCertMap: {
|
||||||
'Front End Libraries Projects': isFrontEndLibsCert,
|
'Responsive Web Design Projects': isRespWebDesignCert,
|
||||||
'Data Visualization Projects': is2018DataVisCert,
|
/* eslint-disable max-len */
|
||||||
'APIs and Microservices Projects': isApisMicroservicesCert,
|
'JavaScript Algorithms and Data Structures Projects': isJsAlgoDataStructCert,
|
||||||
'Information Security and Quality Assurance Projects': isInfosecQaCert,
|
/* eslint-enable max-len */
|
||||||
'Legacy Front End Projects': isFrontEndCert,
|
'Front End Libraries Projects': isFrontEndLibsCert,
|
||||||
'Legacy Back End Projects': isBackEndCert,
|
'Data Visualization Projects': is2018DataVisCert,
|
||||||
'Legacy Data Visualization Projects': isDataVisCert
|
'APIs and Microservices Projects': isApisMicroservicesCert,
|
||||||
},
|
'Information Security and Quality Assurance Projects': isInfosecQaCert,
|
||||||
username
|
'Full Stack Certification': isFullStackCert,
|
||||||
})
|
'Legacy Front End Projects': isFrontEndCert,
|
||||||
|
'Legacy Back End Projects': isBackEndCert,
|
||||||
|
'Legacy Data Visualization Projects': isDataVisCert
|
||||||
|
},
|
||||||
|
username
|
||||||
|
};
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
@ -178,12 +185,40 @@ class CertificationSettings extends PureComponent {
|
|||||||
.length - 1;
|
.length - 1;
|
||||||
|
|
||||||
const fullForm = completedProjects === challengeTitles.length;
|
const fullForm = completedProjects === challengeTitles.length;
|
||||||
|
|
||||||
|
let isFullStack = superBlock === 'full-stack';
|
||||||
|
let isFullStackClaimable = false;
|
||||||
|
let description = '';
|
||||||
|
if (isFullStack) {
|
||||||
|
isFullStackClaimable = Object.keys(blockNameIsCertMap).every(function(e) {
|
||||||
|
if (e.indexOf('Full Stack') !== -1 || e.indexOf('Legacy') !== -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return blockNameIsCertMap[e];
|
||||||
|
});
|
||||||
|
|
||||||
|
description = (<div>
|
||||||
|
Once you've earned the following freeCodeCamp certifications,
|
||||||
|
you'll be able to claim The Full Stack Developer Certification:
|
||||||
|
<ul>
|
||||||
|
<li>Responsive Web Design</li>
|
||||||
|
<li>Algorithms and Data Structures</li>
|
||||||
|
<li>Front End Libraries</li>
|
||||||
|
<li>Data Visualization</li>
|
||||||
|
<li>APIs and Microservices</li>
|
||||||
|
<li>Information Security and Quality Assurance</li>
|
||||||
|
</ul>
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FullWidthRow key={superBlock}>
|
<FullWidthRow key={superBlock}>
|
||||||
<h3 className='project-heading'>{ projectBlockName }</h3>
|
<h3 className='project-heading'>{ projectBlockName }</h3>
|
||||||
|
{description}
|
||||||
<Form
|
<Form
|
||||||
buttonText={ fullForm ? 'Claim Certification' : 'Save Progress' }
|
buttonText={ fullForm || isFullStack
|
||||||
enableSubmit={ fullForm }
|
? 'Claim Certification' : 'Save Progress' }
|
||||||
|
enableSubmit={ isFullStack ? isFullStackClaimable : fullForm }
|
||||||
formFields={ challengeTitles.concat([ 'id' ]) }
|
formFields={ challengeTitles.concat([ 'id' ]) }
|
||||||
hideButton={isCertClaimed}
|
hideButton={isCertClaimed}
|
||||||
id={ superBlock }
|
id={ superBlock }
|
||||||
|
@ -23,7 +23,8 @@ import {
|
|||||||
jsAlgoDataStructId,
|
jsAlgoDataStructId,
|
||||||
dataVis2018Id,
|
dataVis2018Id,
|
||||||
apisMicroservicesId,
|
apisMicroservicesId,
|
||||||
infosecQaId
|
infosecQaId,
|
||||||
|
fullStackId
|
||||||
} from '../utils/constantStrings.json';
|
} from '../utils/constantStrings.json';
|
||||||
import certTypes from '../utils/certTypes.json';
|
import certTypes from '../utils/certTypes.json';
|
||||||
import superBlockCertTypeMap from '../utils/superBlockCertTypeMap';
|
import superBlockCertTypeMap from '../utils/superBlockCertTypeMap';
|
||||||
@ -59,14 +60,14 @@ const certIds = {
|
|||||||
[certTypes.jsAlgoDataStruct]: jsAlgoDataStructId,
|
[certTypes.jsAlgoDataStruct]: jsAlgoDataStructId,
|
||||||
[certTypes.dataVis2018]: dataVis2018Id,
|
[certTypes.dataVis2018]: dataVis2018Id,
|
||||||
[certTypes.apisMicroservices]: apisMicroservicesId,
|
[certTypes.apisMicroservices]: apisMicroservicesId,
|
||||||
[certTypes.infosecQa]: infosecQaId
|
[certTypes.infosecQa]: infosecQaId,
|
||||||
|
[certTypes.fullStack]: fullStackId
|
||||||
};
|
};
|
||||||
|
|
||||||
const certViews = {
|
const certViews = {
|
||||||
[certTypes.frontEnd]: 'certificate/legacy/front-end.jade',
|
[certTypes.frontEnd]: 'certificate/legacy/front-end.jade',
|
||||||
[certTypes.backEnd]: 'certificate/legacy/back-end.jade',
|
[certTypes.backEnd]: 'certificate/legacy/back-end.jade',
|
||||||
[certTypes.dataVis]: 'certificate/legacy/data-visualization.jade',
|
[certTypes.dataVis]: 'certificate/legacy/data-visualization.jade',
|
||||||
[certTypes.fullStack]: 'certificate/legacy/full-stack.jade',
|
|
||||||
|
|
||||||
[certTypes.respWebDesign]: 'certificate/responsive-web-design.jade',
|
[certTypes.respWebDesign]: 'certificate/responsive-web-design.jade',
|
||||||
[certTypes.frontEndLibs]: 'certificate/front-end-libraries.jade',
|
[certTypes.frontEndLibs]: 'certificate/front-end-libraries.jade',
|
||||||
@ -75,7 +76,8 @@ const certViews = {
|
|||||||
[certTypes.dataVis2018]: 'certificate/data-visualization.jade',
|
[certTypes.dataVis2018]: 'certificate/data-visualization.jade',
|
||||||
[certTypes.apisMicroservices]: 'certificate/apis-and-microservices.jade',
|
[certTypes.apisMicroservices]: 'certificate/apis-and-microservices.jade',
|
||||||
[certTypes.infosecQa]:
|
[certTypes.infosecQa]:
|
||||||
'certificate/information-security-and-quality-assurance.jade'
|
'certificate/information-security-and-quality-assurance.jade',
|
||||||
|
[certTypes.fullStack]: 'certificate/full-stack.jade'
|
||||||
};
|
};
|
||||||
|
|
||||||
const certText = {
|
const certText = {
|
||||||
@ -178,7 +180,8 @@ export default function certificate(app) {
|
|||||||
apisMicroservicesId,
|
apisMicroservicesId,
|
||||||
Challenge
|
Challenge
|
||||||
),
|
),
|
||||||
[certTypes.infosecQa]: getIdsForCert$(infosecQaId, Challenge)
|
[certTypes.infosecQa]: getIdsForCert$(infosecQaId, Challenge),
|
||||||
|
[certTypes.fullStack]: getIdsForCert$(fullStackId, Challenge)
|
||||||
};
|
};
|
||||||
|
|
||||||
const superBlocks = Object.keys(superBlockCertTypeMap);
|
const superBlocks = Object.keys(superBlockCertTypeMap);
|
||||||
@ -207,7 +210,7 @@ export default function certificate(app) {
|
|||||||
router.get(
|
router.get(
|
||||||
'/:username/full-stack-certification',
|
'/:username/full-stack-certification',
|
||||||
(req, res) => res.redirect(
|
(req, res) => res.redirect(
|
||||||
`/certification/${req.params.username}/legacy-full-stack`
|
`/certification/${req.params.username}/full-stack`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -254,39 +257,45 @@ export default function certificate(app) {
|
|||||||
return user.getCompletedChallenges$()
|
return user.getCompletedChallenges$()
|
||||||
.flatMap(() => certTypeIds[certType])
|
.flatMap(() => certTypeIds[certType])
|
||||||
.flatMap(challenge => {
|
.flatMap(challenge => {
|
||||||
const {
|
|
||||||
id,
|
|
||||||
tests,
|
|
||||||
challengeType
|
|
||||||
} = challenge;
|
|
||||||
const certName = certText[certType];
|
const certName = certText[certType];
|
||||||
if (user[certType]) {
|
if (user[certType]) {
|
||||||
return Observable.just(alreadyClaimedMessage(certName));
|
return Observable.just(alreadyClaimedMessage(certName));
|
||||||
}
|
}
|
||||||
if (!user[certType] && !isCertified(tests, user.completedChallenges)) {
|
|
||||||
return Observable.just(notCertifiedMessage(certName));
|
let updateData = {
|
||||||
}
|
$set: {
|
||||||
if (!user.name) {
|
[certType]: true
|
||||||
return Observable.just(noNameMessage);
|
}
|
||||||
}
|
};
|
||||||
const updateData = {
|
|
||||||
$push: {
|
if (challenge) {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
tests,
|
||||||
|
challengeType
|
||||||
|
} = challenge;
|
||||||
|
if (!user[certType] &&
|
||||||
|
!isCertified(tests, user.completedChallenges)) {
|
||||||
|
return Observable.just(notCertifiedMessage(certName));
|
||||||
|
}
|
||||||
|
updateData['$push'] = {
|
||||||
completedChallenges: {
|
completedChallenges: {
|
||||||
id,
|
id,
|
||||||
completedDate: new Date(),
|
completedDate: new Date(),
|
||||||
challengeType
|
challengeType
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
$set: {
|
user.completedChallenges[
|
||||||
[certType]: true
|
user.completedChallenges.length - 1
|
||||||
}
|
] = { id, completedDate: new Date() };
|
||||||
};
|
}
|
||||||
|
|
||||||
|
if (!user.name) {
|
||||||
|
return Observable.just(noNameMessage);
|
||||||
|
}
|
||||||
// set here so sendCertifiedEmail works properly
|
// set here so sendCertifiedEmail works properly
|
||||||
// not used otherwise
|
// not used otherwise
|
||||||
user[certType] = true;
|
user[certType] = true;
|
||||||
user.completedChallenges[
|
|
||||||
user.completedChallenges.length - 1
|
|
||||||
] = { id, completedDate: new Date() };
|
|
||||||
return Observable.combineLatest(
|
return Observable.combineLatest(
|
||||||
// update user data
|
// update user data
|
||||||
user.update$(updateData),
|
user.update$(updateData),
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
"frontEnd": "isFrontEndCert",
|
"frontEnd": "isFrontEndCert",
|
||||||
"backEnd": "isBackEndCert",
|
"backEnd": "isBackEndCert",
|
||||||
"dataVis": "isDataVisCert",
|
"dataVis": "isDataVisCert",
|
||||||
"fullStack": "isFullStackCert",
|
|
||||||
"respWebDesign": "isRespWebDesignCert",
|
"respWebDesign": "isRespWebDesignCert",
|
||||||
"frontEndLibs": "isFrontEndLibsCert",
|
"frontEndLibs": "isFrontEndLibsCert",
|
||||||
"dataVis2018": "is2018DataVisCert",
|
"dataVis2018": "is2018DataVisCert",
|
||||||
"jsAlgoDataStruct": "isJsAlgoDataStructCert",
|
"jsAlgoDataStruct": "isJsAlgoDataStructCert",
|
||||||
"apisMicroservices": "isApisMicroservicesCert",
|
"apisMicroservices": "isApisMicroservicesCert",
|
||||||
"infosecQa": "isInfosecQaCert"
|
"infosecQa": "isInfosecQaCert",
|
||||||
}
|
"fullStack": "isFullStackCert"
|
||||||
|
}
|
||||||
|
@ -10,5 +10,6 @@
|
|||||||
"dataVis2018Id": "5a553ca864b52e1d8bceea14",
|
"dataVis2018Id": "5a553ca864b52e1d8bceea14",
|
||||||
"jsAlgoDataStructId": "561abd10cb81ac38a17513bc",
|
"jsAlgoDataStructId": "561abd10cb81ac38a17513bc",
|
||||||
"apisMicroservicesId": "561add10cb82ac38a17523bc",
|
"apisMicroservicesId": "561add10cb82ac38a17523bc",
|
||||||
"infosecQaId": "561add10cb82ac38a17213bc"
|
"infosecQaId": "561add10cb82ac38a17213bc",
|
||||||
|
"fullStackId": "561add10cb82ac38a17213bd"
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ const superBlockCertTypeMap = {
|
|||||||
'legacy-front-end': certTypes.frontEnd,
|
'legacy-front-end': certTypes.frontEnd,
|
||||||
'legacy-back-end': certTypes.backEnd,
|
'legacy-back-end': certTypes.backEnd,
|
||||||
'legacy-data-visualization': certTypes.dataVis,
|
'legacy-data-visualization': certTypes.dataVis,
|
||||||
'legacy-full-stack': certTypes.fullStack,
|
|
||||||
|
|
||||||
// modern
|
// modern
|
||||||
'responsive-web-design': certTypes.respWebDesign,
|
'responsive-web-design': certTypes.respWebDesign,
|
||||||
@ -13,7 +12,8 @@ const superBlockCertTypeMap = {
|
|||||||
'front-end-libraries': certTypes.frontEndLibs,
|
'front-end-libraries': certTypes.frontEndLibs,
|
||||||
'data-visualization': certTypes.dataVis2018,
|
'data-visualization': certTypes.dataVis2018,
|
||||||
'apis-and-microservices': certTypes.apisMicroservices,
|
'apis-and-microservices': certTypes.apisMicroservices,
|
||||||
'information-security-and-quality-assurance': certTypes.infosecQa
|
'information-security-and-quality-assurance': certTypes.infosecQa,
|
||||||
|
'full-stack': certTypes.fullStack
|
||||||
};
|
};
|
||||||
|
|
||||||
export default superBlockCertTypeMap;
|
export default superBlockCertTypeMap;
|
||||||
|
32
server/views/certificate/full-stack.jade
Normal file
32
server/views/certificate/full-stack.jade
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
meta(name='viewport', content='width=device-width, initial-scale=1')
|
||||||
|
link(rel='stylesheet', href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css')
|
||||||
|
include styles
|
||||||
|
|
||||||
|
.certificate-wrapper.container
|
||||||
|
.row
|
||||||
|
header
|
||||||
|
.col-md-5.col-sm-12
|
||||||
|
.logo
|
||||||
|
img(class='img-responsive', src='https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg', alt="freeCodeCamp's Logo")
|
||||||
|
.col-md-7.col-sm-12
|
||||||
|
.issue-date Issued
|
||||||
|
strong #{date}
|
||||||
|
|
||||||
|
section.information
|
||||||
|
.information-container
|
||||||
|
h3 This certifies that
|
||||||
|
h1
|
||||||
|
strong= name
|
||||||
|
h3 has successfully completed freeCodeCamp's
|
||||||
|
h1
|
||||||
|
strong Full Stack
|
||||||
|
h4 Developer Certification, representing approximately 1800 hours of coursework
|
||||||
|
|
||||||
|
footer
|
||||||
|
.row.signatures
|
||||||
|
img(class='img-responsive', src='https://i.imgur.com/OJFVJKg.png', alt="Quincy Larson's Signature")
|
||||||
|
p
|
||||||
|
strong Quincy Larson
|
||||||
|
p Executive Director, freeCodeCamp.org
|
||||||
|
.row
|
||||||
|
p.verify Verify this certification at: https://www.freecodecamp.org/certification/#{username}/responsive-web-design
|
Reference in New Issue
Block a user