mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(client): move legacy rwd button to bottom of map (#47596)
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com> Closes https://github.com/freeCodeCamp/freeCodeCamp/issues/46523
This commit is contained in:
@@ -5,4 +5,5 @@ api-server/src/public/**
|
||||
api-server/lib/**
|
||||
config/i18n.js
|
||||
config/certification-settings.js
|
||||
config/superblock-order.js
|
||||
web/**
|
||||
|
||||
@@ -164,6 +164,8 @@ config/client/test-evaluator.json
|
||||
config/curriculum.json
|
||||
config/i18n.js
|
||||
config/certification-settings.js
|
||||
config/superblock-order.js
|
||||
config/superblock-order.test.js
|
||||
|
||||
### Generated utils files ###
|
||||
utils/block-nameify.js
|
||||
|
||||
@@ -7,6 +7,8 @@ curriculum/challenges/**/*
|
||||
config/**/*.json
|
||||
config/i18n.js
|
||||
config/certification-settings.js
|
||||
config/superblock-order.js
|
||||
config/superblock-order.test.js
|
||||
docs/i18n
|
||||
utils/block-nameify.js
|
||||
utils/block-nameify.test.js
|
||||
|
||||
@@ -480,7 +480,7 @@ export class NavLinks extends Component<NavLinksProps, NavlinkStates> {
|
||||
className='nav-link nav-lang-menu-option'
|
||||
data-value={lang}
|
||||
{...(LangCodes[lang] && {
|
||||
lang: LangCodes[lang] as string
|
||||
lang: LangCodes[lang]
|
||||
})}
|
||||
onClick={this.handleLanguageChange}
|
||||
onKeyDown={this.handleLanguageMenuKeyDown}
|
||||
|
||||
@@ -1,535 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Map /> snapshot: Map 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="map-ui"
|
||||
data-test-label="learn-curriculum-map"
|
||||
>
|
||||
<ul
|
||||
data-test-label="certifications"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-one/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-four/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-one/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-one/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-one/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-one/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-two/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-two/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-two/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-two/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-three/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-three/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
class="btn link-btn btn-lg"
|
||||
href="/learn/super-block-three/"
|
||||
>
|
||||
<div
|
||||
style="display: flex; justify-content: space-between; align-items: center; gap: 15px;"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="map-icon"
|
||||
viewBox="0 0 640 512"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M112 48h352v48h48V32a32.09 32.09 0 00-32-32H96a32.09 32.09 0 00-32 32v256H16a16 16 0 00-16 16v16a64.14 64.14 0 0063.91 64H352v-96H112zm492 80H420a36 36 0 00-36 36v312a36 36 0 0036 36h184a36 36 0 0036-36V164a36 36 0 00-36-36zm-12 336H432V176h160z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="inherit"
|
||||
height="20px"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 20"
|
||||
width="18px"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<g>
|
||||
<polygon
|
||||
points="-2.68014473e-15 -1.06357708e-13 2.01917516 -1.06357708e-13 8.99824941 9.00746464 2.01917516 18.0149293 -2.66453526e-15 18.0149293 7.00955027 9"
|
||||
/>
|
||||
<polygon
|
||||
points="7.99971435 -1.06357708e-13 10.0188895 -1.06357708e-13 16.9979638 9.00746464 10.0188895 18.0149293 7.99971435 18.0149293 15.0092646 9"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,39 +1,29 @@
|
||||
import { graphql, useStaticQuery } from 'gatsby';
|
||||
import i18next from 'i18next';
|
||||
import React from 'react';
|
||||
|
||||
import { SuperBlocks } from '../../../../config/certification-settings';
|
||||
import {
|
||||
CurriculumMaps,
|
||||
getAuditedSuperBlocks,
|
||||
getNotAuditedSuperBlocks,
|
||||
superBlockOrder
|
||||
} from '../../../../config/superblock-order';
|
||||
import { Languages } from '../../../../config/i18n';
|
||||
import envData from '../../../../config/env.json';
|
||||
import { isAuditedCert } from '../../../../utils/is-audited';
|
||||
import { generateIconComponent } from '../../assets/icons';
|
||||
import LinkButton from '../../assets/icons/link-button';
|
||||
import { ChallengeNode } from '../../redux/prop-types';
|
||||
import { Link, Spacer } from '../helpers';
|
||||
import { getSuperBlockTitleForMap } from '../../utils/superblock-map-titles';
|
||||
|
||||
import './map.css';
|
||||
|
||||
const { curriculumLocale } = envData;
|
||||
const { curriculumLocale, showNewCurriculum, showUpcomingChanges } = envData;
|
||||
|
||||
interface MapProps {
|
||||
currentSuperBlock?: SuperBlocks | null;
|
||||
forLanding?: boolean;
|
||||
}
|
||||
|
||||
interface MapData {
|
||||
allChallengeNode: {
|
||||
nodes: ChallengeNode[];
|
||||
};
|
||||
}
|
||||
|
||||
function createSuperBlockTitle(superBlock: SuperBlocks) {
|
||||
const superBlockTitle = i18next.t(`intro:${superBlock}.title`);
|
||||
return superBlock === 'coding-interview-prep'
|
||||
? superBlockTitle
|
||||
: i18next.t('learn.cert-map-estimates.certs', {
|
||||
title: superBlockTitle
|
||||
});
|
||||
}
|
||||
|
||||
const linkSpacingStyle = {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
@@ -41,102 +31,91 @@ const linkSpacingStyle = {
|
||||
gap: '15px'
|
||||
};
|
||||
|
||||
function renderLandingMap(nodes: ChallengeNode[]) {
|
||||
nodes = nodes.filter(
|
||||
({ challenge }) => challenge.superBlock !== SuperBlocks.CodingInterviewPrep
|
||||
function MapLi({
|
||||
superBlock,
|
||||
landing = false
|
||||
}: {
|
||||
superBlock: SuperBlocks;
|
||||
landing: boolean;
|
||||
}) {
|
||||
return (
|
||||
<li>
|
||||
<Link className='btn link-btn btn-lg' to={`/learn/${superBlock}/`}>
|
||||
<div style={linkSpacingStyle}>
|
||||
{generateIconComponent(superBlock, 'map-icon')}
|
||||
{getSuperBlockTitleForMap(superBlock)}
|
||||
</div>
|
||||
{landing && <LinkButton />}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
function renderLandingMap() {
|
||||
const landingSuperOrder =
|
||||
superBlockOrder[curriculumLocale as Languages][CurriculumMaps.Landing];
|
||||
|
||||
return (
|
||||
<ul data-test-label='certifications'>
|
||||
{nodes.map(({ challenge }, i) => (
|
||||
<li key={i}>
|
||||
<Link
|
||||
className='btn link-btn btn-lg'
|
||||
to={`/learn/${challenge.superBlock}/`}
|
||||
>
|
||||
<div style={linkSpacingStyle}>
|
||||
{generateIconComponent(challenge.superBlock, 'map-icon')}
|
||||
{i18next.t(`intro:${challenge.superBlock}.title`)}
|
||||
</div>
|
||||
<LinkButton />
|
||||
</Link>
|
||||
</li>
|
||||
{landingSuperOrder.map((superBlock, i) => (
|
||||
<MapLi superBlock={superBlock} key={i} landing={true} />
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
function renderLearnMap(
|
||||
nodes: ChallengeNode[],
|
||||
currentSuperBlock: MapProps['currentSuperBlock']
|
||||
) {
|
||||
nodes = nodes.filter(
|
||||
({ challenge }) => challenge.superBlock !== currentSuperBlock
|
||||
function renderLearnMap(currentSuperBlock: MapProps['currentSuperBlock']) {
|
||||
const tempAuditedSuperBlocks = getAuditedSuperBlocks({
|
||||
language: curriculumLocale,
|
||||
showNewCurriculum: showNewCurriculum.toString(),
|
||||
showUpcomingChanges: showUpcomingChanges.toString()
|
||||
});
|
||||
const tempNotAuditedSuperBlocks = getNotAuditedSuperBlocks({
|
||||
language: curriculumLocale,
|
||||
showNewCurriculum: showNewCurriculum.toString(),
|
||||
showUpcomingChanges: showUpcomingChanges.toString()
|
||||
});
|
||||
|
||||
const auditedSuperBlocks = tempAuditedSuperBlocks.filter(
|
||||
superBlock => superBlock !== currentSuperBlock
|
||||
);
|
||||
return curriculumLocale === 'english' ? (
|
||||
|
||||
const notAuditedSuperBlocks = tempNotAuditedSuperBlocks.filter(
|
||||
superBlock => superBlock !== currentSuperBlock
|
||||
);
|
||||
|
||||
return (
|
||||
<ul data-test-label='learn-curriculum-map'>
|
||||
{nodes.map(({ challenge }, i) => (
|
||||
<li key={i}>
|
||||
<Link
|
||||
className='btn link-btn btn-lg'
|
||||
to={`/learn/${challenge.superBlock}/`}
|
||||
>
|
||||
<div style={linkSpacingStyle}>
|
||||
{generateIconComponent(challenge.superBlock, 'map-icon')}
|
||||
{createSuperBlockTitle(challenge.superBlock)}
|
||||
</div>
|
||||
</Link>
|
||||
</li>
|
||||
{/* audited superblocks */}
|
||||
{auditedSuperBlocks.map((superBlock, i) => (
|
||||
<MapLi key={i} superBlock={superBlock} landing={false} />
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<ul data-test-label='learn-curriculum-map'>
|
||||
{nodes
|
||||
.filter(({ challenge }) =>
|
||||
isAuditedCert(curriculumLocale, challenge.superBlock)
|
||||
)
|
||||
.map(({ challenge }, i) => (
|
||||
<li key={i}>
|
||||
|
||||
{/* has not audited superblocks */}
|
||||
{notAuditedSuperBlocks.length > 0 && (
|
||||
<>
|
||||
{' '}
|
||||
<hr />
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<p style={{ marginBottom: 0 }}>
|
||||
{i18next.t('learn.help-translate')}{' '}
|
||||
</p>
|
||||
<Link
|
||||
className='btn link-btn btn-lg'
|
||||
to={`/learn/${challenge.superBlock}/`}
|
||||
external={true}
|
||||
sameTab={false}
|
||||
to={i18next.t('links:help-translate-link-url')}
|
||||
>
|
||||
<div style={linkSpacingStyle}>
|
||||
{generateIconComponent(challenge.superBlock, 'map-icon')}
|
||||
{createSuperBlockTitle(challenge.superBlock)}
|
||||
</div>
|
||||
{i18next.t('learn.help-translate-link')}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
<hr />
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<p style={{ marginBottom: 0 }}>{i18next.t('learn.help-translate')} </p>
|
||||
<Link
|
||||
external={true}
|
||||
sameTab={false}
|
||||
to={i18next.t('links:help-translate-link-url')}
|
||||
>
|
||||
{i18next.t('learn.help-translate-link')}
|
||||
</Link>
|
||||
<Spacer />
|
||||
</div>
|
||||
{nodes
|
||||
.filter(
|
||||
({ challenge }) =>
|
||||
!isAuditedCert(curriculumLocale, challenge.superBlock)
|
||||
)
|
||||
.map(({ challenge }, i) => (
|
||||
<li key={i}>
|
||||
<Link
|
||||
className='btn link-btn btn-lg'
|
||||
to={`/learn/${challenge.superBlock}/`}
|
||||
>
|
||||
<div style={linkSpacingStyle}>
|
||||
{generateIconComponent(challenge.superBlock, 'map-icon')}
|
||||
{createSuperBlockTitle(challenge.superBlock)}
|
||||
</div>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
<Spacer />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* not audited superblocks */}
|
||||
{notAuditedSuperBlocks.map((superBlock, i) => (
|
||||
<MapLi key={i} superBlock={superBlock} landing={false} />
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
@@ -145,39 +124,9 @@ export function Map({
|
||||
forLanding = false,
|
||||
currentSuperBlock = null
|
||||
}: MapProps): React.ReactElement {
|
||||
/*
|
||||
* this query gets the first challenge from each block and the first block
|
||||
* from each superblock, leaving you with one challenge from each
|
||||
* superblock
|
||||
*/
|
||||
const data: MapData = useStaticQuery(graphql`
|
||||
query SuperBlockNodes {
|
||||
allChallengeNode(
|
||||
sort: { fields: [challenge___superOrder] }
|
||||
filter: { challenge: { order: { eq: 0 }, challengeOrder: { eq: 0 } } }
|
||||
) {
|
||||
nodes {
|
||||
challenge {
|
||||
superBlock
|
||||
dashedName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
const nodes = data.allChallengeNode.nodes;
|
||||
const temp = [
|
||||
nodes[0],
|
||||
nodes[12],
|
||||
...nodes.filter((_, i) => i !== 0 && i !== 12)
|
||||
];
|
||||
|
||||
return (
|
||||
<div className='map-ui' data-test-label='learn-curriculum-map'>
|
||||
{forLanding
|
||||
? renderLandingMap(temp)
|
||||
: renderLearnMap(temp, currentSuperBlock)}
|
||||
{forLanding ? renderLandingMap() : renderLearnMap(currentSuperBlock)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { useStaticQuery } from 'gatsby';
|
||||
import React from 'react';
|
||||
|
||||
import mockChallengeNodes from '../../__mocks__/challenge-nodes';
|
||||
import { Map } from '.';
|
||||
|
||||
beforeEach(() => {
|
||||
(useStaticQuery as jest.Mock).mockImplementationOnce(() => ({
|
||||
allChallengeNode: {
|
||||
nodes: mockChallengeNodes
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
// set .scrollTo to avoid errors in default test environment
|
||||
window.scrollTo = jest.fn();
|
||||
|
||||
test('<Map /> snapshot', () => {
|
||||
const { container } = render(<Map {...props} />);
|
||||
|
||||
expect(container).toMatchSnapshot('Map');
|
||||
});
|
||||
|
||||
const props = {
|
||||
forLanding: true
|
||||
};
|
||||
@@ -11,6 +11,7 @@ import { bindActionCreators, Dispatch } from 'redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import { SuperBlocks } from '../../../../config/certification-settings';
|
||||
import { getSuperBlockTitleForMap } from '../../utils/superblock-map-titles';
|
||||
import DonateModal from '../../components/Donation/donation-modal';
|
||||
import Login from '../../components/Header/components/Login';
|
||||
import Map from '../../components/Map';
|
||||
@@ -177,14 +178,7 @@ const SuperBlockIntroductionPage = (props: SuperBlockProp) => {
|
||||
nodesForSuperBlock.map(({ challenge: { block } }) => block)
|
||||
);
|
||||
|
||||
const i18nSuperBlock = t(`intro:${superBlock}.title`);
|
||||
const i18nTitle =
|
||||
superBlock === SuperBlocks.CodingInterviewPrep
|
||||
? i18nSuperBlock
|
||||
: t(`intro:misc-text.certification`, {
|
||||
cert: i18nSuperBlock
|
||||
});
|
||||
|
||||
const i18nTitle = getSuperBlockTitleForMap(superBlock);
|
||||
const defaultCurriculumNames = blockDashedNames;
|
||||
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import i18next from 'i18next';
|
||||
import { SuperBlocks } from '../../../config/certification-settings';
|
||||
|
||||
// these are keys from i18n translations.json files
|
||||
enum SuperBlockI18nKeys {
|
||||
Certification = 'learn.cert-map-estimates.certs'
|
||||
}
|
||||
|
||||
// the key above is used to create the last word for superBlock titles used on
|
||||
// the map and window. e.g. 'Certification' in Responsive Web Design
|
||||
// Certification
|
||||
const superBlocksWithoutLastWord = [SuperBlocks.CodingInterviewPrep];
|
||||
|
||||
export function getSuperBlockTitleForMap(superBlock: SuperBlocks) {
|
||||
const i18nSuperBlock = i18next.t(`intro:${superBlock}.title`);
|
||||
|
||||
return superBlocksWithoutLastWord.includes(superBlock)
|
||||
? i18nSuperBlock
|
||||
: i18next.t([SuperBlockI18nKeys.Certification], {
|
||||
title: i18nSuperBlock
|
||||
});
|
||||
}
|
||||
+67
-188
@@ -1,5 +1,16 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
import { SuperBlocks } from './certification-settings';
|
||||
export enum Languages {
|
||||
English = 'english',
|
||||
Espanol = 'espanol',
|
||||
Chinese = 'chinese',
|
||||
ChineseTrandational = 'chinese-traditional',
|
||||
Italian = 'italian',
|
||||
Portuguese = 'portuguese',
|
||||
Ukrainian = 'ukrainian',
|
||||
Japanese = 'japanese',
|
||||
German = 'german',
|
||||
Arabic = 'arabic'
|
||||
}
|
||||
|
||||
/*
|
||||
* List of languages with localizations enabled for builds.
|
||||
*
|
||||
@@ -10,160 +21,31 @@ import { SuperBlocks } from './certification-settings';
|
||||
*/
|
||||
export const availableLangs = {
|
||||
client: [
|
||||
'english',
|
||||
'espanol',
|
||||
'chinese',
|
||||
'chinese-traditional',
|
||||
'italian',
|
||||
'portuguese',
|
||||
'ukrainian',
|
||||
'japanese',
|
||||
'german',
|
||||
'arabic'
|
||||
Languages.English,
|
||||
Languages.Espanol,
|
||||
Languages.Chinese,
|
||||
Languages.ChineseTrandational,
|
||||
Languages.Italian,
|
||||
Languages.Portuguese,
|
||||
Languages.Ukrainian,
|
||||
Languages.Japanese,
|
||||
Languages.German,
|
||||
Languages.Arabic
|
||||
],
|
||||
curriculum: [
|
||||
'english',
|
||||
'espanol',
|
||||
'chinese',
|
||||
'chinese-traditional',
|
||||
'italian',
|
||||
'portuguese',
|
||||
'ukrainian',
|
||||
'japanese',
|
||||
'german',
|
||||
'arabic'
|
||||
Languages.English,
|
||||
Languages.Espanol,
|
||||
Languages.Chinese,
|
||||
Languages.ChineseTrandational,
|
||||
Languages.Italian,
|
||||
Languages.Portuguese,
|
||||
Languages.Ukrainian,
|
||||
Languages.Japanese,
|
||||
Languages.German,
|
||||
Languages.Arabic
|
||||
]
|
||||
};
|
||||
|
||||
/*
|
||||
* List of certifications with localization enabled in their world language.
|
||||
*
|
||||
* These certifications have been approved 100% on Crowdin at least during
|
||||
* their launch, and hence meet the QA standard to be published live. Other
|
||||
* certifications which have not been audited & approved will fallback to
|
||||
* English equivalent.
|
||||
*/
|
||||
export const auditedCerts = {
|
||||
espanol: [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy
|
||||
],
|
||||
chinese: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
'chinese-traditional': [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
italian: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep
|
||||
],
|
||||
portuguese: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep,
|
||||
SuperBlocks.RelationalDb
|
||||
],
|
||||
ukrainian: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.RelationalDb
|
||||
],
|
||||
japanese: [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep,
|
||||
SuperBlocks.RelationalDb
|
||||
],
|
||||
german: [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs
|
||||
],
|
||||
arabic: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* This contains the list of languages which have a beta->stable release
|
||||
* that has been 100% translated. This will only be used during the window
|
||||
* where a beta goes to stable but the translation isn't complete yet.
|
||||
*/
|
||||
export const languagesWithAuditedBetaReleases = [
|
||||
'english',
|
||||
'portuguese',
|
||||
'italian',
|
||||
'ukrainian',
|
||||
'chinese',
|
||||
'chinese-traditional',
|
||||
'arabic'
|
||||
];
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Each client language needs an entry in the rest of the variables below
|
||||
@@ -173,51 +55,48 @@ export const languagesWithAuditedBetaReleases = [
|
||||
* Use a 639-1 code here https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
|
||||
*/
|
||||
export const i18nextCodes = {
|
||||
english: 'en',
|
||||
espanol: 'es',
|
||||
chinese: 'zh',
|
||||
'chinese-traditional': 'zh-Hant',
|
||||
italian: 'it',
|
||||
portuguese: 'pt-BR',
|
||||
ukrainian: 'uk',
|
||||
japanese: 'ja',
|
||||
german: 'de',
|
||||
arabic: 'ar'
|
||||
[Languages.English]: 'en',
|
||||
[Languages.Espanol]: 'es',
|
||||
[Languages.Chinese]: 'zh',
|
||||
[Languages.ChineseTrandational]: 'zh-Hant',
|
||||
[Languages.Italian]: 'it',
|
||||
[Languages.Portuguese]: 'pt-BR',
|
||||
[Languages.Ukrainian]: 'uk',
|
||||
[Languages.Japanese]: 'ja',
|
||||
[Languages.German]: 'de',
|
||||
[Languages.Arabic]: 'ar'
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
// These are for the language selector dropdown menu in the footer
|
||||
export enum LangNames {
|
||||
english = 'English',
|
||||
espanol = 'Español',
|
||||
chinese = '中文(简体字)',
|
||||
'chinese-traditional' = '中文(繁體字)',
|
||||
italian = 'Italiano',
|
||||
portuguese = 'Português',
|
||||
ukrainian = 'Українська',
|
||||
japanese = '日本語',
|
||||
german = 'Deutsch',
|
||||
arabic = 'العربية'
|
||||
}
|
||||
export const LangNames = {
|
||||
[Languages.English]: 'English',
|
||||
[Languages.Espanol]: 'Español',
|
||||
[Languages.Chinese]: '中文(简体字)',
|
||||
[Languages.ChineseTrandational]: '中文(繁體字)',
|
||||
[Languages.Italian]: 'Italiano',
|
||||
[Languages.Portuguese]: 'Português',
|
||||
[Languages.Ukrainian]: 'Українська',
|
||||
[Languages.Japanese]: '日本語',
|
||||
[Languages.German]: 'Deutsch',
|
||||
[Languages.Arabic]: 'العربية'
|
||||
};
|
||||
|
||||
/* These are for formatting dates and numbers. Used with JS .toLocaleString().
|
||||
* There's an example in profile/components/Camper.js
|
||||
* List: https://github.com/unicode-cldr/cldr-dates-modern/tree/master/main
|
||||
*/
|
||||
export enum LangCodes {
|
||||
english = 'en-US',
|
||||
espanol = 'es-419',
|
||||
chinese = 'zh',
|
||||
'chinese-traditional' = 'zh-Hant',
|
||||
italian = 'it',
|
||||
portuguese = 'pt-BR',
|
||||
ukrainian = 'uk',
|
||||
japanese = 'ja',
|
||||
german = 'de',
|
||||
arabic = 'ar'
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
export const LangCodes = {
|
||||
[Languages.English]: 'en-US',
|
||||
[Languages.Espanol]: 'es-419',
|
||||
[Languages.Chinese]: 'zh',
|
||||
[Languages.ChineseTrandational]: 'zh-Hant',
|
||||
[Languages.Italian]: 'it',
|
||||
[Languages.Portuguese]: 'pt-BR',
|
||||
[Languages.Ukrainian]: 'uk',
|
||||
[Languages.Japanese]: 'ja',
|
||||
[Languages.German]: 'de',
|
||||
[Languages.Arabic]: 'ar'
|
||||
};
|
||||
|
||||
/**
|
||||
* This array contains languages that should NOT appear in the language selector.
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
import { Languages } from './i18n';
|
||||
import { SuperBlocks } from './certification-settings';
|
||||
import {
|
||||
CurriculumMaps,
|
||||
defaultSuperBlockOrder,
|
||||
getAuditedSuperBlocks,
|
||||
getNotAuditedSuperBlocks,
|
||||
getLearnSuperBlocks,
|
||||
numberOfSuperBlocksOnLanding,
|
||||
superBlockOrder,
|
||||
SuperBlockStates,
|
||||
TranslationStates
|
||||
} from './superblock-order';
|
||||
|
||||
const superBlocks = Object.values(SuperBlocks);
|
||||
const translationStates = Object.values(TranslationStates);
|
||||
const superBlockStates = Object.values(SuperBlockStates);
|
||||
const superBlockOrderLanguages = Object.keys(superBlockOrder);
|
||||
|
||||
describe("'defaultSuperBlockOrder'", () => {
|
||||
it("should have a matching item for each value in the 'SuperBlocks' object", () => {
|
||||
expect(defaultSuperBlockOrder).toEqual(expect.arrayContaining(superBlocks));
|
||||
});
|
||||
|
||||
it('should not have any extra keys', () => {
|
||||
expect(defaultSuperBlockOrder.length).toEqual(superBlocks.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe("'superBlockOrder'", () => {
|
||||
superBlockOrderLanguages.forEach(language => {
|
||||
describe(`'${language}'`, () => {
|
||||
describe("'landing'", () => {
|
||||
const landingSuperBlocks =
|
||||
superBlockOrder[language as Languages][CurriculumMaps.Landing];
|
||||
|
||||
it(`should have ${numberOfSuperBlocksOnLanding} items (superBlocks)`, () => {
|
||||
expect(landingSuperBlocks.length).toEqual(
|
||||
numberOfSuperBlocksOnLanding
|
||||
);
|
||||
});
|
||||
|
||||
it('should not have a superBlock out of order', () => {
|
||||
landingSuperBlocks.forEach((superBlock, index) => {
|
||||
const defaultIndex = defaultSuperBlockOrder.indexOf(superBlock);
|
||||
const defaultSbsAfterCurrentSb = defaultSuperBlockOrder.slice(
|
||||
defaultIndex + 1
|
||||
);
|
||||
|
||||
for (let j = index + 1; j < landingSuperBlocks.length; j++) {
|
||||
expect(defaultSbsAfterCurrentSb).toContain(landingSuperBlocks[j]);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("'learn'", () => {
|
||||
const learn =
|
||||
superBlockOrder[language as Languages][CurriculumMaps.Learn];
|
||||
const audited = learn[TranslationStates.Audited];
|
||||
const notAudited = learn[TranslationStates.NotAudited];
|
||||
|
||||
describe("'audited'", () => {
|
||||
superBlockStates.forEach(superBlockState => {
|
||||
const stateSuperBlocks = audited[superBlockState];
|
||||
|
||||
describe(`'${superBlockState}'`, () => {
|
||||
it('should not have a superBlock out of order', () => {
|
||||
stateSuperBlocks.forEach((superBlock, index) => {
|
||||
const defaultIndex =
|
||||
defaultSuperBlockOrder.indexOf(superBlock);
|
||||
const defaultSbsAfterCurrentSb = defaultSuperBlockOrder.slice(
|
||||
defaultIndex + 1
|
||||
);
|
||||
|
||||
for (let j = index + 1; j < stateSuperBlocks.length; j++) {
|
||||
expect(defaultSbsAfterCurrentSb).toContain(
|
||||
stateSuperBlocks[j]
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('not audited', () => {
|
||||
superBlockStates.forEach(superBlockState => {
|
||||
const stateSuperBlocks = notAudited[superBlockState];
|
||||
|
||||
describe(`'${superBlockState}'`, () => {
|
||||
it('should not have a superBlock out of order', () => {
|
||||
stateSuperBlocks.forEach((superBlock, index) => {
|
||||
const defaultIndex =
|
||||
defaultSuperBlockOrder.indexOf(superBlock);
|
||||
const defaultSbsAfterCurrentSb = defaultSuperBlockOrder.slice(
|
||||
defaultIndex + 1
|
||||
);
|
||||
|
||||
for (let j = index + 1; j < stateSuperBlocks.length; j++) {
|
||||
expect(defaultSbsAfterCurrentSb).toContain(
|
||||
stateSuperBlocks[j]
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should have exactly one of each 'SuperBlocks' among it's children", () => {
|
||||
// flatten all ${language}.learn superblocks into one array
|
||||
const learnSuperBlocks: SuperBlocks[] = [];
|
||||
|
||||
translationStates.forEach(translationState => {
|
||||
superBlockStates.forEach(superBlockState => {
|
||||
learnSuperBlocks.push(
|
||||
...learn[translationState][superBlockState]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
superBlocks.forEach(superBlock => {
|
||||
expect(learnSuperBlocks).toContain(superBlock);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("'superBlockOrder' helper functions", () => {
|
||||
it("'getLearnSuperBlocks('english')' should return the correct array", () => {
|
||||
const learnSuperBlocks = getLearnSuperBlocks({
|
||||
language: 'english',
|
||||
showNewCurriculum: 'true',
|
||||
showUpcomingChanges: 'true'
|
||||
});
|
||||
const test = [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep,
|
||||
SuperBlocks.JsAlgoDataStructNew,
|
||||
SuperBlocks.RespWebDesign
|
||||
];
|
||||
expect(learnSuperBlocks).toStrictEqual(test);
|
||||
expect(learnSuperBlocks.length).toEqual(test.length);
|
||||
});
|
||||
|
||||
it("'getAuditedSuperBlocks('german')' should return the correct array", () => {
|
||||
const auditedSuperBlocks = getAuditedSuperBlocks({
|
||||
language: 'german',
|
||||
showNewCurriculum: 'true',
|
||||
showUpcomingChanges: 'true'
|
||||
});
|
||||
const test = [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs
|
||||
];
|
||||
expect(auditedSuperBlocks).toStrictEqual(test);
|
||||
expect(auditedSuperBlocks.length).toEqual(test.length);
|
||||
});
|
||||
|
||||
it("'getNotAuditedSuperBlocks('german')' should return the correct array", () => {
|
||||
const notAuditedSuperBlocks = getNotAuditedSuperBlocks({
|
||||
language: 'german',
|
||||
showNewCurriculum: 'true',
|
||||
showUpcomingChanges: 'true'
|
||||
});
|
||||
const test = [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep,
|
||||
SuperBlocks.JsAlgoDataStructNew
|
||||
];
|
||||
expect(notAuditedSuperBlocks).toStrictEqual(test);
|
||||
expect(notAuditedSuperBlocks.length).toEqual(test.length);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,626 @@
|
||||
import { Languages } from './i18n';
|
||||
import { SuperBlocks } from './certification-settings';
|
||||
|
||||
/*
|
||||
* .env SHOW_NEW_CURRICULUM = SuperBlockStates.New
|
||||
* 'New' -> shown only on english staging at the moment
|
||||
*
|
||||
* .env SHOW_UPCOMING_CHANGES = SuperBlockStates.Upcoming
|
||||
* 'Upcoming' is for development -> not shown on stag or prod anywhere
|
||||
*
|
||||
*/
|
||||
|
||||
export enum CurriculumMaps {
|
||||
Landing = 'landing',
|
||||
Learn = 'learn'
|
||||
}
|
||||
|
||||
export enum TranslationStates {
|
||||
Audited = 'audited',
|
||||
NotAudited = 'notAudited'
|
||||
}
|
||||
|
||||
export enum SuperBlockStates {
|
||||
Current = 'current',
|
||||
New = 'new',
|
||||
Upcoming = 'upcoming',
|
||||
Legacy = 'legacy'
|
||||
}
|
||||
|
||||
export const orderedSuperBlockStates = [
|
||||
SuperBlockStates.Current,
|
||||
SuperBlockStates.New,
|
||||
SuperBlockStates.Upcoming,
|
||||
SuperBlockStates.Legacy
|
||||
];
|
||||
|
||||
type SuperBlockOrder = {
|
||||
[key in Languages]: {
|
||||
[CurriculumMaps.Landing]: SuperBlocks[];
|
||||
[CurriculumMaps.Learn]: {
|
||||
[TranslationStates.Audited]: {
|
||||
[SuperBlockStates.Current]: SuperBlocks[];
|
||||
[SuperBlockStates.New]: SuperBlocks[];
|
||||
[SuperBlockStates.Upcoming]: SuperBlocks[];
|
||||
[SuperBlockStates.Legacy]: SuperBlocks[];
|
||||
};
|
||||
[TranslationStates.NotAudited]: {
|
||||
[SuperBlockStates.Current]: SuperBlocks[];
|
||||
[SuperBlockStates.New]: SuperBlocks[];
|
||||
[SuperBlockStates.Upcoming]: SuperBlocks[];
|
||||
[SuperBlockStates.Legacy]: SuperBlocks[];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// all languages should have this many, one for each current cert
|
||||
export const numberOfSuperBlocksOnLanding = 11;
|
||||
|
||||
/*
|
||||
* This is the used for tests to make sure a superBlock isn't out of order
|
||||
* e.g. so that a RWD button isn't below a JS button.
|
||||
* It compares each array in `superBlockOrder` to this - those arrays do not
|
||||
* have to include all these superBlocks, but the ones it does include, have
|
||||
* to be in this order
|
||||
*/
|
||||
export const defaultSuperBlockOrder: SuperBlocks[] = [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStructNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep
|
||||
];
|
||||
|
||||
/*
|
||||
* The order of superblocks in the arrays below are how they appear on the maps
|
||||
*
|
||||
* The 'Landing' map array should contain exactly one superblock for each
|
||||
* current, non-legacy certification, and only one superblock of each type -
|
||||
* e.g. only one RWD superblock (button)
|
||||
*
|
||||
* The 'Learn' map arrays should contain ALL available SuperBlocks, sorted into
|
||||
* their various states. These will be used to create the 'superOrder' property.
|
||||
*
|
||||
*/
|
||||
export const superBlockOrder: SuperBlockOrder = {
|
||||
[Languages.English]: {
|
||||
[CurriculumMaps.Landing]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[CurriculumMaps.Learn]: {
|
||||
[TranslationStates.Audited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
|
||||
[SuperBlockStates.Legacy]: [SuperBlocks.RespWebDesign]
|
||||
},
|
||||
[TranslationStates.NotAudited]: {
|
||||
[SuperBlockStates.Current]: [],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
}
|
||||
}
|
||||
},
|
||||
[Languages.Espanol]: {
|
||||
[CurriculumMaps.Landing]: [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[CurriculumMaps.Learn]: {
|
||||
[TranslationStates.Audited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
},
|
||||
[TranslationStates.NotAudited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
}
|
||||
}
|
||||
},
|
||||
[Languages.Chinese]: {
|
||||
[CurriculumMaps.Landing]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[CurriculumMaps.Learn]: {
|
||||
[TranslationStates.Audited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [],
|
||||
[SuperBlockStates.Legacy]: [SuperBlocks.RespWebDesign]
|
||||
},
|
||||
[TranslationStates.NotAudited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.CodingInterviewPrep
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
}
|
||||
}
|
||||
},
|
||||
[Languages.ChineseTrandational]: {
|
||||
[CurriculumMaps.Landing]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[CurriculumMaps.Learn]: {
|
||||
[TranslationStates.Audited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [],
|
||||
[SuperBlockStates.Legacy]: [SuperBlocks.RespWebDesign]
|
||||
},
|
||||
[TranslationStates.NotAudited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.CodingInterviewPrep
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
}
|
||||
}
|
||||
},
|
||||
[Languages.Italian]: {
|
||||
[CurriculumMaps.Landing]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[CurriculumMaps.Learn]: {
|
||||
[TranslationStates.Audited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [],
|
||||
[SuperBlockStates.Legacy]: [SuperBlocks.RespWebDesign]
|
||||
},
|
||||
[TranslationStates.NotAudited]: {
|
||||
[SuperBlockStates.Current]: [],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
}
|
||||
}
|
||||
},
|
||||
[Languages.Portuguese]: {
|
||||
[CurriculumMaps.Landing]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[CurriculumMaps.Learn]: {
|
||||
[TranslationStates.Audited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [],
|
||||
[SuperBlockStates.Legacy]: [SuperBlocks.RespWebDesign]
|
||||
},
|
||||
[TranslationStates.NotAudited]: {
|
||||
[SuperBlockStates.Current]: [],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
}
|
||||
}
|
||||
},
|
||||
[Languages.Ukrainian]: {
|
||||
[CurriculumMaps.Landing]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[CurriculumMaps.Learn]: {
|
||||
[TranslationStates.Audited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [],
|
||||
[SuperBlockStates.Legacy]: [SuperBlocks.RespWebDesign]
|
||||
},
|
||||
[TranslationStates.NotAudited]: {
|
||||
[SuperBlockStates.Current]: [SuperBlocks.CodingInterviewPrep],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
}
|
||||
}
|
||||
},
|
||||
[Languages.Japanese]: {
|
||||
[CurriculumMaps.Landing]: [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[CurriculumMaps.Learn]: {
|
||||
[TranslationStates.Audited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
},
|
||||
[TranslationStates.NotAudited]: {
|
||||
[SuperBlockStates.Current]: [SuperBlocks.RespWebDesignNew],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
}
|
||||
}
|
||||
},
|
||||
[Languages.German]: {
|
||||
[CurriculumMaps.Landing]: [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[CurriculumMaps.Learn]: {
|
||||
[TranslationStates.Audited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesign,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
},
|
||||
[TranslationStates.NotAudited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
}
|
||||
}
|
||||
},
|
||||
[Languages.Arabic]: {
|
||||
[CurriculumMaps.Landing]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs,
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy
|
||||
],
|
||||
[CurriculumMaps.Learn]: {
|
||||
[TranslationStates.Audited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.RespWebDesignNew,
|
||||
SuperBlocks.JsAlgoDataStruct,
|
||||
SuperBlocks.FrontEndDevLibs
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [],
|
||||
[SuperBlockStates.Legacy]: []
|
||||
},
|
||||
[TranslationStates.NotAudited]: {
|
||||
[SuperBlockStates.Current]: [
|
||||
SuperBlocks.DataVis,
|
||||
SuperBlocks.RelationalDb,
|
||||
SuperBlocks.BackEndDevApis,
|
||||
SuperBlocks.QualityAssurance,
|
||||
SuperBlocks.SciCompPy,
|
||||
SuperBlocks.DataAnalysisPy,
|
||||
SuperBlocks.InfoSec,
|
||||
SuperBlocks.MachineLearningPy,
|
||||
SuperBlocks.CodingInterviewPrep
|
||||
],
|
||||
[SuperBlockStates.New]: [],
|
||||
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
|
||||
[SuperBlockStates.Legacy]: [SuperBlocks.RespWebDesign]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// The client uses the object above to create the map
|
||||
// Keep this so it can't change
|
||||
Object.freeze(superBlockOrder);
|
||||
|
||||
function shouldShowSuperblocks({
|
||||
superBlockState,
|
||||
showNewCurriculum = 'false',
|
||||
showUpcomingChanges = 'false'
|
||||
}: {
|
||||
superBlockState: string;
|
||||
showNewCurriculum: string;
|
||||
showUpcomingChanges: string;
|
||||
}) {
|
||||
if (
|
||||
(superBlockState === SuperBlockStates.New &&
|
||||
showNewCurriculum !== 'true') ||
|
||||
(superBlockState === SuperBlockStates.Upcoming &&
|
||||
showUpcomingChanges !== 'true')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function getLearnSuperBlocks({
|
||||
language = 'english',
|
||||
showNewCurriculum = 'false',
|
||||
showUpcomingChanges = 'false'
|
||||
}) {
|
||||
const learnSuperBlocks: SuperBlocks[] = [];
|
||||
|
||||
Object.values(TranslationStates).forEach(translationState => {
|
||||
Object.values(SuperBlockStates).forEach(superBlockState => {
|
||||
if (
|
||||
shouldShowSuperblocks({
|
||||
superBlockState,
|
||||
showNewCurriculum,
|
||||
showUpcomingChanges
|
||||
})
|
||||
) {
|
||||
learnSuperBlocks.push(
|
||||
...superBlockOrder[language as Languages][CurriculumMaps.Learn][
|
||||
translationState as TranslationStates
|
||||
][superBlockState as SuperBlockStates]
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return learnSuperBlocks;
|
||||
}
|
||||
|
||||
export function getAuditedSuperBlocks({
|
||||
language = 'english',
|
||||
showNewCurriculum = 'false',
|
||||
showUpcomingChanges = 'false'
|
||||
}) {
|
||||
const auditedSuperBlocks: SuperBlocks[] = [];
|
||||
|
||||
Object.values(SuperBlockStates).forEach(superBlockState => {
|
||||
if (
|
||||
shouldShowSuperblocks({
|
||||
superBlockState,
|
||||
showNewCurriculum,
|
||||
showUpcomingChanges
|
||||
})
|
||||
) {
|
||||
auditedSuperBlocks.push(
|
||||
...superBlockOrder[language as Languages][CurriculumMaps.Learn][
|
||||
TranslationStates.Audited
|
||||
][superBlockState as SuperBlockStates]
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return auditedSuperBlocks;
|
||||
}
|
||||
|
||||
export function getNotAuditedSuperBlocks({
|
||||
language = 'english',
|
||||
showNewCurriculum = 'false',
|
||||
showUpcomingChanges = 'false'
|
||||
}) {
|
||||
const notAuditedSuperBlocks: SuperBlocks[] = [];
|
||||
|
||||
Object.values(SuperBlockStates).forEach(superBlockState => {
|
||||
if (
|
||||
shouldShowSuperblocks({
|
||||
superBlockState,
|
||||
showNewCurriculum,
|
||||
showUpcomingChanges
|
||||
})
|
||||
) {
|
||||
notAuditedSuperBlocks.push(
|
||||
...superBlockOrder[language as Languages][CurriculumMaps.Learn][
|
||||
TranslationStates.NotAudited
|
||||
][superBlockState as SuperBlockStates]
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return notAuditedSuperBlocks;
|
||||
}
|
||||
+76
-58
@@ -1,12 +1,18 @@
|
||||
const path = require('path');
|
||||
const {
|
||||
CurriculumMaps,
|
||||
superBlockOrder,
|
||||
SuperBlockStates,
|
||||
TranslationStates,
|
||||
orderedSuperBlockStates
|
||||
} = require('../config/superblock-order');
|
||||
|
||||
require('dotenv').config({ path: path.resolve(__dirname, '../.env') });
|
||||
|
||||
const {
|
||||
availableLangs,
|
||||
languagesWithAuditedBetaReleases
|
||||
} = require('../config/i18n');
|
||||
const { availableLangs } = require('../config/i18n');
|
||||
const curriculumLangs = availableLangs.curriculum;
|
||||
|
||||
// checks that the CURRICULUM_LOCALE exists and is an available language
|
||||
exports.testedLang = function testedLang() {
|
||||
if (process.env.CURRICULUM_LOCALE) {
|
||||
if (curriculumLangs.includes(process.env.CURRICULUM_LOCALE)) {
|
||||
@@ -20,67 +26,78 @@ exports.testedLang = function testedLang() {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: migrate to TS and use the SuperBlocks enum from
|
||||
// config/certification-settings.ts
|
||||
|
||||
const superBlockToOrder = {
|
||||
'2022/responsive-web-design': 0,
|
||||
'javascript-algorithms-and-data-structures': 1,
|
||||
'front-end-development-libraries': 2,
|
||||
'data-visualization': 3,
|
||||
'relational-database': 4,
|
||||
'back-end-development-and-apis': 5,
|
||||
'quality-assurance': 6,
|
||||
'scientific-computing-with-python': 7,
|
||||
'data-analysis-with-python': 8,
|
||||
'information-security': 9,
|
||||
'machine-learning-with-python': 10,
|
||||
'coding-interview-prep': 11,
|
||||
'responsive-web-design': 12
|
||||
};
|
||||
|
||||
/**
|
||||
* This order is used for i18n instances where a new certification is released
|
||||
* from beta but is not audited, so cannot be reordered (due to the way we
|
||||
* split the map)
|
||||
/*
|
||||
* creates an object with all the superblocks in
|
||||
* 'superBlockOrder[lang][learn]' as keys and gives them
|
||||
* a number (superOrder), starting with 0, as the value
|
||||
*/
|
||||
const superBlockNonAuditedOrder = {
|
||||
'responsive-web-design': 0,
|
||||
'javascript-algorithms-and-data-structures': 1,
|
||||
'front-end-development-libraries': 2,
|
||||
'data-visualization': 3,
|
||||
'relational-database': 4,
|
||||
'back-end-development-and-apis': 5,
|
||||
'quality-assurance': 6,
|
||||
'scientific-computing-with-python': 7,
|
||||
'data-analysis-with-python': 8,
|
||||
'information-security': 9,
|
||||
'machine-learning-with-python': 10,
|
||||
'coding-interview-prep': 11,
|
||||
'2022/responsive-web-design': 12
|
||||
};
|
||||
|
||||
const superBlockToNewOrder = {
|
||||
...superBlockToOrder,
|
||||
'2022/javascript-algorithms-and-data-structures': 13
|
||||
};
|
||||
|
||||
function getSuperOrder(
|
||||
superblock,
|
||||
{ showNewCurriculum } = { showNewCurriculum: false }
|
||||
) {
|
||||
let orderMap = superBlockToOrder;
|
||||
if (showNewCurriculum) {
|
||||
orderMap = superBlockToNewOrder;
|
||||
function createSuperOrder({
|
||||
language = 'english',
|
||||
showNewCurriculum = 'false',
|
||||
showUpcomingChanges = 'false'
|
||||
}) {
|
||||
if (!Object.prototype.hasOwnProperty.call(superBlockOrder, language)) {
|
||||
throw Error(`${language} not found in superblock-order.ts`);
|
||||
}
|
||||
|
||||
if (
|
||||
!languagesWithAuditedBetaReleases.includes(process.env.CURRICULUM_LOCALE)
|
||||
!Object.prototype.hasOwnProperty.call(superBlockOrder[language], [
|
||||
CurriculumMaps.Learn
|
||||
])
|
||||
) {
|
||||
orderMap = superBlockNonAuditedOrder;
|
||||
throw Error(
|
||||
`${language} does not have a 'learn' key in superblock-order.ts`
|
||||
);
|
||||
}
|
||||
|
||||
const audited =
|
||||
superBlockOrder[language][CurriculumMaps.Learn][TranslationStates.Audited];
|
||||
const notAudited =
|
||||
superBlockOrder[language][CurriculumMaps.Learn][
|
||||
TranslationStates.NotAudited
|
||||
];
|
||||
|
||||
const superOrder = {};
|
||||
let i = 0;
|
||||
|
||||
function addToSuperOrder(superBlocks) {
|
||||
superBlocks.forEach(key => {
|
||||
superOrder[key] = i;
|
||||
i++;
|
||||
});
|
||||
}
|
||||
|
||||
function canAddToSuperOrder(superBlockState) {
|
||||
if (superBlockState === SuperBlockStates.New)
|
||||
return showNewCurriculum === 'true';
|
||||
if (superBlockState === SuperBlockStates.Upcoming)
|
||||
return showUpcomingChanges === 'true';
|
||||
return true;
|
||||
}
|
||||
|
||||
function addSuperBlockStates(translationState) {
|
||||
orderedSuperBlockStates.forEach(state => {
|
||||
if (canAddToSuperOrder(state)) addToSuperOrder(translationState[state]);
|
||||
});
|
||||
}
|
||||
|
||||
addSuperBlockStates(audited);
|
||||
addSuperBlockStates(notAudited);
|
||||
|
||||
return superOrder;
|
||||
}
|
||||
|
||||
const superOrder = createSuperOrder({
|
||||
language: process.env.CURRICULUM_LOCALE,
|
||||
showNewCurriculum: process.env.SHOW_NEW_CURRICULUM,
|
||||
showUpcomingChanges: process.env.SHOW_UPCOMING_CHANGES
|
||||
});
|
||||
|
||||
// gets the superOrder of a superBlock from the object created above
|
||||
function getSuperOrder(superblock) {
|
||||
if (typeof superblock !== 'string')
|
||||
throw Error('superblock must be a string');
|
||||
const order = orderMap[superblock];
|
||||
const order = superOrder[superblock];
|
||||
if (typeof order === 'undefined')
|
||||
throw Error(`${superblock} is not a valid superblock`);
|
||||
return order;
|
||||
@@ -112,5 +129,6 @@ function getSuperBlockFromDir(dir) {
|
||||
return directoryToSuperblock[dir];
|
||||
}
|
||||
|
||||
exports.createSuperOrder = createSuperOrder;
|
||||
exports.getSuperOrder = getSuperOrder;
|
||||
exports.getSuperBlockFromDir = getSuperBlockFromDir;
|
||||
|
||||
+136
-101
@@ -5,11 +5,117 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { config } from 'dotenv';
|
||||
import { SuperBlocks } from '../config/certification-settings';
|
||||
import { languagesWithAuditedBetaReleases } from '../config/i18n';
|
||||
import { getSuperOrder, getSuperBlockFromDir } from './utils';
|
||||
import { createSuperOrder, getSuperOrder, getSuperBlockFromDir } from './utils';
|
||||
|
||||
config({ path: path.resolve(__dirname, '../.env') });
|
||||
|
||||
const englishTest = {
|
||||
[SuperBlocks.RespWebDesignNew]: 0,
|
||||
[SuperBlocks.JsAlgoDataStruct]: 1,
|
||||
[SuperBlocks.FrontEndDevLibs]: 2,
|
||||
[SuperBlocks.DataVis]: 3,
|
||||
[SuperBlocks.RelationalDb]: 4,
|
||||
[SuperBlocks.BackEndDevApis]: 5,
|
||||
[SuperBlocks.QualityAssurance]: 6,
|
||||
[SuperBlocks.SciCompPy]: 7,
|
||||
[SuperBlocks.DataAnalysisPy]: 8,
|
||||
[SuperBlocks.InfoSec]: 9,
|
||||
[SuperBlocks.MachineLearningPy]: 10,
|
||||
[SuperBlocks.CodingInterviewPrep]: 11,
|
||||
[SuperBlocks.RespWebDesign]: 12
|
||||
};
|
||||
|
||||
const upcomingTest = {
|
||||
[SuperBlocks.RespWebDesignNew]: 0,
|
||||
[SuperBlocks.JsAlgoDataStruct]: 1,
|
||||
[SuperBlocks.FrontEndDevLibs]: 2,
|
||||
[SuperBlocks.DataVis]: 3,
|
||||
[SuperBlocks.RelationalDb]: 4,
|
||||
[SuperBlocks.BackEndDevApis]: 5,
|
||||
[SuperBlocks.QualityAssurance]: 6,
|
||||
[SuperBlocks.SciCompPy]: 7,
|
||||
[SuperBlocks.DataAnalysisPy]: 8,
|
||||
[SuperBlocks.InfoSec]: 9,
|
||||
[SuperBlocks.MachineLearningPy]: 10,
|
||||
[SuperBlocks.CodingInterviewPrep]: 11,
|
||||
[SuperBlocks.JsAlgoDataStructNew]: 12,
|
||||
[SuperBlocks.RespWebDesign]: 13
|
||||
};
|
||||
|
||||
const espanolTest = {
|
||||
[SuperBlocks.RespWebDesign]: 0,
|
||||
[SuperBlocks.JsAlgoDataStruct]: 1,
|
||||
[SuperBlocks.FrontEndDevLibs]: 2,
|
||||
[SuperBlocks.DataVis]: 3,
|
||||
[SuperBlocks.BackEndDevApis]: 4,
|
||||
[SuperBlocks.QualityAssurance]: 5,
|
||||
[SuperBlocks.SciCompPy]: 6,
|
||||
[SuperBlocks.DataAnalysisPy]: 7,
|
||||
[SuperBlocks.RespWebDesignNew]: 8,
|
||||
[SuperBlocks.RelationalDb]: 9,
|
||||
[SuperBlocks.InfoSec]: 10,
|
||||
[SuperBlocks.MachineLearningPy]: 11,
|
||||
[SuperBlocks.CodingInterviewPrep]: 12
|
||||
};
|
||||
|
||||
const chineseTest = {
|
||||
[SuperBlocks.RespWebDesignNew]: 0,
|
||||
[SuperBlocks.JsAlgoDataStruct]: 1,
|
||||
[SuperBlocks.FrontEndDevLibs]: 2,
|
||||
[SuperBlocks.DataVis]: 3,
|
||||
[SuperBlocks.BackEndDevApis]: 4,
|
||||
[SuperBlocks.QualityAssurance]: 5,
|
||||
[SuperBlocks.SciCompPy]: 6,
|
||||
[SuperBlocks.DataAnalysisPy]: 7,
|
||||
[SuperBlocks.InfoSec]: 8,
|
||||
[SuperBlocks.MachineLearningPy]: 9,
|
||||
[SuperBlocks.RespWebDesign]: 10,
|
||||
[SuperBlocks.RelationalDb]: 11,
|
||||
[SuperBlocks.CodingInterviewPrep]: 12
|
||||
};
|
||||
|
||||
describe('createSuperOrder', () => {
|
||||
const englishSuperOrder = createSuperOrder({
|
||||
language: 'english',
|
||||
showNewCurriculum: 'false',
|
||||
showUpcomingChanges: 'false'
|
||||
});
|
||||
|
||||
const upcomingSuperOrder = createSuperOrder({
|
||||
language: 'english',
|
||||
showNewCurriculum: 'false',
|
||||
showUpcomingChanges: 'true'
|
||||
});
|
||||
|
||||
const espanolSuperOrder = createSuperOrder({
|
||||
language: 'espanol',
|
||||
showNewCurriculum: 'false',
|
||||
showUpcomingChanges: 'false'
|
||||
});
|
||||
|
||||
const chineseSuperOrder = createSuperOrder({
|
||||
language: 'chinese',
|
||||
showNewCurriculum: 'false',
|
||||
showUpcomingChanges: 'false'
|
||||
});
|
||||
|
||||
it("should create the correct object for 'english'", () => {
|
||||
expect(englishSuperOrder).toStrictEqual(englishTest);
|
||||
});
|
||||
|
||||
it('should create the correct object with upcoming changes shown', () => {
|
||||
expect(upcomingSuperOrder).toStrictEqual(upcomingTest);
|
||||
});
|
||||
|
||||
it("should create the correct object for 'espanol'", () => {
|
||||
expect(espanolSuperOrder).toStrictEqual(espanolTest);
|
||||
});
|
||||
|
||||
it("should create the correct object for 'chinese'", () => {
|
||||
expect(chineseSuperOrder).toStrictEqual(chineseTest);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSuperOrder', () => {
|
||||
it('returns a number for valid superblocks', () => {
|
||||
expect.assertions(1);
|
||||
@@ -29,108 +135,37 @@ describe('getSuperOrder', () => {
|
||||
expect(() => getSuperOrder('certifications')).toThrow();
|
||||
});
|
||||
|
||||
if (
|
||||
languagesWithAuditedBetaReleases.includes(
|
||||
process.env.CURRICULUM_LOCALE as string
|
||||
)
|
||||
) {
|
||||
it('returns unique numbers for all current superblocks (audited beta)', () => {
|
||||
expect.assertions(13);
|
||||
expect(getSuperOrder('2022/responsive-web-design')).toBe(0);
|
||||
expect(getSuperOrder('javascript-algorithms-and-data-structures')).toBe(
|
||||
1
|
||||
);
|
||||
expect(getSuperOrder('front-end-development-libraries')).toBe(2);
|
||||
expect(getSuperOrder('data-visualization')).toBe(3);
|
||||
expect(getSuperOrder('relational-database')).toBe(4);
|
||||
expect(getSuperOrder('back-end-development-and-apis')).toBe(5);
|
||||
expect(getSuperOrder('quality-assurance')).toBe(6);
|
||||
expect(getSuperOrder('scientific-computing-with-python')).toBe(7);
|
||||
expect(getSuperOrder('data-analysis-with-python')).toBe(8);
|
||||
expect(getSuperOrder('information-security')).toBe(9);
|
||||
expect(getSuperOrder('machine-learning-with-python')).toBe(10);
|
||||
expect(getSuperOrder('coding-interview-prep')).toBe(11);
|
||||
expect(getSuperOrder('responsive-web-design')).toBe(12);
|
||||
});
|
||||
} else {
|
||||
it('returns unique numbers for all current superblocks (not audited beta)', () => {
|
||||
expect.assertions(13);
|
||||
expect(getSuperOrder('responsive-web-design')).toBe(0);
|
||||
expect(getSuperOrder('javascript-algorithms-and-data-structures')).toBe(
|
||||
1
|
||||
);
|
||||
expect(getSuperOrder('front-end-development-libraries')).toBe(2);
|
||||
expect(getSuperOrder('data-visualization')).toBe(3);
|
||||
expect(getSuperOrder('relational-database')).toBe(4);
|
||||
expect(getSuperOrder('back-end-development-and-apis')).toBe(5);
|
||||
expect(getSuperOrder('quality-assurance')).toBe(6);
|
||||
expect(getSuperOrder('scientific-computing-with-python')).toBe(7);
|
||||
expect(getSuperOrder('data-analysis-with-python')).toBe(8);
|
||||
expect(getSuperOrder('information-security')).toBe(9);
|
||||
expect(getSuperOrder('machine-learning-with-python')).toBe(10);
|
||||
expect(getSuperOrder('coding-interview-prep')).toBe(11);
|
||||
expect(getSuperOrder('2022/responsive-web-design')).toBe(12);
|
||||
});
|
||||
}
|
||||
|
||||
it('returns a different order if passed the option showNewCurriculum: true', () => {
|
||||
// Skip non-english tests while the RWD cert is still being translated.
|
||||
it('returns unique numbers for all current superblocks', () => {
|
||||
// Skip non-english tests
|
||||
if (process.env.CURRICULUM_LOCALE !== 'english') {
|
||||
return;
|
||||
}
|
||||
expect.assertions(14);
|
||||
expect(
|
||||
getSuperOrder('2022/responsive-web-design', { showNewCurriculum: true })
|
||||
).toBe(0);
|
||||
expect(
|
||||
getSuperOrder('javascript-algorithms-and-data-structures', {
|
||||
showNewCurriculum: true
|
||||
})
|
||||
).toBe(1);
|
||||
expect(
|
||||
getSuperOrder('front-end-development-libraries', {
|
||||
showNewCurriculum: true
|
||||
})
|
||||
).toBe(2);
|
||||
expect(
|
||||
getSuperOrder('data-visualization', { showNewCurriculum: true })
|
||||
).toBe(3);
|
||||
expect(
|
||||
getSuperOrder('relational-database', { showNewCurriculum: true })
|
||||
).toBe(4);
|
||||
expect(
|
||||
getSuperOrder('back-end-development-and-apis', {
|
||||
showNewCurriculum: true
|
||||
})
|
||||
).toBe(5);
|
||||
expect(
|
||||
getSuperOrder('quality-assurance', { showNewCurriculum: true })
|
||||
).toBe(6);
|
||||
expect(
|
||||
getSuperOrder('scientific-computing-with-python', {
|
||||
showNewCurriculum: true
|
||||
})
|
||||
).toBe(7);
|
||||
expect(
|
||||
getSuperOrder('data-analysis-with-python', { showNewCurriculum: true })
|
||||
).toBe(8);
|
||||
expect(
|
||||
getSuperOrder('information-security', { showNewCurriculum: true })
|
||||
).toBe(9);
|
||||
expect(
|
||||
getSuperOrder('machine-learning-with-python', { showNewCurriculum: true })
|
||||
).toBe(10);
|
||||
expect(
|
||||
getSuperOrder('coding-interview-prep', { showNewCurriculum: true })
|
||||
).toBe(11);
|
||||
expect(
|
||||
getSuperOrder('responsive-web-design', { showNewCurriculum: true })
|
||||
).toBe(12);
|
||||
expect(
|
||||
getSuperOrder('2022/javascript-algorithms-and-data-structures', {
|
||||
showNewCurriculum: true
|
||||
})
|
||||
).toBe(13);
|
||||
|
||||
if (process.env.SHOW_UPCOMING_CHANGES !== 'true') {
|
||||
expect.assertions(13);
|
||||
} else {
|
||||
expect.assertions(14);
|
||||
}
|
||||
|
||||
expect(getSuperOrder(SuperBlocks.RespWebDesignNew)).toBe(0);
|
||||
expect(getSuperOrder(SuperBlocks.JsAlgoDataStruct)).toBe(1);
|
||||
expect(getSuperOrder(SuperBlocks.FrontEndDevLibs)).toBe(2);
|
||||
expect(getSuperOrder(SuperBlocks.DataVis)).toBe(3);
|
||||
expect(getSuperOrder(SuperBlocks.RelationalDb)).toBe(4);
|
||||
expect(getSuperOrder(SuperBlocks.BackEndDevApis)).toBe(5);
|
||||
expect(getSuperOrder(SuperBlocks.QualityAssurance)).toBe(6);
|
||||
expect(getSuperOrder(SuperBlocks.SciCompPy)).toBe(7);
|
||||
expect(getSuperOrder(SuperBlocks.DataAnalysisPy)).toBe(8);
|
||||
expect(getSuperOrder(SuperBlocks.InfoSec)).toBe(9);
|
||||
expect(getSuperOrder(SuperBlocks.MachineLearningPy)).toBe(10);
|
||||
expect(getSuperOrder(SuperBlocks.CodingInterviewPrep)).toBe(11);
|
||||
|
||||
if (process.env.SHOW_UPCOMING_CHANGES === 'true') {
|
||||
expect(getSuperOrder(SuperBlocks.JsAlgoDataStructNew)).toBe(12);
|
||||
expect(getSuperOrder(SuperBlocks.RespWebDesign)).toBe(13);
|
||||
} else {
|
||||
expect(getSuperOrder(SuperBlocks.RespWebDesign)).toBe(12);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ const selectors = {
|
||||
|
||||
const certifications = [
|
||||
'(New) Responsive Web Design',
|
||||
'Legacy Responsive Web Design',
|
||||
'JavaScript Algorithms and Data Structures',
|
||||
'Front End Development Libraries',
|
||||
'Data Visualization',
|
||||
@@ -59,7 +58,7 @@ describe('Landing page', () => {
|
||||
});
|
||||
|
||||
it('Has links to all the certifications', function () {
|
||||
cy.get(selectors.certifications).children().its('length').should('eq', 12);
|
||||
cy.get(selectors.certifications).children().its('length').should('eq', 11);
|
||||
cy.wrap(certifications).each(cert => {
|
||||
cy.get(selectors.certifications).contains(cert);
|
||||
});
|
||||
|
||||
@@ -8,7 +8,6 @@ const locations = {
|
||||
|
||||
const superBlockNames = [
|
||||
'(New) Responsive Web Design Certification',
|
||||
'Legacy Responsive Web Design Certification',
|
||||
'JavaScript Algorithms and Data Structures Certification',
|
||||
'Front End Development Libraries Certification',
|
||||
'Data Visualization Certification',
|
||||
@@ -19,7 +18,8 @@ const superBlockNames = [
|
||||
'Data Analysis with Python Certification',
|
||||
'Information Security Certification',
|
||||
'Machine Learning with Python Certification',
|
||||
'Coding Interview Prep'
|
||||
'Coding Interview Prep',
|
||||
'Legacy Responsive Web Design Certification'
|
||||
];
|
||||
|
||||
describe('Learn Landing page (not logged in)', () => {
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
"test:curriculum": "cd ./curriculum && npm test",
|
||||
"test-curriculum-full-output": "cd ./curriculum && npm run test:full-output",
|
||||
"test-client": "jest client",
|
||||
"test-config": "jest config",
|
||||
"test-curriculum-js": "jest curriculum",
|
||||
"test-server": "jest api-server",
|
||||
"test-tools": "jest tools",
|
||||
|
||||
@@ -7,10 +7,11 @@ import { config } from 'dotenv';
|
||||
const envPath = resolve(__dirname, '../../.env');
|
||||
config({ path: envPath });
|
||||
|
||||
import { availableLangs, auditedCerts } from '../../config/i18n';
|
||||
import { availableLangs } from '../../config/i18n';
|
||||
import { getChallengesForLang } from '../../curriculum/getChallenges';
|
||||
import { SuperBlocks } from '../../config/certification-settings';
|
||||
import { ChallengeNode } from '../../client/src/redux/prop-types';
|
||||
import { getAuditedSuperBlocks } from '../../config/superblock-order';
|
||||
|
||||
const superBlockFolderMap = {
|
||||
'responsive-web-design': '01-responsive-web-design',
|
||||
@@ -89,7 +90,11 @@ void (async () => {
|
||||
);
|
||||
for (const lang of langsToCheck) {
|
||||
console.log(`\n=== ${lang} ===`);
|
||||
const certs = auditedCerts[lang as keyof typeof auditedCerts];
|
||||
const certs = getAuditedSuperBlocks({
|
||||
language: lang,
|
||||
showNewCurriculum: process.env.SHOW_NEW_CURRICULUM,
|
||||
showUpcomingChanges: process.env.SHOW_UPCOMING_CHANGES
|
||||
});
|
||||
const langCurriculumDirectory = join(
|
||||
process.cwd(),
|
||||
'curriculum',
|
||||
|
||||
@@ -2,7 +2,7 @@ import { spawn } from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import { availableLangs } from '../../../config/i18n';
|
||||
import { availableLangs, Languages } from '../../../config/i18n';
|
||||
import env from '../../../config/read-env';
|
||||
|
||||
const globalConfigPath = path.resolve(__dirname, '../../../config');
|
||||
@@ -11,7 +11,7 @@ const { FREECODECAMP_NODE_ENV } = process.env;
|
||||
|
||||
function checkClientLocale() {
|
||||
if (!process.env.CLIENT_LOCALE) throw Error('CLIENT_LOCALE is not set');
|
||||
if (!availableLangs.client.includes(process.env.CLIENT_LOCALE)) {
|
||||
if (!availableLangs.client.includes(process.env.CLIENT_LOCALE as Languages)) {
|
||||
throw Error(`
|
||||
|
||||
CLIENT_LOCALE, ${process.env.CLIENT_LOCALE}, is not an available language in config/i18n.ts
|
||||
@@ -23,7 +23,11 @@ function checkClientLocale() {
|
||||
function checkCurriculumLocale() {
|
||||
if (!process.env.CURRICULUM_LOCALE)
|
||||
throw Error('CURRICULUM_LOCALE is not set');
|
||||
if (!availableLangs.curriculum.includes(process.env.CURRICULUM_LOCALE)) {
|
||||
if (
|
||||
!availableLangs.curriculum.includes(
|
||||
process.env.CURRICULUM_LOCALE as Languages
|
||||
)
|
||||
) {
|
||||
throw Error(`
|
||||
|
||||
CURRICULUM_LOCALE, ${process.env.CURRICULUM_LOCALE}, is not an available language in config/i18n.ts
|
||||
|
||||
+6
-15
@@ -1,20 +1,11 @@
|
||||
// this can go once all certs have been audited.
|
||||
const { getAuditedSuperBlocks } = require('../config/superblock-order');
|
||||
|
||||
// Currently the auditing is going through Crowdin, so once a cert has been 100%
|
||||
// proofread, we can add it in here. That means that translations can come
|
||||
// through from Crowdin whenever they are done, but we don't show them on the
|
||||
// client until we decide the entire cert is ready.
|
||||
|
||||
// NOTE: certificates themselves (.yml files) are not currently being
|
||||
// translated, but when they are they can be included by adding 'certificates'
|
||||
// to the arrays below
|
||||
|
||||
const { auditedCerts } = require('../config/i18n');
|
||||
|
||||
function isAuditedCert(lang, cert) {
|
||||
if (!lang || !cert)
|
||||
function isAuditedCert(language, superblock) {
|
||||
if (!language || !superblock)
|
||||
throw Error('Both arguments must be provided for auditing');
|
||||
return lang === 'english' || auditedCerts[lang].includes(cert);
|
||||
|
||||
const auditedSuperBlocks = getAuditedSuperBlocks(language);
|
||||
return auditedSuperBlocks.includes(superblock);
|
||||
}
|
||||
|
||||
exports.isAuditedCert = isAuditedCert;
|
||||
|
||||
Reference in New Issue
Block a user