refactor(client): replace Map's static query with page queries (#55792)

pull/55894/head
Oliver Eyton-Williams 2024-08-19 13:56:44 +02:00 committed by GitHub
parent 7345989917
commit 8c0b459c2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 152 additions and 146 deletions

View File

@ -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) => {

View File

@ -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 (
<Col
className='certification-section'
@ -15,7 +23,7 @@ const Certifications = (): JSX.Element => {
smOffset={1}
xs={12}
>
<Map forLanding={true} />
<Map allChallenges={allChallenges} forLanding={true} />
<Spacer size='medium' />
<BigCallToAction />
<Spacer size='medium' />

View File

@ -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 = () => (
<main className='landing-page'>
<LandingTop />
<AsSeenIn />
<Testimonials />
<Certifications />
<Faq />
</main>
);
const LandingB = () => (
<main className='landing-page landing-page-b'>
<LandingTopB />
<Testimonials />
<Certifications />
<Faq />
</main>
);
function Landing(): ReactElement {
const { t } = useTranslation();
const growthbook = useGrowthBook();
if (growthbook && growthbook.ready) {
const showLandingPageRedesign = growthbook.getFeatureValue(
'landing-page-redesign',
false
);
return (
<>
<SEO title={t('metaTags:title')} />
{showLandingPageRedesign === true ? <LandingB /> : <LandingA />}
</>
);
} else {
return (
<>
<SEO title={t('metaTags:title')} />
<Loader fullScreen={true} />
</>
);
}
}
Landing.displayName = 'Landing';
export default Landing;

View File

@ -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('<Landing />', () => {
it('renders when visiting index page and logged out', () => {
const utils = createRenderer();
// @ts-expect-error Type definition mismatch
utils.render(<IndexPage {...loggedOutProps} />);
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: {}
};

View File

@ -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 <Landing />;
type Challenge = {
id: string;
superBlock: SuperBlocks;
};
type Props = {
data: {
allChallengeNode: {
nodes: {
challenge: Challenge;
}[];
};
};
};
type LandingProps = {
allChallenges: Challenge[];
};
const LandingA = ({ allChallenges }: LandingProps) => (
<main className='landing-page'>
<LandingTop />
<AsSeenIn />
<Testimonials />
<Certifications allChallenges={allChallenges} />
<Faq />
</main>
);
const LandingB = ({ allChallenges }: LandingProps) => (
<main className='landing-page landing-page-b'>
<LandingTopB />
<Testimonials />
<Certifications allChallenges={allChallenges} />
<Faq />
</main>
);
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 (
<>
<SEO title={t('metaTags:title')} />
{showLandingPageRedesign === true ? (
<LandingB allChallenges={allChallenges} />
) : (
<LandingA allChallenges={allChallenges} />
)}
</>
);
} else {
return (
<>
<SEO title={t('metaTags:title')} />
<Loader fullScreen={true} />
</>
);
}
}
IndexPage.displayName = 'IndexPage';
export default IndexPage;
export const query = graphql`
query AllChallengeNode {
allChallengeNode {
nodes {
challenge {
id
superBlock
}
}
}
}
`;

View File

@ -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}
/>
<Map />
<Map allChallenges={challengeNodes.map(node => node.challenge)} />
<Spacer size='large' />
</Col>
</Row>
@ -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
}
}
}
}
`;

View File

@ -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`)}
</h3>
<Spacer size='medium' />
<Map />
<Map allChallenges={allChallenges} />
<Spacer size='large' />
</Col>
</Row>
@ -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 {

View File

@ -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
}
});
};