From 8c0b459c2bbfc397b1c4fc9d733616d838c27c65 Mon Sep 17 00:00:00 2001 From: Oliver Eyton-Williams Date: Mon, 19 Aug 2024 13:56:44 +0200 Subject: [PATCH] refactor(client): replace Map's static query with page queries (#55792) --- client/src/components/Map/index.tsx | 35 ++----- .../landing/components/certifications.tsx | 12 ++- client/src/components/landing/index.tsx | 59 ----------- .../src/components/landing/landing.test.tsx | 30 ------ client/src/pages/index.tsx | 98 ++++++++++++++++++- client/src/pages/learn.tsx | 24 ++++- .../Introduction/super-block-intro.tsx | 32 +++--- client/utils/gatsby/challenge-page-creator.js | 8 +- 8 files changed, 152 insertions(+), 146 deletions(-) delete mode 100644 client/src/components/landing/index.tsx delete mode 100644 client/src/components/landing/landing.test.tsx diff --git a/client/src/components/Map/index.tsx b/client/src/components/Map/index.tsx index ac77091c349..17ca474afee 100644 --- a/client/src/components/Map/index.tsx +++ b/client/src/components/Map/index.tsx @@ -1,5 +1,4 @@ import React, { Fragment } from 'react'; -import { graphql, useStaticQuery } from 'gatsby'; import { useTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; @@ -27,11 +26,7 @@ import { import { RibbonIcon } from '../../assets/icons/completion-ribbon'; -import { - CurrentCert, - ClaimedCertifications, - AllChallengeNode -} from '../../redux/prop-types'; +import { CurrentCert, ClaimedCertifications } from '../../redux/prop-types'; import { certSlugTypeMap, superBlockCertTypeMap @@ -44,6 +39,10 @@ interface MapProps { currentCerts: CurrentCert[]; claimedCertifications?: ClaimedCertifications; completedChallengeIds: string[]; + allChallenges: { + id: string; + superBlock: SuperBlocks; + }[]; } const linkSpacingStyle = { @@ -131,29 +130,9 @@ function Map({ forLanding = false, isSignedIn, currentCerts, - completedChallengeIds + completedChallengeIds, + allChallenges }: MapProps): React.ReactElement { - const { - allChallengeNode: { edges } - }: { - allChallengeNode: AllChallengeNode; - } = useStaticQuery(graphql` - query allChallenges { - allChallengeNode { - edges { - node { - challenge { - id - superBlock - } - } - } - } - } - `); - - const allChallenges = edges.map(edge => edge.node.challenge); - const { t } = useTranslation(); const allSuperblockChallengesCompleted = (superblock: SuperBlocks) => { diff --git a/client/src/components/landing/components/certifications.tsx b/client/src/components/landing/components/certifications.tsx index 88968272d55..ca4c2170a57 100644 --- a/client/src/components/landing/components/certifications.tsx +++ b/client/src/components/landing/components/certifications.tsx @@ -3,9 +3,17 @@ import { Col } from '@freecodecamp/ui'; import Map from '../../Map/index'; import { Spacer } from '../../helpers'; +import { type SuperBlocks } from '../../../../../shared/config/curriculum'; import BigCallToAction from './big-call-to-action'; -const Certifications = (): JSX.Element => { +const Certifications = ({ + allChallenges +}: { + allChallenges: { + id: string; + superBlock: SuperBlocks; + }[]; +}): JSX.Element => { return ( { smOffset={1} xs={12} > - + diff --git a/client/src/components/landing/index.tsx b/client/src/components/landing/index.tsx deleted file mode 100644 index 573809ff4d5..00000000000 --- a/client/src/components/landing/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React, { ReactElement } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useGrowthBook } from '@growthbook/growthbook-react'; -import SEO from '../seo'; -import { Loader } from '../helpers'; -import AsSeenIn from './components/as-seen-in'; -import Certifications from './components/certifications'; -import LandingTop from './components/landing-top'; -import LandingTopB from './components/landing-top-b'; -import Testimonials from './components/testimonials'; -import Faq from './components/faq'; - -import './landing.css'; - -const LandingA = () => ( -
- - - - - -
-); - -const LandingB = () => ( -
- - - - -
-); - -function Landing(): ReactElement { - const { t } = useTranslation(); - const growthbook = useGrowthBook(); - if (growthbook && growthbook.ready) { - const showLandingPageRedesign = growthbook.getFeatureValue( - 'landing-page-redesign', - false - ); - return ( - <> - - {showLandingPageRedesign === true ? : } - - ); - } else { - return ( - <> - - - - ); - } -} - -Landing.displayName = 'Landing'; -export default Landing; diff --git a/client/src/components/landing/landing.test.tsx b/client/src/components/landing/landing.test.tsx deleted file mode 100644 index e34c7a11b98..00000000000 --- a/client/src/components/landing/landing.test.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; -import { createRenderer } from 'react-test-renderer/shallow'; - -import mockChallengeNodes from '../../__mocks__/challenge-nodes'; -import IndexPage from '../../pages'; - -jest.mock('../../analytics'); - -describe('', () => { - it('renders when visiting index page and logged out', () => { - const utils = createRenderer(); - // @ts-expect-error Type definition mismatch - utils.render(); - const view = utils.getRenderOutput(); - // @ts-expect-error Type definition mismatch - expect(view.type.displayName === 'Landing').toBeTruthy(); - }); -}); - -const loggedOutProps = { - data: { allChallengeNode: { edges: mockChallengeNodes } }, - fetchState: { - complete: true, - error: null, - errored: false, - pending: false - }, - isSignedIn: false, - user: {} -}; diff --git a/client/src/pages/index.tsx b/client/src/pages/index.tsx index 38b541bd5a4..3c78f9f0d43 100644 --- a/client/src/pages/index.tsx +++ b/client/src/pages/index.tsx @@ -1,11 +1,103 @@ import React from 'react'; +import { graphql } from 'gatsby'; +import { useTranslation } from 'react-i18next'; +import { useGrowthBook } from '@growthbook/growthbook-react'; -import Landing from '../components/landing'; +import { SuperBlocks } from '../../../shared/config/curriculum'; +import SEO from '../components/seo'; +import { Loader } from '../components/helpers'; +import LandingTop from '../components/landing/components/landing-top'; +import LandingTopB from '../components/landing/components/landing-top-b'; +import AsSeenIn from '../components/landing/components/as-seen-in'; +import Testimonials from '../components/landing/components/testimonials'; +import Certifications from '../components/landing/components/certifications'; +import Faq from '../components/landing/components/faq'; +import '../components/landing/landing.css'; -function IndexPage(): JSX.Element { - return ; +type Challenge = { + id: string; + superBlock: SuperBlocks; +}; + +type Props = { + data: { + allChallengeNode: { + nodes: { + challenge: Challenge; + }[]; + }; + }; +}; + +type LandingProps = { + allChallenges: Challenge[]; +}; + +const LandingA = ({ allChallenges }: LandingProps) => ( +
+ + + + + +
+); + +const LandingB = ({ allChallenges }: LandingProps) => ( +
+ + + + +
+); + +function IndexPage({ + data: { + allChallengeNode: { nodes: challengeNodes } + } +}: Props): JSX.Element { + const { t } = useTranslation(); + const growthbook = useGrowthBook(); + const allChallenges = challengeNodes.map(node => node.challenge); + if (growthbook && growthbook.ready) { + const showLandingPageRedesign = growthbook.getFeatureValue( + 'landing-page-redesign', + false + ); + return ( + <> + + {showLandingPageRedesign === true ? ( + + ) : ( + + )} + + ); + } else { + return ( + <> + + + + ); + } } IndexPage.displayName = 'IndexPage'; export default IndexPage; + +export const query = graphql` + query AllChallengeNode { + allChallengeNode { + nodes { + challenge { + id + superBlock + } + } + } + } +`; diff --git a/client/src/pages/learn.tsx b/client/src/pages/learn.tsx index 6145e4a2628..b782acccf0d 100644 --- a/client/src/pages/learn.tsx +++ b/client/src/pages/learn.tsx @@ -17,6 +17,7 @@ import { } from '../redux/selectors'; import callGA from '../analytics/call-ga'; +import { SuperBlocks } from '../../../shared/config/curriculum'; interface FetchState { pending: boolean; @@ -57,6 +58,14 @@ interface LearnPageProps { fields: Slug; }; }; + allChallengeNode: { + nodes: { + challenge: { + id: string; + superBlock: SuperBlocks; + }; + }[]; + }; }; } @@ -69,7 +78,8 @@ function LearnPage({ challenge: { fields: { slug } } - } + }, + allChallengeNode: { nodes: challengeNodes } } }: LearnPageProps) { const { t } = useTranslation(); @@ -96,7 +106,7 @@ function LearnPage({ onLearnDonationAlertClick={onLearnDonationAlertClick} isDonating={isDonating} /> - + node.challenge)} /> @@ -110,7 +120,7 @@ LearnPage.displayName = 'LearnPage'; export default connect(mapStateToProps)(LearnPage); export const query = graphql` - query FirstChallenge { + query LearnPageQuery { challengeNode( challenge: { superOrder: { eq: 0 } @@ -124,5 +134,13 @@ export const query = graphql` } } } + allChallengeNode { + nodes { + challenge { + id + superBlock + } + } + } } `; diff --git a/client/src/templates/Introduction/super-block-intro.tsx b/client/src/templates/Introduction/super-block-intro.tsx index 83682ededea..fa51b35a3e6 100644 --- a/client/src/templates/Introduction/super-block-intro.tsx +++ b/client/src/templates/Introduction/super-block-intro.tsx @@ -25,7 +25,8 @@ import { userFetchStateSelector, signInLoadingSelector } from '../../redux/selectors'; -import { MarkdownRemark, AllChallengeNode, User } from '../../redux/prop-types'; +import type { AllChallengeNode, User } from '../../redux/prop-types'; +import { CertTitle } from '../../../config/cert-and-project-map'; import Block from './components/block'; import CertChallenge from './components/cert-challenge'; import LegacyLinks from './components/legacy-links'; @@ -44,7 +45,6 @@ type FetchState = { type SuperBlockProp = { currentChallengeId: string; data: { - markdownRemark: MarkdownRemark; allChallengeNode: AllChallengeNode; }; expandedState: { @@ -54,6 +54,11 @@ type SuperBlockProp = { isSignedIn: boolean; signInLoading: boolean; location: WindowLocation<{ breadcrumbBlockClick: string }>; + pageContext: { + superBlock: SuperBlocks; + title: CertTitle; + certification: string; + }; resetExpansion: () => void; toggleBlock: (arg0: string) => void; tryToShowDonationModal: () => void; @@ -164,17 +169,18 @@ const SuperBlockIntroductionPage = (props: SuperBlockProp) => { const { data: { - markdownRemark: { - frontmatter: { superBlock, title, certification } - }, allChallengeNode: { edges } }, isSignedIn, signInLoading, - user + user, + pageContext: { superBlock, title, certification } } = props; - const nodesForSuperBlock = edges.map(({ node }) => node); + const allChallenges = edges.map(({ node }) => node.challenge); + const nodesForSuperBlock = edges + .filter(edge => edge.node.challenge.superBlock === superBlock) + .map(({ node }) => node); const blockDashedNames = uniq( nodesForSuperBlock.map(({ challenge: { block } }) => block) ); @@ -257,7 +263,7 @@ const SuperBlockIntroductionPage = (props: SuperBlockProp) => { {t(`intro:misc-text.browse-other`)} - + @@ -276,14 +282,7 @@ export default connect( )(withTranslation()(memo(SuperBlockIntroductionPage))); export const query = graphql` - query SuperBlockIntroPageBySlug($id: String!, $superBlock: String!) { - markdownRemark(id: { eq: $id }) { - frontmatter { - certification - superBlock - title - } - } + query SuperBlockIntroPageQuery { allChallengeNode( sort: { fields: [ @@ -292,7 +291,6 @@ export const query = graphql` challenge___challengeOrder ] } - filter: { challenge: { superBlock: { eq: $superBlock } } } ) { edges { node { diff --git a/client/utils/gatsby/challenge-page-creator.js b/client/utils/gatsby/challenge-page-creator.js index e05746df383..7c1b8a99bed 100644 --- a/client/utils/gatsby/challenge-page-creator.js +++ b/client/utils/gatsby/challenge-page-creator.js @@ -198,8 +198,7 @@ exports.createSuperBlockIntroPages = function (createPage) { return function (edge) { const { fields: { slug }, - frontmatter: { superBlock, certification }, - id + frontmatter: { superBlock, certification, title } } = edge.node; if (!certification) { @@ -215,8 +214,9 @@ exports.createSuperBlockIntroPages = function (createPage) { path: slug, component: superBlockIntro, context: { - id, - superBlock + certification, + superBlock, + title } }); };