fix(dev): rename superBlock with v7 to certSlug (#41738)
* fix(dev): rename superBlock with v7 to slug * improve name slug -> certSlug * superBlockTitle -> superBlock * correct teeny, tiny mistake * fix: correct slug to certSlug in certLocation * refactor currentCerts * rename showCert cert -> certSlug and various
This commit is contained in:
@ -15,7 +15,7 @@ import { getChallenges } from '../utils/get-curriculum';
|
||||
import {
|
||||
completionHours,
|
||||
certTypes,
|
||||
superBlockCertTypeMap,
|
||||
certSlugTypeMap,
|
||||
certTypeTitleMap,
|
||||
certTypeIdMap,
|
||||
certIds,
|
||||
@ -51,7 +51,7 @@ export default function bootCertificate(app) {
|
||||
const verifyCert = createVerifyCert(certTypeIds, app);
|
||||
|
||||
api.put('/certificate/verify', ifNoUser401, ifNoSuperBlock404, verifyCert);
|
||||
api.get('/certificate/showCert/:username/:cert', showCert);
|
||||
api.get('/certificate/showCert/:username/:certSlug', showCert);
|
||||
|
||||
app.use(api);
|
||||
}
|
||||
@ -66,9 +66,11 @@ export function getFallbackFrontEndDate(completedChallenges, completedDate) {
|
||||
return latestCertDate ? latestCertDate : completedDate;
|
||||
}
|
||||
|
||||
const certSlugs = Object.keys(certSlugTypeMap);
|
||||
|
||||
function ifNoSuperBlock404(req, res, next) {
|
||||
const { superBlock } = req.body;
|
||||
if (superBlock && superBlocks.includes(superBlock)) {
|
||||
const { certSlug } = req.body;
|
||||
if (certSlug && certSlugs.includes(certSlug)) {
|
||||
return next();
|
||||
}
|
||||
return res.status(404).end();
|
||||
@ -130,8 +132,6 @@ function getCertById(anId, allChallenges) {
|
||||
}))[0];
|
||||
}
|
||||
|
||||
const superBlocks = Object.keys(superBlockCertTypeMap);
|
||||
|
||||
function sendCertifiedEmail(
|
||||
{
|
||||
email = '',
|
||||
@ -223,11 +223,11 @@ function createVerifyCert(certTypeIds, app) {
|
||||
const { Email } = app.models;
|
||||
return function verifyCert(req, res, next) {
|
||||
const {
|
||||
body: { superBlock },
|
||||
body: { certSlug },
|
||||
user
|
||||
} = req;
|
||||
log(superBlock);
|
||||
let certType = superBlockCertTypeMap[superBlock];
|
||||
log(certSlug);
|
||||
let certType = certSlugTypeMap[certSlug];
|
||||
log(certType);
|
||||
return Observable.of(certTypeIds[certType])
|
||||
.flatMap(challenge => {
|
||||
@ -335,9 +335,9 @@ function createShowCert(app) {
|
||||
}
|
||||
|
||||
return function showCert(req, res, next) {
|
||||
let { username, cert } = req.params;
|
||||
let { username, certSlug } = req.params;
|
||||
username = username.toLowerCase();
|
||||
const certType = superBlockCertTypeMap[cert];
|
||||
const certType = certSlugTypeMap[certSlug];
|
||||
const certId = certTypeIdMap[certType];
|
||||
const certTitle = certTypeTitleMap[certType];
|
||||
const completionTime = completionHours[certType] || 300;
|
||||
|
@ -132,6 +132,7 @@ exports.createPages = function createPages({ graphql, actions, reporter }) {
|
||||
);
|
||||
|
||||
// Create intro pages
|
||||
// TODO: Remove allMarkdownRemark (populate from elsewhere)
|
||||
result.data.allMarkdownRemark.edges.forEach(edge => {
|
||||
const {
|
||||
node: { frontmatter, fields }
|
||||
|
@ -33,6 +33,7 @@ import envData from '../../../config/env.json';
|
||||
import RedirectHome from '../components/RedirectHome';
|
||||
import { Loader, Spacer } from '../components/helpers';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { User } from '../redux/propTypes';
|
||||
|
||||
const { clientLocale } = envData;
|
||||
|
||||
@ -48,7 +49,7 @@ const propTypes = {
|
||||
date: PropTypes.number
|
||||
}),
|
||||
certDashedName: PropTypes.string,
|
||||
certName: PropTypes.string,
|
||||
certSlug: PropTypes.string,
|
||||
createFlashMessage: PropTypes.func.isRequired,
|
||||
executeGA: PropTypes.func,
|
||||
fetchProfileForUser: PropTypes.func,
|
||||
@ -58,48 +59,27 @@ const propTypes = {
|
||||
errored: PropTypes.bool
|
||||
}),
|
||||
isDonating: PropTypes.bool,
|
||||
isValidCert: PropTypes.bool,
|
||||
location: PropTypes.shape({
|
||||
pathname: PropTypes.string
|
||||
}),
|
||||
showCert: PropTypes.func.isRequired,
|
||||
signedInUserName: PropTypes.string,
|
||||
user: PropTypes.shape({
|
||||
completedChallenges: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
solution: PropTypes.string,
|
||||
githubLink: PropTypes.string,
|
||||
files: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
contents: PropTypes.string,
|
||||
ext: PropTypes.string,
|
||||
key: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
path: PropTypes.string
|
||||
})
|
||||
)
|
||||
})
|
||||
),
|
||||
profileUI: PropTypes.shape({
|
||||
showName: PropTypes.bool
|
||||
}),
|
||||
username: PropTypes.string
|
||||
}),
|
||||
user: User,
|
||||
userFetchState: PropTypes.shape({
|
||||
complete: PropTypes.bool
|
||||
}),
|
||||
userFullName: PropTypes.string,
|
||||
username: PropTypes.string,
|
||||
validCertName: PropTypes.bool
|
||||
username: PropTypes.string
|
||||
};
|
||||
|
||||
const requestedUserSelector = (state, { username = '' }) =>
|
||||
userByNameSelector(username.toLowerCase())(state);
|
||||
|
||||
const validCertNames = certMap.map(cert => cert.slug);
|
||||
const validCertSlugs = certMap.map(cert => cert.certSlug);
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const validCertName = validCertNames.some(name => name === props.certName);
|
||||
const isValidCert = validCertSlugs.some(slug => slug === props.certSlug);
|
||||
return createSelector(
|
||||
showCertSelector,
|
||||
showCertFetchStateSelector,
|
||||
@ -110,7 +90,7 @@ const mapStateToProps = (state, props) => {
|
||||
(cert, fetchState, signedInUserName, userFetchState, isDonating, user) => ({
|
||||
cert,
|
||||
fetchState,
|
||||
validCertName,
|
||||
isValidCert,
|
||||
signedInUserName,
|
||||
userFetchState,
|
||||
isDonating,
|
||||
@ -132,9 +112,9 @@ const ShowCertification = props => {
|
||||
const [isDonationClosed, setIsDonationClosed] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const { username, certName, validCertName, showCert } = props;
|
||||
if (validCertName) {
|
||||
showCert({ username, certName });
|
||||
const { username, certSlug, isValidCert, showCert } = props;
|
||||
if (isValidCert) {
|
||||
showCert({ username, certSlug });
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
@ -208,13 +188,13 @@ const ShowCertification = props => {
|
||||
const {
|
||||
cert,
|
||||
fetchState,
|
||||
validCertName,
|
||||
isValidCert,
|
||||
createFlashMessage,
|
||||
signedInUserName,
|
||||
location: { pathname }
|
||||
} = props;
|
||||
|
||||
if (!validCertName) {
|
||||
if (!isValidCert) {
|
||||
createFlashMessage(standardErrorMessage);
|
||||
return <RedirectHome />;
|
||||
}
|
||||
|
@ -125,8 +125,8 @@ const ShowProjectLinks = props => {
|
||||
];
|
||||
return legacyCerts.map((cert, ind) => {
|
||||
const mapToUse = projectMap[cert.title] || legacyProjectMap[cert.title];
|
||||
const { superBlock } = first(mapToUse);
|
||||
const certLocation = `/certification/${username}/${superBlock}`;
|
||||
const { certSlug } = first(mapToUse);
|
||||
const certLocation = `/certification/${username}/${certSlug}`;
|
||||
return (
|
||||
<li key={ind}>
|
||||
<a
|
||||
|
@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { certificatesByNameSelector } from '../../../redux';
|
||||
import { ButtonSpacer, FullWidthRow, Link, Spacer } from '../../helpers';
|
||||
import './certifications.css';
|
||||
import { CurrentCertsType } from '../../../redux/propTypes';
|
||||
|
||||
const mapStateToProps = (state, props) =>
|
||||
createSelector(
|
||||
@ -21,19 +22,11 @@ const mapStateToProps = (state, props) =>
|
||||
})
|
||||
)(state, props);
|
||||
|
||||
const certArrayTypes = PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
show: PropTypes.bool,
|
||||
title: PropTypes.string,
|
||||
showURL: PropTypes.string
|
||||
})
|
||||
);
|
||||
|
||||
const propTypes = {
|
||||
currentCerts: certArrayTypes,
|
||||
currentCerts: CurrentCertsType,
|
||||
hasLegacyCert: PropTypes.bool,
|
||||
hasModernCert: PropTypes.bool,
|
||||
legacyCerts: certArrayTypes,
|
||||
legacyCerts: CurrentCertsType,
|
||||
username: PropTypes.string
|
||||
};
|
||||
|
||||
@ -45,7 +38,7 @@ function renderCertShow(username, cert) {
|
||||
<Link
|
||||
className='btn btn-lg btn-primary btn-block'
|
||||
external={true}
|
||||
to={`/certification/${username}/${cert.showURL}`}
|
||||
to={`/certification/${username}/${cert.certSlug}`}
|
||||
>
|
||||
View {cert.title}
|
||||
</Link>
|
||||
|
@ -289,15 +289,15 @@ export class CertificationSettings extends Component {
|
||||
t,
|
||||
verifyCert
|
||||
} = this.props;
|
||||
const { superBlock } = first(projectMap[certName]);
|
||||
const certLocation = `/certification/${username}/${superBlock}`;
|
||||
const createClickHandler = superBlock => e => {
|
||||
const { certSlug } = first(projectMap[certName]);
|
||||
const certLocation = `/certification/${username}/${certSlug}`;
|
||||
const createClickHandler = certSlug => e => {
|
||||
e.preventDefault();
|
||||
if (isCert) {
|
||||
return navigate(certLocation);
|
||||
}
|
||||
return isHonest
|
||||
? verifyCert(superBlock)
|
||||
? verifyCert(certSlug)
|
||||
: createFlashMessage(honestyInfoMessage);
|
||||
};
|
||||
return projectMap[certName]
|
||||
@ -312,13 +312,13 @@ export class CertificationSettings extends Component {
|
||||
</tr>
|
||||
))
|
||||
.concat([
|
||||
<tr key={`cert-${superBlock}-button`}>
|
||||
<tr key={`cert-${certSlug}-button`}>
|
||||
<td colSpan={2}>
|
||||
<Button
|
||||
block={true}
|
||||
bsStyle='primary'
|
||||
href={certLocation}
|
||||
onClick={createClickHandler(superBlock)}
|
||||
onClick={createClickHandler(certSlug)}
|
||||
>
|
||||
{isCert ? t('buttons.show-cert') : t('buttons.claim-cert')}
|
||||
</Button>
|
||||
@ -336,13 +336,13 @@ export class CertificationSettings extends Component {
|
||||
updateLegacyCert
|
||||
} = this.props;
|
||||
let legacyTitle;
|
||||
let superBlock;
|
||||
let certSlug;
|
||||
let certs = Object.keys(legacyProjectMap);
|
||||
let loopBreak = false;
|
||||
for (let certTitle of certs) {
|
||||
for (let chalTitle of legacyProjectMap[certTitle]) {
|
||||
if (chalTitle.title === Object.keys(formChalObj)[0]) {
|
||||
superBlock = chalTitle.superBlock;
|
||||
certSlug = chalTitle.certSlug;
|
||||
loopBreak = true;
|
||||
legacyTitle = certTitle;
|
||||
break;
|
||||
@ -392,16 +392,16 @@ export class CertificationSettings extends Component {
|
||||
|
||||
if (isProjectSectionComplete) {
|
||||
return isHonest
|
||||
? verifyCert(superBlock)
|
||||
? verifyCert(certSlug)
|
||||
: createFlashMessage(honestyInfoMessage);
|
||||
}
|
||||
return updateLegacyCert({ challengesToUpdate, superBlock });
|
||||
return updateLegacyCert({ challengesToUpdate, certSlug });
|
||||
}
|
||||
|
||||
renderLegacyCertifications = certName => {
|
||||
const { username, createFlashMessage, completedChallenges, t } = this.props;
|
||||
const { superBlock } = first(legacyProjectMap[certName]);
|
||||
const certLocation = `/certification/${username}/${superBlock}`;
|
||||
const { certSlug } = first(legacyProjectMap[certName]);
|
||||
const certLocation = `/certification/${username}/${certSlug}`;
|
||||
const challengeTitles = legacyProjectMap[certName].map(item => item.title);
|
||||
const isCertClaimed = this.getUserIsCertMap()[certName];
|
||||
const initialObject = {};
|
||||
@ -446,7 +446,7 @@ export class CertificationSettings extends Component {
|
||||
};
|
||||
|
||||
return (
|
||||
<FullWidthRow key={superBlock}>
|
||||
<FullWidthRow key={certSlug}>
|
||||
<Spacer />
|
||||
<h3 className='text-center'>{certName}</h3>
|
||||
<Form
|
||||
@ -456,7 +456,7 @@ export class CertificationSettings extends Component {
|
||||
enableSubmit={fullForm}
|
||||
formFields={formFields}
|
||||
hideButton={isCertClaimed}
|
||||
id={superBlock}
|
||||
id={certSlug}
|
||||
initialValues={{
|
||||
...initialObject
|
||||
}}
|
||||
@ -470,7 +470,7 @@ export class CertificationSettings extends Component {
|
||||
bsStyle='primary'
|
||||
className={'col-xs-12'}
|
||||
href={certLocation}
|
||||
id={'button-' + superBlock}
|
||||
id={'button-' + certSlug}
|
||||
onClick={createClickHandler(certLocation)}
|
||||
style={buttonStyle}
|
||||
target='_blank'
|
||||
@ -507,10 +507,10 @@ export class CertificationSettings extends Component {
|
||||
isJsAlgoDataStructCert &&
|
||||
isRespWebDesignCert;
|
||||
|
||||
// Keep the settings page slug as full-stack rather than
|
||||
// Keep the settings page certSlug as full-stack rather than
|
||||
// legacy-full-stack so we don't break existing links
|
||||
const superBlock = 'full-stack';
|
||||
const certLocation = `/certification/${username}/${superBlock}`;
|
||||
const certSlug = 'full-stack';
|
||||
const certLocation = `/certification/${username}/${certSlug}`;
|
||||
|
||||
const buttonStyle = {
|
||||
marginBottom: '30px',
|
||||
@ -518,17 +518,17 @@ export class CertificationSettings extends Component {
|
||||
fontSize: '18px'
|
||||
};
|
||||
|
||||
const createClickHandler = superBlock => e => {
|
||||
const createClickHandler = certSlug => e => {
|
||||
e.preventDefault();
|
||||
if (isFullStackCert) {
|
||||
return navigate(certLocation);
|
||||
}
|
||||
return isHonest
|
||||
? verifyCert(superBlock)
|
||||
? verifyCert(certSlug)
|
||||
: createFlashMessage(honestyInfoMessage);
|
||||
};
|
||||
return (
|
||||
<FullWidthRow key={superBlock}>
|
||||
<FullWidthRow key={certSlug}>
|
||||
<Spacer />
|
||||
<h3 className='text-center'>Legacy Full Stack Certification</h3>
|
||||
<div>
|
||||
@ -554,8 +554,8 @@ export class CertificationSettings extends Component {
|
||||
bsStyle='primary'
|
||||
className={'col-xs-12'}
|
||||
href={certLocation}
|
||||
id={'button-' + superBlock}
|
||||
onClick={createClickHandler(superBlock)}
|
||||
id={'button-' + certSlug}
|
||||
onClick={createClickHandler(certSlug)}
|
||||
style={buttonStyle}
|
||||
target='_blank'
|
||||
>
|
||||
@ -569,7 +569,7 @@ export class CertificationSettings extends Component {
|
||||
bsStyle='primary'
|
||||
className={'col-xs-12'}
|
||||
disabled={true}
|
||||
id={'button-' + superBlock}
|
||||
id={'button-' + certSlug}
|
||||
style={buttonStyle}
|
||||
target='_blank'
|
||||
>
|
||||
|
@ -12,7 +12,7 @@ class Certification extends Component {
|
||||
return (
|
||||
<Router>
|
||||
<ShowCertification
|
||||
path={withPrefix('/certification/:username/:certName')}
|
||||
path={withPrefix('/certification/:username/:certSlug')}
|
||||
/>
|
||||
<RedirectHome default={true} />
|
||||
</Router>
|
||||
|
@ -266,81 +266,81 @@ export const certificatesByNameSelector = username => state => {
|
||||
{
|
||||
show: isRespWebDesignCert,
|
||||
title: 'Responsive Web Design Certification',
|
||||
showURL: 'responsive-web-design'
|
||||
certSlug: 'responsive-web-design'
|
||||
},
|
||||
{
|
||||
show: isJsAlgoDataStructCert,
|
||||
title: 'JavaScript Algorithms and Data Structures Certification',
|
||||
showURL: 'javascript-algorithms-and-data-structures'
|
||||
certSlug: 'javascript-algorithms-and-data-structures'
|
||||
},
|
||||
{
|
||||
show: isFrontEndLibsCert,
|
||||
title: 'Front End Libraries Certification',
|
||||
showURL: 'front-end-libraries'
|
||||
certSlug: 'front-end-libraries'
|
||||
},
|
||||
{
|
||||
show: is2018DataVisCert,
|
||||
title: 'Data Visualization Certification',
|
||||
showURL: 'data-visualization'
|
||||
certSlug: 'data-visualization'
|
||||
},
|
||||
{
|
||||
show: isApisMicroservicesCert,
|
||||
title: 'APIs and Microservices Certification',
|
||||
showURL: 'apis-and-microservices'
|
||||
certSlug: 'apis-and-microservices'
|
||||
},
|
||||
{
|
||||
show: isQaCertV7,
|
||||
title: ' Quality Assurance Certification',
|
||||
showURL: 'quality-assurance-v7'
|
||||
certSlug: 'quality-assurance-v7'
|
||||
},
|
||||
{
|
||||
show: isInfosecCertV7,
|
||||
title: 'Information Security Certification',
|
||||
showURL: 'information-security-v7'
|
||||
certSlug: 'information-security-v7'
|
||||
},
|
||||
{
|
||||
show: isSciCompPyCertV7,
|
||||
title: 'Scientific Computing with Python Certification',
|
||||
showURL: 'scientific-computing-with-python-v7'
|
||||
certSlug: 'scientific-computing-with-python-v7'
|
||||
},
|
||||
{
|
||||
show: isDataAnalysisPyCertV7,
|
||||
title: 'Data Analysis with Python Certification',
|
||||
showURL: 'data-analysis-with-python-v7'
|
||||
certSlug: 'data-analysis-with-python-v7'
|
||||
},
|
||||
{
|
||||
show: isMachineLearningPyCertV7,
|
||||
title: 'Machine Learning with Python Certification',
|
||||
showURL: 'machine-learning-with-python-v7'
|
||||
certSlug: 'machine-learning-with-python-v7'
|
||||
}
|
||||
],
|
||||
legacyCerts: [
|
||||
{
|
||||
show: isFrontEndCert,
|
||||
title: 'Front End Certification',
|
||||
showURL: 'legacy-front-end'
|
||||
certSlug: 'legacy-front-end'
|
||||
},
|
||||
{
|
||||
show: isBackEndCert,
|
||||
title: 'Back End Certification',
|
||||
showURL: 'legacy-back-end'
|
||||
certSlug: 'legacy-back-end'
|
||||
},
|
||||
{
|
||||
show: isDataVisCert,
|
||||
title: 'Data Visualization Certification',
|
||||
showURL: 'legacy-data-visualization'
|
||||
certSlug: 'legacy-data-visualization'
|
||||
},
|
||||
{
|
||||
show: isInfosecQaCert,
|
||||
title: 'Information Security and Quality Assurance Certification',
|
||||
// Keep the current public profile cert slug
|
||||
showURL: 'information-security-and-quality-assurance'
|
||||
certSlug: 'information-security-and-quality-assurance'
|
||||
},
|
||||
{
|
||||
show: isFullStackCert,
|
||||
title: 'Full Stack Certification',
|
||||
// Keep the current public profile cert slug
|
||||
showURL: 'full-stack'
|
||||
certSlug: 'full-stack'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@ -124,3 +124,11 @@ export const User = PropTypes.shape({
|
||||
username: PropTypes.string,
|
||||
website: PropTypes.string
|
||||
});
|
||||
|
||||
export const CurrentCertsType = PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
show: PropTypes.bool,
|
||||
title: PropTypes.string,
|
||||
certSlug: PropTypes.string
|
||||
})
|
||||
);
|
||||
|
@ -5,9 +5,9 @@ import { createFlashMessage } from '../components/Flash/redux';
|
||||
import { getShowCert } from '../utils/ajax';
|
||||
import { showCertComplete, showCertError } from '.';
|
||||
|
||||
function* getShowCertSaga({ payload: { username, certName: cert } }) {
|
||||
function* getShowCertSaga({ payload: { username, certSlug } }) {
|
||||
try {
|
||||
const { data: response } = yield call(getShowCert, username, cert);
|
||||
const { data: response } = yield call(getShowCert, username, certSlug);
|
||||
const { messages } = response;
|
||||
if (messages && messages.length) {
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
|
@ -27,143 +27,143 @@ const certMap = [
|
||||
{
|
||||
id: '561add10cb82ac38a17513be',
|
||||
title: 'Legacy Front End',
|
||||
slug: 'legacy-front-end',
|
||||
certSlug: 'legacy-front-end',
|
||||
flag: 'isFrontEndCert',
|
||||
projects: [
|
||||
{
|
||||
id: 'bd7158d8c242eddfaeb5bd13',
|
||||
title: 'Build a Personal Portfolio Webpage',
|
||||
link: `${legacyFrontEndBase}/build-a-personal-portfolio-webpage`,
|
||||
superBlock: 'legacy-front-end'
|
||||
certSlug: 'legacy-front-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd13',
|
||||
title: 'Build a Random Quote Machine',
|
||||
link: `${legacyFrontEndBase}/build-a-random-quote-machine`,
|
||||
superBlock: 'legacy-front-end'
|
||||
certSlug: 'legacy-front-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd0f',
|
||||
title: 'Build a 25 + 5 Clock',
|
||||
link: `${legacyFrontEndBase}/build-a-25--5-clock`,
|
||||
superBlock: 'legacy-front-end'
|
||||
certSlug: 'legacy-front-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd17',
|
||||
title: 'Build a JavaScript Calculator',
|
||||
link: `${legacyFrontEndBase}/build-a-javascript-calculator`,
|
||||
superBlock: 'legacy-front-end'
|
||||
certSlug: 'legacy-front-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd10',
|
||||
title: 'Show the Local Weather',
|
||||
link: `${legacyFrontEndBase}/show-the-local-weather`,
|
||||
superBlock: 'legacy-front-end'
|
||||
certSlug: 'legacy-front-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd1f',
|
||||
title: 'Use the TwitchTV JSON API',
|
||||
link: `${legacyFrontEndBase}/use-the-twitchtv-json-api`,
|
||||
superBlock: 'legacy-front-end'
|
||||
certSlug: 'legacy-front-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd18',
|
||||
title: 'Stylize Stories on Camper News',
|
||||
link: `${legacyFrontEndBase}/stylize-stories-on-camper-news`,
|
||||
superBlock: 'legacy-front-end'
|
||||
certSlug: 'legacy-front-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd19',
|
||||
title: 'Build a Wikipedia Viewer',
|
||||
link: `${legacyFrontEndBase}/build-a-wikipedia-viewer`,
|
||||
superBlock: 'legacy-front-end'
|
||||
certSlug: 'legacy-front-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c442eedfaeb5bd1c',
|
||||
title: 'Build a Tic Tac Toe Game',
|
||||
link: `${legacyFrontEndBase}/build-a-tic-tac-toe-game`,
|
||||
superBlock: 'legacy-front-end'
|
||||
certSlug: 'legacy-front-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd1c',
|
||||
title: 'Build a Simon Game',
|
||||
link: `${legacyFrontEndBase}/build-a-simon-game`,
|
||||
superBlock: 'legacy-front-end'
|
||||
certSlug: 'legacy-front-end'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '660add10cb82ac38a17513be',
|
||||
title: 'Legacy Back End',
|
||||
slug: 'legacy-back-end',
|
||||
certSlug: 'legacy-back-end',
|
||||
flag: 'isBackEndCert',
|
||||
projects: [
|
||||
{
|
||||
id: 'bd7158d8c443edefaeb5bdef',
|
||||
title: 'Timestamp Microservice',
|
||||
link: `${legacyBackEndBase}/timestamp-microservice`,
|
||||
superBlock: 'legacy-back-end'
|
||||
certSlug: 'legacy-back-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443edefaeb5bdff',
|
||||
title: 'Request Header Parser Microservice',
|
||||
link: `${legacyBackEndBase}/request-header-parser-microservice`,
|
||||
superBlock: 'legacy-back-end'
|
||||
certSlug: 'legacy-back-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443edefaeb5bd0e',
|
||||
title: 'URL Shortener Microservice',
|
||||
link: `${legacyBackEndBase}/url-shortener-microservice`,
|
||||
superBlock: 'legacy-back-end'
|
||||
certSlug: 'legacy-back-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443edefaeb5bdee',
|
||||
title: 'Image Search Abstraction Layer',
|
||||
link: `${legacyBackEndBase}/image-search-abstraction-layer`,
|
||||
superBlock: 'legacy-back-end'
|
||||
certSlug: 'legacy-back-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443edefaeb5bd0f',
|
||||
title: 'File Metadata Microservice',
|
||||
link: `${legacyBackEndBase}/file-metadata-microservice`,
|
||||
superBlock: 'legacy-back-end'
|
||||
certSlug: 'legacy-back-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443eddfaeb5bdef',
|
||||
title: 'Build a Voting App',
|
||||
link: `${legacyBackEndBase}/build-a-voting-app`,
|
||||
superBlock: 'legacy-back-end'
|
||||
certSlug: 'legacy-back-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443eddfaeb5bdff',
|
||||
title: 'Build a Nightlife Coordination App',
|
||||
link: `${legacyBackEndBase}/build-a-nightlife-coordination-app`,
|
||||
superBlock: 'legacy-back-end'
|
||||
certSlug: 'legacy-back-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443eddfaeb5bd0e',
|
||||
title: 'Chart the Stock Market',
|
||||
link: `${legacyBackEndBase}/chart-the-stock-market`,
|
||||
superBlock: 'legacy-back-end'
|
||||
certSlug: 'legacy-back-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443eddfaeb5bd0f',
|
||||
title: 'Manage a Book Trading Club',
|
||||
link: `${legacyBackEndBase}/manage-a-book-trading-club`,
|
||||
superBlock: 'legacy-back-end'
|
||||
certSlug: 'legacy-back-end'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443eddfaeb5bdee',
|
||||
title: 'Build a Pinterest Clone',
|
||||
link: `${legacyBackEndBase}/build-a-pinterest-clone`,
|
||||
superBlock: 'legacy-back-end'
|
||||
certSlug: 'legacy-back-end'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '561add10cb82ac38a17213bd',
|
||||
title: 'Legacy Full Stack',
|
||||
slug: 'full-stack',
|
||||
certSlug: 'full-stack',
|
||||
flag: 'isFullStackCert'
|
||||
// Requirements are other certs and is
|
||||
// handled elsewhere
|
||||
@ -171,68 +171,68 @@ const certMap = [
|
||||
{
|
||||
id: '561add10cb82ac39a17513bc',
|
||||
title: 'Legacy Data Visualization',
|
||||
slug: 'legacy-data-visualization',
|
||||
certSlug: 'legacy-data-visualization',
|
||||
flag: 'isDataVisCert',
|
||||
projects: [
|
||||
{
|
||||
id: 'bd7157d8c242eddfaeb5bd13',
|
||||
title: 'Build a Markdown Previewer',
|
||||
link: `${legacyDataVisBase}/build-a-markdown-previewer`,
|
||||
superBlock: 'legacy-data-visualization'
|
||||
certSlug: 'legacy-data-visualization'
|
||||
},
|
||||
{
|
||||
id: 'bd7156d8c242eddfaeb5bd13',
|
||||
title: 'Build a Camper Leaderboard',
|
||||
link: `${legacyDataVisBase}/build-a-camper-leaderboard`,
|
||||
superBlock: 'legacy-data-visualization'
|
||||
certSlug: 'legacy-data-visualization'
|
||||
},
|
||||
{
|
||||
id: 'bd7155d8c242eddfaeb5bd13',
|
||||
title: 'Build a Recipe Box',
|
||||
link: `${legacyDataVisBase}/build-a-recipe-box`,
|
||||
superBlock: 'legacy-data-visualization'
|
||||
certSlug: 'legacy-data-visualization'
|
||||
},
|
||||
{
|
||||
id: 'bd7154d8c242eddfaeb5bd13',
|
||||
title: 'Build the Game of Life',
|
||||
link: `${legacyDataVisBase}/build-the-game-of-life`,
|
||||
superBlock: 'legacy-data-visualization'
|
||||
certSlug: 'legacy-data-visualization'
|
||||
},
|
||||
{
|
||||
id: 'bd7153d8c242eddfaeb5bd13',
|
||||
title: 'Build a Roguelike Dungeon Crawler Game',
|
||||
link: `${legacyDataVisBase}/build-a-roguelike-dungeon-crawler-game`,
|
||||
superBlock: 'legacy-data-visualization'
|
||||
certSlug: 'legacy-data-visualization'
|
||||
},
|
||||
{
|
||||
id: 'bd7168d8c242eddfaeb5bd13',
|
||||
title: 'Visualize Data with a Bar Chart',
|
||||
link: `${legacyDataVisBase}/visualize-data-with-a-bar-chart`,
|
||||
superBlock: 'legacy-data-visualization'
|
||||
certSlug: 'legacy-data-visualization'
|
||||
},
|
||||
{
|
||||
id: 'bd7178d8c242eddfaeb5bd13',
|
||||
title: 'Visualize Data with a Scatterplot Graph',
|
||||
link: `${legacyDataVisBase}/visualize-data-with-a-scatterplot-graph`,
|
||||
superBlock: 'legacy-data-visualization'
|
||||
certSlug: 'legacy-data-visualization'
|
||||
},
|
||||
{
|
||||
id: 'bd7188d8c242eddfaeb5bd13',
|
||||
title: 'Visualize Data with a Heat Map',
|
||||
link: `${legacyDataVisBase}/visualize-data-with-a-heat-map`,
|
||||
superBlock: 'legacy-data-visualization'
|
||||
certSlug: 'legacy-data-visualization'
|
||||
},
|
||||
{
|
||||
id: 'bd7198d8c242eddfaeb5bd13',
|
||||
title: 'Show National Contiguity with a Force Directed Graph',
|
||||
link: `${legacyDataVisBase}/show-national-contiguity-with-a-force-directed-graph`,
|
||||
superBlock: 'legacy-data-visualization'
|
||||
certSlug: 'legacy-data-visualization'
|
||||
},
|
||||
{
|
||||
id: 'bd7108d8c242eddfaeb5bd13',
|
||||
title: 'Map Data Across the Globe',
|
||||
link: `${legacyDataVisBase}/map-data-across-the-globe`,
|
||||
superBlock: 'legacy-data-visualization'
|
||||
certSlug: 'legacy-data-visualization'
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -240,7 +240,7 @@ const certMap = [
|
||||
id: '561add10cb82ac38a17213bc',
|
||||
title: 'Legacy Information Security and Quality Assurance',
|
||||
// Keep this as information-security-and-quality-assurance
|
||||
slug: 'information-security-and-quality-assurance',
|
||||
certSlug: 'information-security-and-quality-assurance',
|
||||
flag: 'isInfosecQaCert',
|
||||
projects: [
|
||||
// Keep this as information-security-and-quality-assurance
|
||||
@ -248,335 +248,335 @@ const certMap = [
|
||||
id: '587d8249367417b2b2512c41',
|
||||
title: 'Metric-Imperial Converter',
|
||||
link: `${legacyInfosecQaBase}/metric-imperial-converter`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
certSlug: 'information-security-and-quality-assurance'
|
||||
},
|
||||
{
|
||||
id: '587d8249367417b2b2512c42',
|
||||
title: 'Issue Tracker',
|
||||
link: `${legacyInfosecQaBase}/issue-tracker`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
certSlug: 'information-security-and-quality-assurance'
|
||||
},
|
||||
{
|
||||
id: '587d824a367417b2b2512c43',
|
||||
title: 'Personal Library',
|
||||
link: `${legacyInfosecQaBase}/personal-library`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
certSlug: 'information-security-and-quality-assurance'
|
||||
},
|
||||
{
|
||||
id: '587d824a367417b2b2512c44',
|
||||
title: 'Stock Price Checker',
|
||||
link: `${legacyInfosecQaBase}/stock-price-checker`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
certSlug: 'information-security-and-quality-assurance'
|
||||
},
|
||||
{
|
||||
id: '587d824a367417b2b2512c45',
|
||||
title: 'Anonymous Message Board',
|
||||
link: `${legacyInfosecQaBase}/anonymous-message-board`,
|
||||
superBlock: 'information-security-and-quality-assurance'
|
||||
certSlug: 'information-security-and-quality-assurance'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '561add10cb82ac38a17513bc',
|
||||
title: 'Responsive Web Design',
|
||||
slug: 'responsive-web-design',
|
||||
certSlug: 'responsive-web-design',
|
||||
flag: 'isRespWebDesignCert',
|
||||
projects: [
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd18',
|
||||
title: 'Build a Tribute Page',
|
||||
link: `${responsiveWebBase}/build-a-tribute-page`,
|
||||
superBlock: 'responsive-web-design'
|
||||
certSlug: 'responsive-web-design'
|
||||
},
|
||||
{
|
||||
id: '587d78af367417b2b2512b03',
|
||||
title: 'Build a Survey Form',
|
||||
link: `${responsiveWebBase}/build-a-survey-form`,
|
||||
superBlock: 'responsive-web-design'
|
||||
certSlug: 'responsive-web-design'
|
||||
},
|
||||
{
|
||||
id: '587d78af367417b2b2512b04',
|
||||
title: 'Build a Product Landing Page',
|
||||
link: `${responsiveWebBase}/build-a-product-landing-page`,
|
||||
superBlock: 'responsive-web-design'
|
||||
certSlug: 'responsive-web-design'
|
||||
},
|
||||
{
|
||||
id: '587d78b0367417b2b2512b05',
|
||||
title: 'Build a Technical Documentation Page',
|
||||
link: `${responsiveWebBase}/build-a-technical-documentation-page`,
|
||||
superBlock: 'responsive-web-design'
|
||||
certSlug: 'responsive-web-design'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c242eddfaeb5bd13',
|
||||
title: 'Build a Personal Portfolio Webpage',
|
||||
link: `${responsiveWebBase}/build-a-personal-portfolio-webpage`,
|
||||
superBlock: 'responsive-web-design'
|
||||
certSlug: 'responsive-web-design'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '561abd10cb81ac38a17513bc',
|
||||
title: 'JavaScript Algorithms and Data Structures',
|
||||
slug: 'javascript-algorithms-and-data-structures',
|
||||
certSlug: 'javascript-algorithms-and-data-structures',
|
||||
flag: 'isJsAlgoDataStructCert',
|
||||
projects: [
|
||||
{
|
||||
id: 'aaa48de84e1ecc7c742e1124',
|
||||
title: 'Palindrome Checker',
|
||||
link: `${jsAlgoBase}/palindrome-checker`,
|
||||
superBlock: 'javascript-algorithms-and-data-structures'
|
||||
certSlug: 'javascript-algorithms-and-data-structures'
|
||||
},
|
||||
{
|
||||
id: 'a7f4d8f2483413a6ce226cac',
|
||||
title: 'Roman Numeral Converter',
|
||||
link: `${jsAlgoBase}/roman-numeral-converter`,
|
||||
superBlock: 'javascript-algorithms-and-data-structures'
|
||||
certSlug: 'javascript-algorithms-and-data-structures'
|
||||
},
|
||||
{
|
||||
id: '56533eb9ac21ba0edf2244e2',
|
||||
title: 'Caesars Cipher',
|
||||
link: `${jsAlgoBase}/caesars-cipher`,
|
||||
superBlock: 'javascript-algorithms-and-data-structures'
|
||||
certSlug: 'javascript-algorithms-and-data-structures'
|
||||
},
|
||||
{
|
||||
id: 'aff0395860f5d3034dc0bfc9',
|
||||
title: 'Telephone Number Validator',
|
||||
link: `${jsAlgoBase}/telephone-number-validator`,
|
||||
superBlock: 'javascript-algorithms-and-data-structures'
|
||||
certSlug: 'javascript-algorithms-and-data-structures'
|
||||
},
|
||||
{
|
||||
id: 'aa2e6f85cab2ab736c9a9b24',
|
||||
title: 'Cash Register',
|
||||
link: `${jsAlgoBase}/cash-register`,
|
||||
superBlock: 'javascript-algorithms-and-data-structures'
|
||||
certSlug: 'javascript-algorithms-and-data-structures'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '561acd10cb82ac38a17513bc',
|
||||
title: 'Front End Libraries',
|
||||
slug: 'front-end-libraries',
|
||||
certSlug: 'front-end-libraries',
|
||||
flag: 'isFrontEndLibsCert',
|
||||
projects: [
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd13',
|
||||
title: 'Build a Random Quote Machine',
|
||||
link: `${feLibsBase}/build-a-random-quote-machine`,
|
||||
superBlock: 'front-end-libraries'
|
||||
certSlug: 'front-end-libraries'
|
||||
},
|
||||
{
|
||||
id: 'bd7157d8c242eddfaeb5bd13',
|
||||
title: 'Build a Markdown Previewer',
|
||||
link: `${feLibsBase}/build-a-markdown-previewer`,
|
||||
superBlock: 'front-end-libraries'
|
||||
certSlug: 'front-end-libraries'
|
||||
},
|
||||
{
|
||||
id: '587d7dbc367417b2b2512bae',
|
||||
title: 'Build a Drum Machine',
|
||||
link: `${feLibsBase}/build-a-drum-machine`,
|
||||
superBlock: 'front-end-libraries'
|
||||
certSlug: 'front-end-libraries'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd17',
|
||||
title: 'Build a JavaScript Calculator',
|
||||
link: `${feLibsBase}/build-a-javascript-calculator`,
|
||||
superBlock: 'front-end-libraries'
|
||||
certSlug: 'front-end-libraries'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c442eddfaeb5bd0f',
|
||||
title: 'Build a 25 + 5 Clock',
|
||||
link: `${feLibsBase}/build-a-25--5-clock`,
|
||||
superBlock: 'front-end-libraries'
|
||||
certSlug: 'front-end-libraries'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '5a553ca864b52e1d8bceea14',
|
||||
title: 'Data Visualization',
|
||||
slug: 'data-visualization',
|
||||
certSlug: 'data-visualization',
|
||||
flag: 'is2018DataVisCert',
|
||||
projects: [
|
||||
{
|
||||
id: 'bd7168d8c242eddfaeb5bd13',
|
||||
title: 'Visualize Data with a Bar Chart',
|
||||
link: `${dataVisBase}/visualize-data-with-a-bar-chart`,
|
||||
superBlock: 'data-visualization'
|
||||
certSlug: 'data-visualization'
|
||||
},
|
||||
{
|
||||
id: 'bd7178d8c242eddfaeb5bd13',
|
||||
title: 'Visualize Data with a Scatterplot Graph',
|
||||
link: `${dataVisBase}/visualize-data-with-a-scatterplot-graph`,
|
||||
superBlock: 'data-visualization'
|
||||
certSlug: 'data-visualization'
|
||||
},
|
||||
{
|
||||
id: 'bd7188d8c242eddfaeb5bd13',
|
||||
title: 'Visualize Data with a Heat Map',
|
||||
link: `${dataVisBase}/visualize-data-with-a-heat-map`,
|
||||
superBlock: 'data-visualization'
|
||||
certSlug: 'data-visualization'
|
||||
},
|
||||
{
|
||||
id: '587d7fa6367417b2b2512bbf',
|
||||
title: 'Visualize Data with a Choropleth Map',
|
||||
link: `${dataVisBase}/visualize-data-with-a-choropleth-map`,
|
||||
superBlock: 'data-visualization'
|
||||
certSlug: 'data-visualization'
|
||||
},
|
||||
{
|
||||
id: '587d7fa6367417b2b2512bc0',
|
||||
title: 'Visualize Data with a Treemap Diagram',
|
||||
link: `${dataVisBase}/visualize-data-with-a-treemap-diagram`,
|
||||
superBlock: 'data-visualization'
|
||||
certSlug: 'data-visualization'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '561add10cb82ac38a17523bc',
|
||||
title: 'APIs and Microservices',
|
||||
slug: 'apis-and-microservices',
|
||||
certSlug: 'apis-and-microservices',
|
||||
flag: 'isApisMicroservicesCert',
|
||||
projects: [
|
||||
{
|
||||
id: 'bd7158d8c443edefaeb5bdef',
|
||||
title: 'Timestamp Microservice',
|
||||
link: `${apiMicroBase}/timestamp-microservice`,
|
||||
superBlock: 'apis-and-microservices'
|
||||
certSlug: 'apis-and-microservices'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443edefaeb5bdff',
|
||||
title: 'Request Header Parser Microservice',
|
||||
link: `${apiMicroBase}/request-header-parser-microservice`,
|
||||
superBlock: 'apis-and-microservices'
|
||||
certSlug: 'apis-and-microservices'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443edefaeb5bd0e',
|
||||
title: 'URL Shortener Microservice',
|
||||
link: `${apiMicroBase}/url-shortener-microservice`,
|
||||
superBlock: 'apis-and-microservices'
|
||||
certSlug: 'apis-and-microservices'
|
||||
},
|
||||
{
|
||||
id: '5a8b073d06fa14fcfde687aa',
|
||||
title: 'Exercise Tracker',
|
||||
link: `${apiMicroBase}/exercise-tracker`,
|
||||
superBlock: 'apis-and-microservices'
|
||||
certSlug: 'apis-and-microservices'
|
||||
},
|
||||
{
|
||||
id: 'bd7158d8c443edefaeb5bd0f',
|
||||
title: 'File Metadata Microservice',
|
||||
link: `${apiMicroBase}/file-metadata-microservice`,
|
||||
superBlock: 'apis-and-microservices'
|
||||
certSlug: 'apis-and-microservices'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '5e611829481575a52dc59c0e',
|
||||
title: 'Quality Assurance',
|
||||
slug: 'quality-assurance-v7',
|
||||
certSlug: 'quality-assurance-v7',
|
||||
flag: 'isQaCertV7',
|
||||
projects: [
|
||||
{
|
||||
id: '587d8249367417b2b2512c41',
|
||||
title: 'Metric-Imperial Converter',
|
||||
link: `${qaBase}/metric-imperial-converter`,
|
||||
superBlock: 'quality-assurance-v7'
|
||||
certSlug: 'quality-assurance-v7'
|
||||
},
|
||||
{
|
||||
id: '587d8249367417b2b2512c42',
|
||||
title: 'Issue Tracker',
|
||||
link: `${qaBase}/issue-tracker`,
|
||||
superBlock: 'quality-assurance-v7'
|
||||
certSlug: 'quality-assurance-v7'
|
||||
},
|
||||
{
|
||||
id: '587d824a367417b2b2512c43',
|
||||
title: 'Personal Library',
|
||||
link: `${qaBase}/personal-library`,
|
||||
superBlock: 'quality-assurance-v7'
|
||||
certSlug: 'quality-assurance-v7'
|
||||
},
|
||||
{
|
||||
id: '5e601bf95ac9d0ecd8b94afd',
|
||||
title: 'Sudoku Solver',
|
||||
link: `${qaBase}/sudoku-solver`,
|
||||
superBlock: 'quality-assurance-v7'
|
||||
certSlug: 'quality-assurance-v7'
|
||||
},
|
||||
{
|
||||
id: '5e601c0d5ac9d0ecd8b94afe',
|
||||
title: 'American British Translator',
|
||||
link: `${qaBase}/american-british-translator`,
|
||||
superBlock: 'quality-assurance-v7'
|
||||
certSlug: 'quality-assurance-v7'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '5e44431b903586ffb414c951',
|
||||
title: 'Scientific Computing with Python',
|
||||
slug: 'scientific-computing-with-python-v7',
|
||||
certSlug: 'scientific-computing-with-python-v7',
|
||||
flag: 'isSciCompPyCertV7',
|
||||
projects: [
|
||||
{
|
||||
id: '5e44412c903586ffb414c94c',
|
||||
title: 'Arithmetic Formatter',
|
||||
link: `${sciCompPyBase}/arithmetic-formatter`,
|
||||
superBlock: 'scientific-computing-with-python-v7'
|
||||
certSlug: 'scientific-computing-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e444136903586ffb414c94d',
|
||||
title: 'Time Calculator',
|
||||
link: `${sciCompPyBase}/time-calculator`,
|
||||
superBlock: 'scientific-computing-with-python-v7'
|
||||
certSlug: 'scientific-computing-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e44413e903586ffb414c94e',
|
||||
title: 'Budget App',
|
||||
link: `${sciCompPyBase}/budget-app`,
|
||||
superBlock: 'scientific-computing-with-python-v7'
|
||||
certSlug: 'scientific-computing-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e444147903586ffb414c94f',
|
||||
title: 'Polygon Area Calculator',
|
||||
link: `${sciCompPyBase}/polygon-area-calculator`,
|
||||
superBlock: 'scientific-computing-with-python-v7'
|
||||
certSlug: 'scientific-computing-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e44414f903586ffb414c950',
|
||||
title: 'Probability Calculator',
|
||||
link: `${sciCompPyBase}/probability-calculator`,
|
||||
superBlock: 'scientific-computing-with-python-v7'
|
||||
certSlug: 'scientific-computing-with-python-v7'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '5e46fc95ac417301a38fb934',
|
||||
title: 'Data Analysis with Python',
|
||||
slug: 'data-analysis-with-python-v7',
|
||||
certSlug: 'data-analysis-with-python-v7',
|
||||
flag: 'isDataAnalysisPyCertV7',
|
||||
projects: [
|
||||
{
|
||||
id: '5e46f7e5ac417301a38fb928',
|
||||
title: 'Mean-Variance-Standard Deviation Calculator',
|
||||
link: `${dataAnalysisPyBase}/mean-variance-standard-deviation-calculator`,
|
||||
superBlock: 'data-analysis-with-python-v7'
|
||||
certSlug: 'data-analysis-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e46f7e5ac417301a38fb929',
|
||||
title: 'Demographic Data Analyzer',
|
||||
link: `${dataAnalysisPyBase}/demographic-data-analyzer`,
|
||||
superBlock: 'data-analysis-with-python-v7'
|
||||
certSlug: 'data-analysis-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e46f7f8ac417301a38fb92a',
|
||||
title: 'Medical Data Visualizer',
|
||||
link: `${dataAnalysisPyBase}/medical-data-visualizer`,
|
||||
superBlock: 'data-analysis-with-python-v7'
|
||||
certSlug: 'data-analysis-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e46f802ac417301a38fb92b',
|
||||
title: 'Page View Time Series Visualizer',
|
||||
link: `${dataAnalysisPyBase}/page-view-time-series-visualizer`,
|
||||
superBlock: 'data-analysis-with-python-v7'
|
||||
certSlug: 'data-analysis-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e4f5c4b570f7e3a4949899f',
|
||||
title: 'Sea Level Predictor',
|
||||
link: `${dataAnalysisPyBase}/sea-level-predictor`,
|
||||
superBlock: 'data-analysis-with-python-v7'
|
||||
certSlug: 'data-analysis-with-python-v7'
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -584,76 +584,76 @@ const certMap = [
|
||||
{
|
||||
id: '5e6021435ac9d0ecd8b94b00',
|
||||
title: 'Information Security',
|
||||
slug: 'information-security-v7',
|
||||
certSlug: 'information-security-v7',
|
||||
flag: 'isInfosecCertV7',
|
||||
projects: [
|
||||
{
|
||||
id: '587d824a367417b2b2512c44',
|
||||
title: 'Stock Price Checker',
|
||||
link: `${infoSecBase}/stock-price-checker`,
|
||||
superBlock: 'information-security-v7'
|
||||
certSlug: 'information-security-v7'
|
||||
},
|
||||
{
|
||||
id: '587d824a367417b2b2512c45',
|
||||
title: 'Anonymous Message Board',
|
||||
link: `${infoSecBase}/anonymous-message-board`,
|
||||
superBlock: 'information-security-v7'
|
||||
certSlug: 'information-security-v7'
|
||||
},
|
||||
{
|
||||
id: '5e46f979ac417301a38fb932',
|
||||
title: 'Port Scanner',
|
||||
link: `${infoSecBase}/port-scanner`,
|
||||
superBlock: 'information-security-v7'
|
||||
certSlug: 'information-security-v7'
|
||||
},
|
||||
{
|
||||
id: '5e46f983ac417301a38fb933',
|
||||
title: 'SHA-1 Password Cracker',
|
||||
link: `${infoSecBase}/sha-1-password-cracker`,
|
||||
superBlock: 'information-security-v7'
|
||||
certSlug: 'information-security-v7'
|
||||
},
|
||||
{
|
||||
id: '5e601c775ac9d0ecd8b94aff',
|
||||
title: 'Secure Real Time Multiplayer Game',
|
||||
link: `${infoSecBase}/secure-real-time-multiplayer-game`,
|
||||
superBlock: 'information-security-v7'
|
||||
certSlug: 'information-security-v7'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: '5e46fc95ac417301a38fb935',
|
||||
title: 'Machine Learning with Python',
|
||||
slug: 'machine-learning-with-python-v7',
|
||||
certSlug: 'machine-learning-with-python-v7',
|
||||
flag: 'isMachineLearningPyCertV7',
|
||||
projects: [
|
||||
{
|
||||
id: '5e46f8d6ac417301a38fb92d',
|
||||
title: 'Rock Paper Scissors',
|
||||
link: `${machineLearningPyBase}/rock-paper-scissors`,
|
||||
superBlock: 'machine-learning-with-python-v7'
|
||||
certSlug: 'machine-learning-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e46f8dcac417301a38fb92e',
|
||||
title: 'Cat and Dog Image Classifier',
|
||||
link: `${machineLearningPyBase}/cat-and-dog-image-classifier`,
|
||||
superBlock: 'machine-learning-with-python-v7'
|
||||
certSlug: 'machine-learning-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e46f8e3ac417301a38fb92f',
|
||||
title: 'Book Recommendation Engine using KNN',
|
||||
link: `${machineLearningPyBase}/book-recommendation-engine-using-knn`,
|
||||
superBlock: 'machine-learning-with-python-v7'
|
||||
certSlug: 'machine-learning-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e46f8edac417301a38fb930',
|
||||
title: 'Linear Regression Health Costs Calculator',
|
||||
link: `${machineLearningPyBase}/linear-regression-health-costs-calculator`,
|
||||
superBlock: 'machine-learning-with-python-v7'
|
||||
certSlug: 'machine-learning-with-python-v7'
|
||||
},
|
||||
{
|
||||
id: '5e46f8edac417301a38fb931',
|
||||
title: 'Neural Network SMS Text Classifier',
|
||||
link: `${machineLearningPyBase}/neural-network-sms-text-classifier`,
|
||||
superBlock: 'machine-learning-with-python-v7'
|
||||
certSlug: 'machine-learning-with-python-v7'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -19,10 +19,11 @@ import { Spacer } from '../../components/helpers';
|
||||
import {
|
||||
currentChallengeIdSelector,
|
||||
userFetchStateSelector,
|
||||
isSignedInSelector
|
||||
isSignedInSelector,
|
||||
userSelector
|
||||
} from '../../redux';
|
||||
import { resetExpansion, toggleBlock } from './redux';
|
||||
import { MarkdownRemark, AllChallengeNode } from '../../redux/propTypes';
|
||||
import { MarkdownRemark, AllChallengeNode, User } from '../../redux/propTypes';
|
||||
|
||||
import './intro.css';
|
||||
|
||||
@ -47,7 +48,8 @@ const propTypes = {
|
||||
}),
|
||||
resetExpansion: PropTypes.func,
|
||||
t: PropTypes.func,
|
||||
toggleBlock: PropTypes.func
|
||||
toggleBlock: PropTypes.func,
|
||||
user: User
|
||||
};
|
||||
|
||||
configureAnchors({ offset: -40, scrollDuration: 0 });
|
||||
@ -57,10 +59,12 @@ const mapStateToProps = state => {
|
||||
currentChallengeIdSelector,
|
||||
isSignedInSelector,
|
||||
userFetchStateSelector,
|
||||
(currentChallengeId, isSignedIn, fetchState) => ({
|
||||
userSelector,
|
||||
(currentChallengeId, isSignedIn, fetchState, user) => ({
|
||||
currentChallengeId,
|
||||
isSignedIn,
|
||||
fetchState
|
||||
fetchState,
|
||||
user
|
||||
})
|
||||
)(state);
|
||||
};
|
||||
@ -137,12 +141,12 @@ class SuperBlockIntroductionPage extends Component {
|
||||
allChallengeNode: { edges }
|
||||
},
|
||||
isSignedIn,
|
||||
t
|
||||
t,
|
||||
user
|
||||
} = this.props;
|
||||
|
||||
const nodesForSuperBlock = edges.map(({ node }) => node);
|
||||
const blockDashedNames = uniq(nodesForSuperBlock.map(({ block }) => block));
|
||||
|
||||
const i18nSuperBlock = t(`intro:${superBlock}.title`);
|
||||
|
||||
return (
|
||||
@ -168,14 +172,18 @@ class SuperBlockIntroductionPage extends Component {
|
||||
challenges={nodesForSuperBlock.filter(
|
||||
node => node.block === blockDashedName
|
||||
)}
|
||||
superBlockDashedName={superBlock}
|
||||
superBlock={superBlock}
|
||||
/>
|
||||
{blockDashedName !== 'project-euler' ? <Spacer /> : null}
|
||||
</Fragment>
|
||||
))}
|
||||
{superBlock !== 'coding-interview-prep' && (
|
||||
<div>
|
||||
<CertChallenge superBlock={superBlock} title={title} />
|
||||
<CertChallenge
|
||||
superBlock={superBlock}
|
||||
title={title}
|
||||
user={user}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -40,7 +40,7 @@ const propTypes = {
|
||||
completedChallenges: PropTypes.arrayOf(PropTypes.string),
|
||||
executeGA: PropTypes.func,
|
||||
isExpanded: PropTypes.bool,
|
||||
superBlockDashedName: PropTypes.string,
|
||||
superBlock: PropTypes.string,
|
||||
t: PropTypes.func,
|
||||
toggleBlock: PropTypes.func.isRequired
|
||||
};
|
||||
@ -90,7 +90,7 @@ export class Block extends Component {
|
||||
completedChallenges,
|
||||
challenges,
|
||||
isExpanded,
|
||||
superBlockDashedName,
|
||||
superBlock,
|
||||
t
|
||||
} = this.props;
|
||||
|
||||
@ -123,9 +123,7 @@ export class Block extends Component {
|
||||
);
|
||||
});
|
||||
|
||||
const blockIntroObj = t(
|
||||
`intro:${superBlockDashedName}.blocks.${blockDashedName}`
|
||||
);
|
||||
const blockIntroObj = t(`intro:${superBlock}.blocks.${blockDashedName}`);
|
||||
const blockTitle = blockIntroObj ? blockIntroObj.title : null;
|
||||
const blockIntroArr = blockIntroObj ? blockIntroObj.intro : [];
|
||||
const {
|
||||
@ -144,7 +142,7 @@ export class Block extends Component {
|
||||
<span className='block-link-icon'>#</span>
|
||||
</h3>
|
||||
</a>
|
||||
{!isAuditedCert(curriculumLocale, superBlockDashedName) && (
|
||||
{!isAuditedCert(curriculumLocale, superBlock) && (
|
||||
<div className='block-cta-wrapper'>
|
||||
<Link
|
||||
className='block-title-translation-cta'
|
||||
@ -172,7 +170,7 @@ export class Block extends Component {
|
||||
<span className='block-link-icon'>#</span>
|
||||
</h3>
|
||||
</a>
|
||||
{!isAuditedCert(curriculumLocale, superBlockDashedName) && (
|
||||
{!isAuditedCert(curriculumLocale, superBlock) && (
|
||||
<div className='block-cta-wrapper'>
|
||||
<Link
|
||||
className='block-title-translation-cta'
|
||||
|
@ -8,21 +8,29 @@ import { withTranslation } from 'react-i18next';
|
||||
import CertificationIcon from '../../../assets/icons/CertificationIcon';
|
||||
import GreenPass from '../../../assets/icons/GreenPass';
|
||||
import GreenNotCompleted from '../../../assets/icons/GreenNotCompleted';
|
||||
import { userSelector } from '../../../redux';
|
||||
import { User } from '../../../redux/propTypes';
|
||||
import { certificatesByNameSelector } from '../../../redux';
|
||||
import { CurrentCertsType, User } from '../../../redux/propTypes';
|
||||
import { certMap } from '../../../resources/certAndProjectMap';
|
||||
import {
|
||||
certSlugTypeMap,
|
||||
superBlockCertTypeMap
|
||||
} from '../../../../../config/certification-settings';
|
||||
|
||||
const propTypes = {
|
||||
currentCerts: CurrentCertsType,
|
||||
superBlock: PropTypes.string,
|
||||
t: PropTypes.func,
|
||||
title: PropTypes.string,
|
||||
user: User
|
||||
};
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return createSelector(userSelector, user => ({
|
||||
user
|
||||
}))(state);
|
||||
const mapStateToProps = (state, props) => {
|
||||
return createSelector(
|
||||
certificatesByNameSelector(props.user.username),
|
||||
({ currentCerts }) => ({
|
||||
currentCerts
|
||||
})
|
||||
)(state, props);
|
||||
};
|
||||
|
||||
export class CertChallenge extends Component {
|
||||
@ -31,37 +39,16 @@ export class CertChallenge extends Component {
|
||||
superBlock,
|
||||
t,
|
||||
title,
|
||||
user: {
|
||||
is2018DataVisCert,
|
||||
isApisMicroservicesCert,
|
||||
isFrontEndLibsCert,
|
||||
isQaCertV7,
|
||||
isInfosecCertV7,
|
||||
isJsAlgoDataStructCert,
|
||||
isRespWebDesignCert,
|
||||
isSciCompPyCertV7,
|
||||
isDataAnalysisPyCertV7,
|
||||
isMachineLearningPyCertV7,
|
||||
username
|
||||
}
|
||||
user: { username },
|
||||
currentCerts
|
||||
} = this.props;
|
||||
|
||||
const userCertificates = {
|
||||
'responsive-web-design': isRespWebDesignCert,
|
||||
'javascript-algorithms-and-data-structures': isJsAlgoDataStructCert,
|
||||
'front-end-libraries': isFrontEndLibsCert,
|
||||
'data-visualization': is2018DataVisCert,
|
||||
'apis-and-microservices': isApisMicroservicesCert,
|
||||
'quality-assurance': isQaCertV7,
|
||||
'information-security': isInfosecCertV7,
|
||||
'scientific-computing-with-python': isSciCompPyCertV7,
|
||||
'data-analysis-with-python': isDataAnalysisPyCertV7,
|
||||
'machine-learning-with-python': isMachineLearningPyCertV7
|
||||
};
|
||||
|
||||
const cert = certMap.find(x => x.title === title);
|
||||
const isCertified = userCertificates[superBlock];
|
||||
const certLocation = `/certification/${username}/${cert.slug}`;
|
||||
const isCertified = currentCerts.find(
|
||||
cert =>
|
||||
certSlugTypeMap[cert.certSlug] === superBlockCertTypeMap[superBlock]
|
||||
).show;
|
||||
const certLocation = `/certification/${username}/${cert.certSlug}`;
|
||||
const certCheckmarkStyle = { height: '40px', width: '40px' };
|
||||
const i18nSuperBlock = t(`intro:${superBlock}.title`);
|
||||
const i18nCertText = t(`intro:misc-text.certification`, {
|
||||
|
@ -47,8 +47,8 @@ export function getUserProfile(username) {
|
||||
return get(`/api/users/get-public-profile?username=${username}`);
|
||||
}
|
||||
|
||||
export function getShowCert(username, cert) {
|
||||
return get(`/certificate/showCert/${username}/${cert}`);
|
||||
export function getShowCert(username, certSlug) {
|
||||
return get(`/certificate/showCert/${username}/${certSlug}`);
|
||||
}
|
||||
|
||||
export function getUsernameExists(username) {
|
||||
@ -114,8 +114,8 @@ export function putUserUpdateEmail(email) {
|
||||
return put('/update-my-email', { email });
|
||||
}
|
||||
|
||||
export function putVerifyCert(superBlock) {
|
||||
return put('/certificate/verify', { superBlock });
|
||||
export function putVerifyCert(certSlug) {
|
||||
return put('/certificate/verify', { certSlug });
|
||||
}
|
||||
|
||||
/** DELETE **/
|
||||
|
@ -52,7 +52,7 @@ const completionHours = {
|
||||
[certTypes.machineLearningPyV7]: 300
|
||||
};
|
||||
|
||||
const superBlockCertTypeMap = {
|
||||
const certSlugTypeMap = {
|
||||
// legacy
|
||||
'legacy-front-end': certTypes.frontEnd,
|
||||
'legacy-back-end': certTypes.backEnd,
|
||||
@ -75,6 +75,27 @@ const superBlockCertTypeMap = {
|
||||
'machine-learning-with-python-v7': certTypes.machineLearningPyV7
|
||||
};
|
||||
|
||||
const superBlockCertTypeMap = {
|
||||
// legacy
|
||||
'legacy-front-end': certTypes.frontEnd,
|
||||
'legacy-back-end': certTypes.backEnd,
|
||||
'legacy-data-visualization': certTypes.dataVis,
|
||||
'information-security-and-quality-assurance': certTypes.infosecQa,
|
||||
'full-stack': certTypes.fullStack,
|
||||
|
||||
// modern
|
||||
'responsive-web-design': certTypes.respWebDesign,
|
||||
'javascript-algorithms-and-data-structures': certTypes.jsAlgoDataStruct,
|
||||
'front-end-libraries': certTypes.frontEndLibs,
|
||||
'data-visualization': certTypes.dataVis2018,
|
||||
'apis-and-microservices': certTypes.apisMicroservices,
|
||||
'quality-assurance': certTypes.qaV7,
|
||||
'information-security': certTypes.infosecV7,
|
||||
'scientific-computing-with-python': certTypes.sciCompPyV7,
|
||||
'data-analysis-with-python': certTypes.dataAnalysisPyV7,
|
||||
'machine-learning-with-python': certTypes.machineLearningPyV7
|
||||
};
|
||||
|
||||
const certTypeIdMap = {
|
||||
[certTypes.frontEnd]: certIds.legacyFrontEndChallengeId,
|
||||
[certTypes.backEnd]: certIds.legacyBackEndChallengeId,
|
||||
@ -115,6 +136,7 @@ exports.oldDataVizId = '561add10cb82ac38a17513b3';
|
||||
exports.completionHours = completionHours;
|
||||
exports.certTypes = certTypes;
|
||||
exports.superBlockCertTypeMap = superBlockCertTypeMap;
|
||||
exports.certSlugTypeMap = certSlugTypeMap;
|
||||
exports.certIds = certIds;
|
||||
exports.certTypeIdMap = certTypeIdMap;
|
||||
exports.certTypeTitleMap = certTypeTitleMap;
|
||||
|
Reference in New Issue
Block a user