refactor: stop spreading challenge over the node (#44499)
* refactor: stop spreading challenge over the node Instead of creating a Gatsby node with id of challenge.id, we create a single node field that has all the challenge data. While this makes the GraphQL queries more verbose, it means we're free to create multiple nodes with the same challenge.id. * test: update time-line test for new GQL schema * test: update mocks with new GQL schema
This commit is contained in:
committed by
GitHub
parent
755f27093c
commit
3b560deab6
@ -20,13 +20,6 @@ const createByIdentityMap = {
|
|||||||
|
|
||||||
exports.onCreateNode = function onCreateNode({ node, actions, getNode }) {
|
exports.onCreateNode = function onCreateNode({ node, actions, getNode }) {
|
||||||
const { createNodeField } = actions;
|
const { createNodeField } = actions;
|
||||||
if (node.internal.type === 'ChallengeNode') {
|
|
||||||
const { tests = [], block, dashedName, superBlock } = node;
|
|
||||||
const slug = `/learn/${superBlock}/${block}/${dashedName}`;
|
|
||||||
createNodeField({ node, name: 'slug', value: slug });
|
|
||||||
createNodeField({ node, name: 'blockName', value: blockNameify(block) });
|
|
||||||
createNodeField({ node, name: 'tests', value: tests });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.internal.type === 'MarkdownRemark') {
|
if (node.internal.type === 'MarkdownRemark') {
|
||||||
const slug = createFilePath({ node, getNode });
|
const slug = createFilePath({ node, getNode });
|
||||||
@ -71,10 +64,17 @@ exports.createPages = function createPages({ graphql, actions, reporter }) {
|
|||||||
graphql(`
|
graphql(`
|
||||||
{
|
{
|
||||||
allChallengeNode(
|
allChallengeNode(
|
||||||
sort: { fields: [superOrder, order, challengeOrder] }
|
sort: {
|
||||||
|
fields: [
|
||||||
|
challenge___superOrder
|
||||||
|
challenge___order
|
||||||
|
challenge___challengeOrder
|
||||||
|
]
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
|
challenge {
|
||||||
block
|
block
|
||||||
challengeType
|
challengeType
|
||||||
fields {
|
fields {
|
||||||
@ -105,6 +105,7 @@ exports.createPages = function createPages({ graphql, actions, reporter }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
allMarkdownRemark {
|
allMarkdownRemark {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
@ -137,12 +138,22 @@ exports.createPages = function createPages({ graphql, actions, reporter }) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const blocks = uniq(
|
const blocks = uniq(
|
||||||
result.data.allChallengeNode.edges.map(({ node: { block } }) => block)
|
result.data.allChallengeNode.edges.map(
|
||||||
|
({
|
||||||
|
node: {
|
||||||
|
challenge: { block }
|
||||||
|
}
|
||||||
|
}) => block
|
||||||
|
)
|
||||||
).map(block => blockNameify(block));
|
).map(block => blockNameify(block));
|
||||||
|
|
||||||
const superBlocks = uniq(
|
const superBlocks = uniq(
|
||||||
result.data.allChallengeNode.edges.map(
|
result.data.allChallengeNode.edges.map(
|
||||||
({ node: { superBlock } }) => superBlock
|
({
|
||||||
|
node: {
|
||||||
|
challenge: { superBlock }
|
||||||
|
}
|
||||||
|
}) => superBlock
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -256,6 +267,9 @@ exports.createSchemaCustomization = ({ actions }) => {
|
|||||||
const { createTypes } = actions;
|
const { createTypes } = actions;
|
||||||
const typeDefs = `
|
const typeDefs = `
|
||||||
type ChallengeNode implements Node {
|
type ChallengeNode implements Node {
|
||||||
|
challenge: Challenge
|
||||||
|
}
|
||||||
|
type Challenge {
|
||||||
challengeFiles: [FileContents]
|
challengeFiles: [FileContents]
|
||||||
notes: String
|
notes: String
|
||||||
url: String
|
url: String
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
const { blockNameify } = require('../../../utils/block-nameify');
|
||||||
|
|
||||||
function createChallengeNode(challenge, reporter) {
|
function createChallengeNode(challenge, reporter) {
|
||||||
// challengeType 11 is for video challenges (they only have instructions)
|
// challengeType 11 is for video challenges (they only have instructions)
|
||||||
@ -31,6 +32,17 @@ function createChallengeNode(challenge, reporter) {
|
|||||||
type: challenge.challengeType === 7 ? 'CertificateNode' : 'ChallengeNode'
|
type: challenge.challengeType === 7 ? 'CertificateNode' : 'ChallengeNode'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (internal.type === 'ChallengeNode') {
|
||||||
|
const { tests = [], block, dashedName, superBlock } = challenge;
|
||||||
|
const slug = `/learn/${superBlock}/${block}/${dashedName}`;
|
||||||
|
|
||||||
|
challenge.fields = {
|
||||||
|
slug,
|
||||||
|
blockName: blockNameify(block),
|
||||||
|
tests
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return JSON.parse(
|
return JSON.parse(
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
Object.assign(
|
Object.assign(
|
||||||
@ -41,7 +53,8 @@ function createChallengeNode(challenge, reporter) {
|
|||||||
internal,
|
internal,
|
||||||
sourceInstanceName: 'challenge'
|
sourceInstanceName: 'challenge'
|
||||||
},
|
},
|
||||||
challenge
|
{ challenge },
|
||||||
|
{ id: crypto.randomUUID() }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const mockChallengeNodes = [
|
const mockChallengeNodes = [
|
||||||
{
|
{
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: '/super-block-one/block-a/challenge-one',
|
slug: '/super-block-one/block-a/challenge-one',
|
||||||
blockName: 'Block A'
|
blockName: 'Block A'
|
||||||
@ -10,8 +11,10 @@ const mockChallengeNodes = [
|
|||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
superBlock: 'super-block-one',
|
superBlock: 'super-block-one',
|
||||||
dashedName: 'challenge-one'
|
dashedName: 'challenge-one'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: '/super-block-one/block-a/challenge-two',
|
slug: '/super-block-one/block-a/challenge-two',
|
||||||
blockName: 'Block A'
|
blockName: 'Block A'
|
||||||
@ -22,8 +25,10 @@ const mockChallengeNodes = [
|
|||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
superBlock: 'super-block-one',
|
superBlock: 'super-block-one',
|
||||||
dashedName: 'challenge-two'
|
dashedName: 'challenge-two'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: '/super-block-one/block-b/challenge-one',
|
slug: '/super-block-one/block-b/challenge-one',
|
||||||
blockName: 'Block B'
|
blockName: 'Block B'
|
||||||
@ -34,8 +39,10 @@ const mockChallengeNodes = [
|
|||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
superBlock: 'super-block-one',
|
superBlock: 'super-block-one',
|
||||||
dashedName: 'challenge-one'
|
dashedName: 'challenge-one'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: '/super-block-one/block-b/challenge-two',
|
slug: '/super-block-one/block-b/challenge-two',
|
||||||
blockName: 'Block B'
|
blockName: 'Block B'
|
||||||
@ -47,8 +54,10 @@ const mockChallengeNodes = [
|
|||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
superBlock: 'super-block-one',
|
superBlock: 'super-block-one',
|
||||||
dashedName: 'challenge-two'
|
dashedName: 'challenge-two'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: '/super-block-one/block-c/challenge-one',
|
slug: '/super-block-one/block-c/challenge-one',
|
||||||
blockName: 'Block C'
|
blockName: 'Block C'
|
||||||
@ -59,8 +68,10 @@ const mockChallengeNodes = [
|
|||||||
isPrivate: true,
|
isPrivate: true,
|
||||||
superBlock: 'super-block-one',
|
superBlock: 'super-block-one',
|
||||||
dashedName: 'challenge-one'
|
dashedName: 'challenge-one'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: '/super-block-two/block-a/challenge-one',
|
slug: '/super-block-two/block-a/challenge-one',
|
||||||
blockName: 'Block A'
|
blockName: 'Block A'
|
||||||
@ -71,8 +82,10 @@ const mockChallengeNodes = [
|
|||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
superBlock: 'super-block-two',
|
superBlock: 'super-block-two',
|
||||||
dashedName: 'challenge-one'
|
dashedName: 'challenge-one'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: '/super-block-two/block-a/challenge-two',
|
slug: '/super-block-two/block-a/challenge-two',
|
||||||
blockName: 'Block A'
|
blockName: 'Block A'
|
||||||
@ -83,8 +96,10 @@ const mockChallengeNodes = [
|
|||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
superBlock: 'super-block-two',
|
superBlock: 'super-block-two',
|
||||||
dashedName: 'challenge-two'
|
dashedName: 'challenge-two'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: '/super-block-two/block-b/challenge-one',
|
slug: '/super-block-two/block-b/challenge-one',
|
||||||
blockName: 'Block B'
|
blockName: 'Block B'
|
||||||
@ -95,8 +110,10 @@ const mockChallengeNodes = [
|
|||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
superBlock: 'super-block-two',
|
superBlock: 'super-block-two',
|
||||||
dashedName: 'challenge-one'
|
dashedName: 'challenge-one'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: '/super-block-two/block-b/challenge-two',
|
slug: '/super-block-two/block-b/challenge-two',
|
||||||
blockName: 'Block B'
|
blockName: 'Block B'
|
||||||
@ -107,8 +124,10 @@ const mockChallengeNodes = [
|
|||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
superBlock: 'super-block-two',
|
superBlock: 'super-block-two',
|
||||||
dashedName: 'challenge-two'
|
dashedName: 'challenge-two'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: '/super-block-three/block-a/challenge-one',
|
slug: '/super-block-three/block-a/challenge-one',
|
||||||
blockName: 'Block A'
|
blockName: 'Block A'
|
||||||
@ -119,8 +138,10 @@ const mockChallengeNodes = [
|
|||||||
isPrivate: false,
|
isPrivate: false,
|
||||||
superBlock: 'super-block-three',
|
superBlock: 'super-block-three',
|
||||||
dashedName: 'challenge-one'
|
dashedName: 'challenge-one'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: '/super-block-three/block-c/challenge-two',
|
slug: '/super-block-three/block-c/challenge-two',
|
||||||
blockName: 'Block C'
|
blockName: 'Block C'
|
||||||
@ -132,6 +153,7 @@ const mockChallengeNodes = [
|
|||||||
superBlock: 'super-block-three',
|
superBlock: 'super-block-three',
|
||||||
dashedName: 'challenge-two'
|
dashedName: 'challenge-two'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export default mockChallengeNodes;
|
export default mockChallengeNodes;
|
||||||
|
@ -42,19 +42,19 @@ const linkSpacingStyle = {
|
|||||||
|
|
||||||
function renderLandingMap(nodes: ChallengeNode[]) {
|
function renderLandingMap(nodes: ChallengeNode[]) {
|
||||||
nodes = nodes.filter(
|
nodes = nodes.filter(
|
||||||
node => node.superBlock !== SuperBlocks.CodingInterviewPrep
|
({ challenge }) => challenge.superBlock !== SuperBlocks.CodingInterviewPrep
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<ul data-test-label='certifications'>
|
<ul data-test-label='certifications'>
|
||||||
{nodes.map((node, i) => (
|
{nodes.map(({ challenge }, i) => (
|
||||||
<li key={i}>
|
<li key={i}>
|
||||||
<Link
|
<Link
|
||||||
className='btn link-btn btn-lg'
|
className='btn link-btn btn-lg'
|
||||||
to={`/learn/${node.superBlock}/`}
|
to={`/learn/${challenge.superBlock}/`}
|
||||||
>
|
>
|
||||||
<div style={linkSpacingStyle}>
|
<div style={linkSpacingStyle}>
|
||||||
{generateIconComponent(node.superBlock, 'map-icon')}
|
{generateIconComponent(challenge.superBlock, 'map-icon')}
|
||||||
{i18next.t(`intro:${node.superBlock}.title`)}
|
{i18next.t(`intro:${challenge.superBlock}.title`)}
|
||||||
</div>
|
</div>
|
||||||
<LinkButton />
|
<LinkButton />
|
||||||
</Link>
|
</Link>
|
||||||
@ -68,18 +68,20 @@ function renderLearnMap(
|
|||||||
nodes: ChallengeNode[],
|
nodes: ChallengeNode[],
|
||||||
currentSuperBlock: MapProps['currentSuperBlock']
|
currentSuperBlock: MapProps['currentSuperBlock']
|
||||||
) {
|
) {
|
||||||
nodes = nodes.filter(node => node.superBlock !== currentSuperBlock);
|
nodes = nodes.filter(
|
||||||
|
({ challenge }) => challenge.superBlock !== currentSuperBlock
|
||||||
|
);
|
||||||
return curriculumLocale === 'english' ? (
|
return curriculumLocale === 'english' ? (
|
||||||
<ul data-test-label='learn-curriculum-map'>
|
<ul data-test-label='learn-curriculum-map'>
|
||||||
{nodes.map((node, i) => (
|
{nodes.map(({ challenge }, i) => (
|
||||||
<li key={i}>
|
<li key={i}>
|
||||||
<Link
|
<Link
|
||||||
className='btn link-btn btn-lg'
|
className='btn link-btn btn-lg'
|
||||||
to={`/learn/${node.superBlock}/`}
|
to={`/learn/${challenge.superBlock}/`}
|
||||||
>
|
>
|
||||||
<div style={linkSpacingStyle}>
|
<div style={linkSpacingStyle}>
|
||||||
{generateIconComponent(node.superBlock, 'map-icon')}
|
{generateIconComponent(challenge.superBlock, 'map-icon')}
|
||||||
{createSuperBlockTitle(node.superBlock)}
|
{createSuperBlockTitle(challenge.superBlock)}
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
@ -88,16 +90,18 @@ function renderLearnMap(
|
|||||||
) : (
|
) : (
|
||||||
<ul data-test-label='learn-curriculum-map'>
|
<ul data-test-label='learn-curriculum-map'>
|
||||||
{nodes
|
{nodes
|
||||||
.filter(node => isAuditedCert(curriculumLocale, node.superBlock))
|
.filter(({ challenge }) =>
|
||||||
.map((node, i) => (
|
isAuditedCert(curriculumLocale, challenge.superBlock)
|
||||||
|
)
|
||||||
|
.map(({ challenge }, i) => (
|
||||||
<li key={i}>
|
<li key={i}>
|
||||||
<Link
|
<Link
|
||||||
className='btn link-btn btn-lg'
|
className='btn link-btn btn-lg'
|
||||||
to={`/learn/${node.superBlock}/`}
|
to={`/learn/${challenge.superBlock}/`}
|
||||||
>
|
>
|
||||||
<div style={linkSpacingStyle}>
|
<div style={linkSpacingStyle}>
|
||||||
{generateIconComponent(node.superBlock, 'map-icon')}
|
{generateIconComponent(challenge.superBlock, 'map-icon')}
|
||||||
{createSuperBlockTitle(node.superBlock)}
|
{createSuperBlockTitle(challenge.superBlock)}
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
@ -115,16 +119,19 @@ function renderLearnMap(
|
|||||||
<Spacer />
|
<Spacer />
|
||||||
</div>
|
</div>
|
||||||
{nodes
|
{nodes
|
||||||
.filter(node => !isAuditedCert(curriculumLocale, node.superBlock))
|
.filter(
|
||||||
.map((node, i) => (
|
({ challenge }) =>
|
||||||
|
!isAuditedCert(curriculumLocale, challenge.superBlock)
|
||||||
|
)
|
||||||
|
.map(({ challenge }, i) => (
|
||||||
<li key={i}>
|
<li key={i}>
|
||||||
<Link
|
<Link
|
||||||
className='btn link-btn btn-lg'
|
className='btn link-btn btn-lg'
|
||||||
to={`/learn/${node.superBlock}/`}
|
to={`/learn/${challenge.superBlock}/`}
|
||||||
>
|
>
|
||||||
<div style={linkSpacingStyle}>
|
<div style={linkSpacingStyle}>
|
||||||
{generateIconComponent(node.superBlock, 'map-icon')}
|
{generateIconComponent(challenge.superBlock, 'map-icon')}
|
||||||
{createSuperBlockTitle(node.superBlock)}
|
{createSuperBlockTitle(challenge.superBlock)}
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
@ -145,15 +152,17 @@ export function Map({
|
|||||||
const data: MapData = useStaticQuery(graphql`
|
const data: MapData = useStaticQuery(graphql`
|
||||||
query SuperBlockNodes {
|
query SuperBlockNodes {
|
||||||
allChallengeNode(
|
allChallengeNode(
|
||||||
sort: { fields: [superOrder] }
|
sort: { fields: [challenge___superOrder] }
|
||||||
filter: { order: { eq: 0 }, challengeOrder: { eq: 0 } }
|
filter: { challenge: { order: { eq: 0 }, challengeOrder: { eq: 0 } } }
|
||||||
) {
|
) {
|
||||||
nodes {
|
nodes {
|
||||||
|
challenge {
|
||||||
superBlock
|
superBlock
|
||||||
dashedName
|
dashedName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const nodes = data.allChallengeNode.nodes;
|
const nodes = data.allChallengeNode.nodes;
|
||||||
|
@ -269,6 +269,7 @@ function useIdToNameMap(): Map<string, string> {
|
|||||||
allChallengeNode {
|
allChallengeNode {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
|
challenge {
|
||||||
fields {
|
fields {
|
||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
@ -278,6 +279,7 @@ function useIdToNameMap(): Map<string, string> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`);
|
`);
|
||||||
const idToNameMap = new Map();
|
const idToNameMap = new Map();
|
||||||
for (const id of getCertIds()) {
|
for (const id of getCertIds()) {
|
||||||
@ -289,6 +291,7 @@ function useIdToNameMap(): Map<string, string> {
|
|||||||
edges.forEach(
|
edges.forEach(
|
||||||
({
|
({
|
||||||
node: {
|
node: {
|
||||||
|
challenge: {
|
||||||
// @ts-expect-error Graphql needs typing
|
// @ts-expect-error Graphql needs typing
|
||||||
id,
|
id,
|
||||||
// @ts-expect-error Graphql needs typing
|
// @ts-expect-error Graphql needs typing
|
||||||
@ -296,6 +299,7 @@ function useIdToNameMap(): Map<string, string> {
|
|||||||
// @ts-expect-error Graphql needs typing
|
// @ts-expect-error Graphql needs typing
|
||||||
fields: { slug }
|
fields: { slug }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}) => {
|
}) => {
|
||||||
idToNameMap.set(id, { challengeTitle: title, challengePath: slug });
|
idToNameMap.set(id, { challengeTitle: title, challengePath: slug });
|
||||||
}
|
}
|
||||||
|
@ -12,24 +12,29 @@ beforeEach(() => {
|
|||||||
edges: [
|
edges: [
|
||||||
{
|
{
|
||||||
node: {
|
node: {
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: ''
|
slug: ''
|
||||||
},
|
},
|
||||||
id: '5e46f802ac417301a38fb92b',
|
id: '5e46f802ac417301a38fb92b',
|
||||||
title: 'Page View Time Series Visualizer'
|
title: 'Page View Time Series Visualizer'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: {
|
node: {
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: ''
|
slug: ''
|
||||||
},
|
},
|
||||||
id: '5e4f5c4b570f7e3a4949899f',
|
id: '5e4f5c4b570f7e3a4949899f',
|
||||||
title: 'Sea Level Predictor'
|
title: 'Sea Level Predictor'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: {
|
node: {
|
||||||
|
challenge: {
|
||||||
fields: {
|
fields: {
|
||||||
slug: ''
|
slug: ''
|
||||||
},
|
},
|
||||||
@ -37,6 +42,7 @@ beforeEach(() => {
|
|||||||
title: 'Medical Data Visualizer'
|
title: 'Medical Data Visualizer'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -53,9 +53,11 @@ interface LearnPageProps {
|
|||||||
user: User;
|
user: User;
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
fields: Slug;
|
fields: Slug;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
executeGA: (payload: Record<string, unknown>) => void;
|
executeGA: (payload: Record<string, unknown>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,9 +72,11 @@ function LearnPage({
|
|||||||
executeGA,
|
executeGA,
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
fields: { slug }
|
fields: { slug }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}: LearnPageProps) {
|
}: LearnPageProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -117,10 +121,12 @@ export default connect(mapStateToProps, mapDispatchToProps)(LearnPage);
|
|||||||
|
|
||||||
export const query = graphql`
|
export const query = graphql`
|
||||||
query FirstChallenge {
|
query FirstChallenge {
|
||||||
challengeNode(order: { eq: 0 }, challengeOrder: { eq: 0 }) {
|
challengeNode(challenge: { order: { eq: 0 }, challengeOrder: { eq: 0 } }) {
|
||||||
|
challenge {
|
||||||
fields {
|
fields {
|
||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -128,6 +128,7 @@ export interface VideoLocaleIds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ChallengeNode = {
|
export type ChallengeNode = {
|
||||||
|
challenge: {
|
||||||
block: string;
|
block: string;
|
||||||
challengeOrder: number;
|
challengeOrder: number;
|
||||||
challengeType: number;
|
challengeType: number;
|
||||||
@ -177,6 +178,7 @@ export type ChallengeNode = {
|
|||||||
videoLocaleIds?: VideoLocaleIds;
|
videoLocaleIds?: VideoLocaleIds;
|
||||||
bilibiliIds?: BilibiliIds;
|
bilibiliIds?: BilibiliIds;
|
||||||
videoUrl: string;
|
videoUrl: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AllChallengeNode = {
|
export type AllChallengeNode = {
|
||||||
|
@ -212,7 +212,9 @@ class ShowClassic extends Component<ShowClassicProps, ShowClassicState> {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const {
|
const {
|
||||||
data: {
|
data: {
|
||||||
challengeNode: { title }
|
challengeNode: {
|
||||||
|
challenge: { title }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} = this.props;
|
} = this.props;
|
||||||
this.initializeComponent(title);
|
this.initializeComponent(title);
|
||||||
@ -222,18 +224,22 @@ class ShowClassic extends Component<ShowClassicProps, ShowClassicState> {
|
|||||||
const {
|
const {
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
title: prevTitle,
|
title: prevTitle,
|
||||||
fields: { tests: prevTests }
|
fields: { tests: prevTests }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} = prevProps;
|
} = prevProps;
|
||||||
const {
|
const {
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
title: currentTitle,
|
title: currentTitle,
|
||||||
fields: { tests: currTests }
|
fields: { tests: currTests }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (prevTitle !== currentTitle || prevTests !== currTests) {
|
if (prevTitle !== currentTitle || prevTests !== currTests) {
|
||||||
this.initializeComponent(currentTitle);
|
this.initializeComponent(currentTitle);
|
||||||
@ -250,12 +256,14 @@ class ShowClassic extends Component<ShowClassicProps, ShowClassicState> {
|
|||||||
openModal,
|
openModal,
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
challengeFiles,
|
challengeFiles,
|
||||||
fields: { tests },
|
fields: { tests },
|
||||||
challengeType,
|
challengeType,
|
||||||
removeComments,
|
removeComments,
|
||||||
helpCategory
|
helpCategory
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
pageContext: {
|
pageContext: {
|
||||||
challengeMeta,
|
challengeMeta,
|
||||||
@ -282,7 +290,7 @@ class ShowClassic extends Component<ShowClassicProps, ShowClassicState> {
|
|||||||
cancelTests();
|
cancelTests();
|
||||||
}
|
}
|
||||||
|
|
||||||
getChallenge = () => this.props.data.challengeNode;
|
getChallenge = () => this.props.data.challengeNode.challenge;
|
||||||
|
|
||||||
getBlockNameTitle(t: TFunction) {
|
getBlockNameTitle(t: TFunction) {
|
||||||
const { block, superBlock, title } = this.getChallenge();
|
const { block, superBlock, title } = this.getChallenge();
|
||||||
@ -337,10 +345,12 @@ class ShowClassic extends Component<ShowClassicProps, ShowClassicState> {
|
|||||||
challengeFiles,
|
challengeFiles,
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
fields: { tests },
|
fields: { tests },
|
||||||
usesMultifileEditor
|
usesMultifileEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { description, title } = this.getChallenge();
|
const { description, title } = this.getChallenge();
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
@ -489,7 +499,8 @@ export default connect(
|
|||||||
|
|
||||||
export const query = graphql`
|
export const query = graphql`
|
||||||
query ClassicChallenge($slug: String!) {
|
query ClassicChallenge($slug: String!) {
|
||||||
challengeNode(fields: { slug: { eq: $slug } }) {
|
challengeNode(challenge: { fields: { slug: { eq: $slug } } }) {
|
||||||
|
challenge {
|
||||||
block
|
block
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
@ -526,4 +537,5 @@ export const query = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -49,7 +49,9 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
|
|||||||
const {
|
const {
|
||||||
updateChallengeMeta,
|
updateChallengeMeta,
|
||||||
data: {
|
data: {
|
||||||
challengeNode: { challengeType, title }
|
challengeNode: {
|
||||||
|
challenge: { challengeType, title }
|
||||||
|
}
|
||||||
},
|
},
|
||||||
pageContext: { challengeMeta }
|
pageContext: { challengeMeta }
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@ -60,10 +62,12 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
|
|||||||
const {
|
const {
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
title,
|
title,
|
||||||
fields: { blockName },
|
fields: { blockName },
|
||||||
url
|
url
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
webhookToken = null
|
webhookToken = null
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@ -94,7 +98,8 @@ export default connect(mapStateToProps, mapDispatchToProps)(ShowCodeAlly);
|
|||||||
// GraphQL
|
// GraphQL
|
||||||
export const query = graphql`
|
export const query = graphql`
|
||||||
query CodeAllyChallenge($slug: String!) {
|
query CodeAllyChallenge($slug: String!) {
|
||||||
challengeNode(fields: { slug: { eq: $slug } }) {
|
challengeNode(challenge: { fields: { slug: { eq: $slug } } }) {
|
||||||
|
challenge {
|
||||||
title
|
title
|
||||||
challengeType
|
challengeType
|
||||||
url
|
url
|
||||||
@ -103,4 +108,5 @@ export const query = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -280,9 +280,18 @@ const useCurrentBlockIds = (blockName: string) => {
|
|||||||
allChallengeNode: { edges }
|
allChallengeNode: { edges }
|
||||||
}: { allChallengeNode: AllChallengeNode } = useStaticQuery(graphql`
|
}: { allChallengeNode: AllChallengeNode } = useStaticQuery(graphql`
|
||||||
query getCurrentBlockNodes {
|
query getCurrentBlockNodes {
|
||||||
allChallengeNode(sort: { fields: [superOrder, order, challengeOrder] }) {
|
allChallengeNode(
|
||||||
|
sort: {
|
||||||
|
fields: [
|
||||||
|
challenge___superOrder
|
||||||
|
challenge___order
|
||||||
|
challenge___challengeOrder
|
||||||
|
]
|
||||||
|
}
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
|
challenge {
|
||||||
fields {
|
fields {
|
||||||
blockName
|
blockName
|
||||||
}
|
}
|
||||||
@ -291,12 +300,13 @@ const useCurrentBlockIds = (blockName: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const currentBlockIds = edges
|
const currentBlockIds = edges
|
||||||
.filter(edge => edge.node.fields.blockName === blockName)
|
.filter(edge => edge.node.challenge.fields.blockName === blockName)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
.map(edge => edge.node.id);
|
.map(edge => edge.node.challenge.id);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||||
return currentBlockIds;
|
return currentBlockIds;
|
||||||
};
|
};
|
||||||
|
@ -123,18 +123,22 @@ class BackEnd extends Component<BackEndProps> {
|
|||||||
const {
|
const {
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
title: prevTitle,
|
title: prevTitle,
|
||||||
fields: { tests: prevTests }
|
fields: { tests: prevTests }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} = prevProps;
|
} = prevProps;
|
||||||
const {
|
const {
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
title: currentTitle,
|
title: currentTitle,
|
||||||
fields: { tests: currTests }
|
fields: { tests: currTests }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (prevTitle !== currentTitle || prevTests !== currTests) {
|
if (prevTitle !== currentTitle || prevTests !== currTests) {
|
||||||
this.initializeComponent();
|
this.initializeComponent();
|
||||||
@ -149,11 +153,13 @@ class BackEnd extends Component<BackEndProps> {
|
|||||||
updateChallengeMeta,
|
updateChallengeMeta,
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
fields: { tests },
|
fields: { tests },
|
||||||
title,
|
title,
|
||||||
challengeType,
|
challengeType,
|
||||||
helpCategory
|
helpCategory
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
pageContext: { challengeMeta }
|
pageContext: { challengeMeta }
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@ -182,6 +188,7 @@ class BackEnd extends Component<BackEndProps> {
|
|||||||
const {
|
const {
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
fields: { blockName },
|
fields: { blockName },
|
||||||
challengeType,
|
challengeType,
|
||||||
forumTopicId,
|
forumTopicId,
|
||||||
@ -192,6 +199,7 @@ class BackEnd extends Component<BackEndProps> {
|
|||||||
superBlock,
|
superBlock,
|
||||||
block
|
block
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
isChallengeCompleted,
|
isChallengeCompleted,
|
||||||
output,
|
output,
|
||||||
@ -278,7 +286,8 @@ export default connect(
|
|||||||
|
|
||||||
export const query = graphql`
|
export const query = graphql`
|
||||||
query BackendChallenge($slug: String!) {
|
query BackendChallenge($slug: String!) {
|
||||||
challengeNode(fields: { slug: { eq: $slug } }) {
|
challengeNode(challenge: { fields: { slug: { eq: $slug } } }) {
|
||||||
|
challenge {
|
||||||
forumTopicId
|
forumTopicId
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
@ -298,4 +307,5 @@ export const query = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -76,7 +76,9 @@ class Project extends Component<ProjectProps> {
|
|||||||
const {
|
const {
|
||||||
challengeMounted,
|
challengeMounted,
|
||||||
data: {
|
data: {
|
||||||
challengeNode: { title, challengeType, helpCategory }
|
challengeNode: {
|
||||||
|
challenge: { title, challengeType, helpCategory }
|
||||||
|
}
|
||||||
},
|
},
|
||||||
pageContext: { challengeMeta },
|
pageContext: { challengeMeta },
|
||||||
updateChallengeMeta
|
updateChallengeMeta
|
||||||
@ -94,13 +96,17 @@ class Project extends Component<ProjectProps> {
|
|||||||
componentDidUpdate(prevProps: ProjectProps): void {
|
componentDidUpdate(prevProps: ProjectProps): void {
|
||||||
const {
|
const {
|
||||||
data: {
|
data: {
|
||||||
challengeNode: { title: prevTitle }
|
challengeNode: {
|
||||||
|
challenge: { title: prevTitle }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} = prevProps;
|
} = prevProps;
|
||||||
const {
|
const {
|
||||||
challengeMounted,
|
challengeMounted,
|
||||||
data: {
|
data: {
|
||||||
challengeNode: { title: currentTitle, challengeType, helpCategory }
|
challengeNode: {
|
||||||
|
challenge: { title: currentTitle, challengeType, helpCategory }
|
||||||
|
}
|
||||||
},
|
},
|
||||||
pageContext: { challengeMeta },
|
pageContext: { challengeMeta },
|
||||||
updateChallengeMeta
|
updateChallengeMeta
|
||||||
@ -130,6 +136,7 @@ class Project extends Component<ProjectProps> {
|
|||||||
const {
|
const {
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
challengeType,
|
challengeType,
|
||||||
fields: { blockName },
|
fields: { blockName },
|
||||||
forumTopicId,
|
forumTopicId,
|
||||||
@ -140,6 +147,7 @@ class Project extends Component<ProjectProps> {
|
|||||||
block,
|
block,
|
||||||
translationPending
|
translationPending
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
isChallengeCompleted,
|
isChallengeCompleted,
|
||||||
pageContext: {
|
pageContext: {
|
||||||
@ -215,7 +223,8 @@ export default connect(
|
|||||||
|
|
||||||
export const query = graphql`
|
export const query = graphql`
|
||||||
query ProjectChallenge($slug: String!) {
|
query ProjectChallenge($slug: String!) {
|
||||||
challengeNode(fields: { slug: { eq: $slug } }) {
|
challengeNode(challenge: { fields: { slug: { eq: $slug } } }) {
|
||||||
|
challenge {
|
||||||
forumTopicId
|
forumTopicId
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
@ -231,4 +240,5 @@ export const query = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -97,7 +97,9 @@ class ShowVideo extends Component<ShowVideoProps, ShowVideoState> {
|
|||||||
const {
|
const {
|
||||||
challengeMounted,
|
challengeMounted,
|
||||||
data: {
|
data: {
|
||||||
challengeNode: { title, challengeType, helpCategory }
|
challengeNode: {
|
||||||
|
challenge: { title, challengeType, helpCategory }
|
||||||
|
}
|
||||||
},
|
},
|
||||||
pageContext: { challengeMeta },
|
pageContext: { challengeMeta },
|
||||||
updateChallengeMeta
|
updateChallengeMeta
|
||||||
@ -115,13 +117,17 @@ class ShowVideo extends Component<ShowVideoProps, ShowVideoState> {
|
|||||||
componentDidUpdate(prevProps: ShowVideoProps): void {
|
componentDidUpdate(prevProps: ShowVideoProps): void {
|
||||||
const {
|
const {
|
||||||
data: {
|
data: {
|
||||||
challengeNode: { title: prevTitle }
|
challengeNode: {
|
||||||
|
challenge: { title: prevTitle }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} = prevProps;
|
} = prevProps;
|
||||||
const {
|
const {
|
||||||
challengeMounted,
|
challengeMounted,
|
||||||
data: {
|
data: {
|
||||||
challengeNode: { title: currentTitle, challengeType, helpCategory }
|
challengeNode: {
|
||||||
|
challenge: { title: currentTitle, challengeType, helpCategory }
|
||||||
|
}
|
||||||
},
|
},
|
||||||
pageContext: { challengeMeta },
|
pageContext: { challengeMeta },
|
||||||
updateChallengeMeta
|
updateChallengeMeta
|
||||||
@ -169,6 +175,7 @@ class ShowVideo extends Component<ShowVideoProps, ShowVideoState> {
|
|||||||
const {
|
const {
|
||||||
data: {
|
data: {
|
||||||
challengeNode: {
|
challengeNode: {
|
||||||
|
challenge: {
|
||||||
fields: { blockName },
|
fields: { blockName },
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
@ -180,6 +187,7 @@ class ShowVideo extends Component<ShowVideoProps, ShowVideoState> {
|
|||||||
bilibiliIds,
|
bilibiliIds,
|
||||||
question: { text, answers, solution }
|
question: { text, answers, solution }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
openCompletionModal,
|
openCompletionModal,
|
||||||
pageContext: {
|
pageContext: {
|
||||||
@ -313,7 +321,8 @@ export default connect(
|
|||||||
|
|
||||||
export const query = graphql`
|
export const query = graphql`
|
||||||
query VideoChallenge($slug: String!) {
|
query VideoChallenge($slug: String!) {
|
||||||
challengeNode(fields: { slug: { eq: $slug } }) {
|
challengeNode(challenge: { fields: { slug: { eq: $slug } } }) {
|
||||||
|
challenge {
|
||||||
videoId
|
videoId
|
||||||
videoLocaleIds {
|
videoLocaleIds {
|
||||||
espanol
|
espanol
|
||||||
@ -343,4 +352,5 @@ export const query = graphql`
|
|||||||
translationPending
|
translationPending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -101,7 +101,7 @@ export class Block extends Component<BlockProps> {
|
|||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
let completedCount = 0;
|
let completedCount = 0;
|
||||||
const challengesWithCompleted = challenges.map(challenge => {
|
const challengesWithCompleted = challenges.map(({ challenge }) => {
|
||||||
const { id } = challenge;
|
const { id } = challenge;
|
||||||
const isCompleted = completedChallengeIds.some(
|
const isCompleted = completedChallengeIds.some(
|
||||||
(completedChallengeId: string) => completedChallengeId === id
|
(completedChallengeId: string) => completedChallengeId === id
|
||||||
@ -112,7 +112,7 @@ export class Block extends Component<BlockProps> {
|
|||||||
return { ...challenge, isCompleted };
|
return { ...challenge, isCompleted };
|
||||||
});
|
});
|
||||||
|
|
||||||
const isProjectBlock = challenges.some(challenge => {
|
const isProjectBlock = challenges.some(({ challenge }) => {
|
||||||
const isJsProject =
|
const isJsProject =
|
||||||
challenge.order === 10 && challenge.challengeType === 5;
|
challenge.order === 10 && challenge.challengeType === 5;
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ function renderMenuItems({
|
|||||||
edges?: Array<{ node: ChallengeNode }>;
|
edges?: Array<{ node: ChallengeNode }>;
|
||||||
}) {
|
}) {
|
||||||
return edges
|
return edges
|
||||||
.map(({ node }) => node)
|
.map(({ node: { challenge } }) => challenge)
|
||||||
.map(({ title, fields: { slug } }) => (
|
.map(({ title, fields: { slug } }) => (
|
||||||
<Link key={'intro-' + slug} to={slug}>
|
<Link key={'intro-' + slug} to={slug}>
|
||||||
<ListGroupItem>{title}</ListGroupItem>
|
<ListGroupItem>{title}</ListGroupItem>
|
||||||
@ -42,7 +42,8 @@ function IntroductionPage({
|
|||||||
html,
|
html,
|
||||||
frontmatter: { block }
|
frontmatter: { block }
|
||||||
} = markdownRemark;
|
} = markdownRemark;
|
||||||
const firstLesson = allChallengeNode && allChallengeNode.edges[0].node;
|
const firstLesson =
|
||||||
|
allChallengeNode && allChallengeNode.edges[0].node.challenge;
|
||||||
const firstLessonPath = firstLesson
|
const firstLessonPath = firstLesson
|
||||||
? firstLesson.fields.slug
|
? firstLesson.fields.slug
|
||||||
: '/strange-place';
|
: '/strange-place';
|
||||||
@ -97,11 +98,18 @@ export const query = graphql`
|
|||||||
html
|
html
|
||||||
}
|
}
|
||||||
allChallengeNode(
|
allChallengeNode(
|
||||||
filter: { block: { eq: $block } }
|
filter: { challenge: { block: { eq: $block } } }
|
||||||
sort: { fields: [superOrder, order, challengeOrder] }
|
sort: {
|
||||||
|
fields: [
|
||||||
|
challenge___superOrder
|
||||||
|
challenge___order
|
||||||
|
challenge___challengeOrder
|
||||||
|
]
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
|
challenge {
|
||||||
fields {
|
fields {
|
||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
@ -110,4 +118,5 @@ export const query = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -141,15 +141,15 @@ const SuperBlockIntroductionPage = (props: SuperBlockProp) => {
|
|||||||
if (isSignedIn) {
|
if (isSignedIn) {
|
||||||
// see if currentChallenge is in this superBlock
|
// see if currentChallenge is in this superBlock
|
||||||
const currentChallengeEdge = edges.find(
|
const currentChallengeEdge = edges.find(
|
||||||
edge => edge.node.id === currentChallengeId
|
edge => edge.node.challenge.id === currentChallengeId
|
||||||
);
|
);
|
||||||
|
|
||||||
return currentChallengeEdge
|
return currentChallengeEdge
|
||||||
? currentChallengeEdge.node.block
|
? currentChallengeEdge.node.challenge.block
|
||||||
: edge.node.block;
|
: edge.node.challenge.block;
|
||||||
}
|
}
|
||||||
|
|
||||||
return edge.node.block;
|
return edge.node.challenge.block;
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeExpandedState = () => {
|
const initializeExpandedState = () => {
|
||||||
@ -173,7 +173,9 @@ const SuperBlockIntroductionPage = (props: SuperBlockProp) => {
|
|||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const nodesForSuperBlock = edges.map(({ node }) => node);
|
const nodesForSuperBlock = edges.map(({ node }) => node);
|
||||||
const blockDashedNames = uniq(nodesForSuperBlock.map(({ block }) => block));
|
const blockDashedNames = uniq(
|
||||||
|
nodesForSuperBlock.map(({ challenge: { block } }) => block)
|
||||||
|
);
|
||||||
const i18nSuperBlock = t(`intro:${superBlock}.title`);
|
const i18nSuperBlock = t(`intro:${superBlock}.title`);
|
||||||
const i18nTitle =
|
const i18nTitle =
|
||||||
superBlock === SuperBlocks.CodingInterviewPrep
|
superBlock === SuperBlocks.CodingInterviewPrep
|
||||||
@ -206,7 +208,7 @@ const SuperBlockIntroductionPage = (props: SuperBlockProp) => {
|
|||||||
<Block
|
<Block
|
||||||
blockDashedName={blockDashedName}
|
blockDashedName={blockDashedName}
|
||||||
challenges={nodesForSuperBlock.filter(
|
challenges={nodesForSuperBlock.filter(
|
||||||
node => node.block === blockDashedName
|
node => node.challenge.block === blockDashedName
|
||||||
)}
|
)}
|
||||||
superBlock={superBlock}
|
superBlock={superBlock}
|
||||||
/>
|
/>
|
||||||
@ -263,11 +265,18 @@ export const query = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
allChallengeNode(
|
allChallengeNode(
|
||||||
sort: { fields: [superOrder, order, challengeOrder] }
|
sort: {
|
||||||
filter: { superBlock: { eq: $superBlock } }
|
fields: [
|
||||||
|
challenge___superOrder
|
||||||
|
challenge___order
|
||||||
|
challenge___challengeOrder
|
||||||
|
]
|
||||||
|
}
|
||||||
|
filter: { challenge: { superBlock: { eq: $superBlock } } }
|
||||||
) {
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
|
challenge {
|
||||||
fields {
|
fields {
|
||||||
slug
|
slug
|
||||||
blockName
|
blockName
|
||||||
@ -283,4 +292,5 @@ export const query = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -45,12 +45,12 @@ const views = {
|
|||||||
|
|
||||||
function getNextChallengePath(_node, index, nodeArray) {
|
function getNextChallengePath(_node, index, nodeArray) {
|
||||||
const next = nodeArray[index + 1];
|
const next = nodeArray[index + 1];
|
||||||
return next ? next.node.fields.slug : '/learn';
|
return next ? next.node.challenge.fields.slug : '/learn';
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrevChallengePath(_node, index, nodeArray) {
|
function getPrevChallengePath(_node, index, nodeArray) {
|
||||||
const prev = nodeArray[index - 1];
|
const prev = nodeArray[index - 1];
|
||||||
return prev ? prev.node.fields.slug : '/learn';
|
return prev ? prev.node.challenge.fields.slug : '/learn';
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTemplateComponent(challengeType) {
|
function getTemplateComponent(challengeType) {
|
||||||
@ -58,7 +58,7 @@ function getTemplateComponent(challengeType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exports.createChallengePages = function (createPage) {
|
exports.createChallengePages = function (createPage) {
|
||||||
return function ({ node: challenge }, index, allChallengeEdges) {
|
return function ({ node: { challenge } }, index, allChallengeEdges) {
|
||||||
const {
|
const {
|
||||||
superBlock,
|
superBlock,
|
||||||
block,
|
block,
|
||||||
@ -103,8 +103,8 @@ function getProjectPreviewConfig(challenge, allChallengeEdges) {
|
|||||||
const { block, challengeOrder, usesMultifileEditor } = challenge;
|
const { block, challengeOrder, usesMultifileEditor } = challenge;
|
||||||
|
|
||||||
const challengesInBlock = allChallengeEdges
|
const challengesInBlock = allChallengeEdges
|
||||||
.filter(({ node }) => node.block === block)
|
.filter(({ node: { challenge } }) => challenge.block === block)
|
||||||
.map(({ node }) => node);
|
.map(({ node: { challenge } }) => challenge);
|
||||||
const lastChallenge = challengesInBlock[challengesInBlock.length - 1];
|
const lastChallenge = challengesInBlock[challengesInBlock.length - 1];
|
||||||
const solutionToLastChallenge = sortChallengeFiles(
|
const solutionToLastChallenge = sortChallengeFiles(
|
||||||
lastChallenge.solutions[0] ?? []
|
lastChallenge.solutions[0] ?? []
|
||||||
|
Reference in New Issue
Block a user