feat: split rdbms into individual blocks and two challengeTypes (#44978)

* feat: split english rdbms into individual blocks

fix: stuff

fix: remove from partiallyComplete array on submit

fix: add suggestion

Update client/i18n/locales/english/translations.json

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/i18n/locales/english/intro.json

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/i18n/locales/english/intro.json

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/i18n/locales/english/intro.json

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Update client/src/templates/Challenges/codeally/show.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* fix: prettier

* fix: style suggestion

* Apply suggestions from code review

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Tom
2022-02-11 09:39:27 -06:00
committed by GitHub
parent 226a8248b7
commit 57cf47dad4
267 changed files with 3832 additions and 2229 deletions

View File

@@ -1,24 +1,68 @@
/* eslint-disable max-len */
// Package Utilities
import { Grid, Col, Row, Button } from '@freecodecamp/react-bootstrap';
import { graphql } from 'gatsby';
import React, { Component } from 'react';
import Helmet from 'react-helmet';
import { TFunction, Trans, withTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import type { Dispatch } from 'redux';
import { createSelector } from 'reselect';
// Local Utilities
import Spacer from '../../../components/helpers/spacer';
import LearnLayout from '../../../components/layouts/learn';
import { webhookTokenSelector } from '../../../redux';
import { ChallengeNode, ChallengeMeta } from '../../../redux/prop-types';
import { updateChallengeMeta, challengeMounted } from '../redux';
// Redux
import ChallengeTitle from '../components/challenge-title';
import PrismFormatted from '../components/prism-formatted';
import { challengeTypes } from '../../../../utils/challenge-types';
import CompletionModal from '../components/completion-modal';
import GreenPass from '../../../assets/icons/green-pass';
import HelpModal from '../components/help-modal';
import Hotkeys from '../components/Hotkeys';
import {
completedChallengesSelector,
isSignedInSelector,
partiallyCompletedChallengesSelector,
webhookTokenSelector
} from '../../../redux';
import {
challengeMounted,
isChallengeCompletedSelector,
updateChallengeMeta,
openModal,
updateSolutionFormValues
} from '../redux';
import { createFlashMessage } from '../../../components/Flash/redux';
import {
ChallengeNode,
ChallengeMeta,
CompletedChallenge
} from '../../../redux/prop-types';
import ProjectToolPanel from '../projects/tool-panel';
import SolutionForm from '../projects/solution-form';
import WebhookToken from '../../../components/settings/webhook-token';
import { FlashMessages } from '../../../components/Flash/redux/flash-messages';
import './codeally.css';
// Redux
const mapStateToProps = createSelector(
completedChallengesSelector,
isChallengeCompletedSelector,
isSignedInSelector,
partiallyCompletedChallengesSelector,
webhookTokenSelector,
(webhookToken: string | null) => ({
(
completedChallenges: CompletedChallenge[],
isChallengeCompleted: boolean,
isSignedIn: boolean,
partiallyCompletedChallenges: CompletedChallenge[],
webhookToken: string | null
) => ({
completedChallenges,
isChallengeCompleted,
isSignedIn,
partiallyCompletedChallenges,
webhookToken
})
);
@@ -26,28 +70,53 @@ const mapStateToProps = createSelector(
const mapDispatchToProps = (dispatch: Dispatch) =>
bindActionCreators(
{
challengeMounted,
createFlashMessage,
openCompletionModal: () => openModal('completion'),
updateChallengeMeta,
challengeMounted
updateSolutionFormValues
},
dispatch
);
// Types
interface ShowCodeAllyProps {
challengeMounted: (arg0: string) => void;
completedChallenges: CompletedChallenge[];
createFlashMessage: typeof createFlashMessage;
data: { challengeNode: ChallengeNode };
isChallengeCompleted: boolean;
isSignedIn: boolean;
openCompletionModal: () => void;
pageContext: {
challengeMeta: ChallengeMeta;
};
partiallyCompletedChallenges: CompletedChallenge[];
t: TFunction;
updateChallengeMeta: (arg0: ChallengeMeta) => void;
updateSolutionFormValues: () => void;
webhookToken: string | null;
}
interface ShowCodeAllyState {
showIframe: boolean;
}
// Component
class ShowCodeAlly extends Component<ShowCodeAllyProps> {
class ShowCodeAlly extends Component<ShowCodeAllyProps, ShowCodeAllyState> {
static displayName: string;
private _container: HTMLElement | null = null;
constructor(props: ShowCodeAllyProps) {
super(props);
this.state = {
showIframe: false
};
}
componentDidMount(): void {
const {
updateChallengeMeta,
challengeMounted,
data: {
challengeNode: {
challenge: { challengeType, title }
@@ -56,27 +125,96 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
pageContext: { challengeMeta }
} = this.props;
updateChallengeMeta({ ...challengeMeta, title, challengeType });
challengeMounted(challengeMeta.id);
this._container?.focus();
}
showIframe = () => {
this.setState({
showIframe: true
});
};
handleSubmit = ({
showCompletionModal
}: {
showCompletionModal: boolean;
}) => {
const {
completedChallenges,
createFlashMessage,
data: {
challengeNode: {
challenge: { id: challengeId }
}
},
partiallyCompletedChallenges
} = this.props;
const isPartiallyCompleted = partiallyCompletedChallenges.some(
challenge => challenge.id === challengeId
);
const isCompleted = completedChallenges.some(
challenge => challenge.id === challengeId
);
if (!isPartiallyCompleted && !isCompleted) {
createFlashMessage({
type: 'danger',
message: FlashMessages.CompleteProjectFirst
});
} else if (showCompletionModal) {
this.props.openCompletionModal();
}
};
render() {
const {
completedChallenges,
data: {
challengeNode: {
challenge: {
title,
block,
certification,
challengeType,
description,
fields: { blockName },
id: challengeId,
instructions,
notes,
superBlock,
title,
translationPending,
url
}
}
},
isChallengeCompleted,
isSignedIn,
pageContext: {
challengeMeta: { nextChallengePath, prevChallengePath }
},
partiallyCompletedChallenges,
t,
updateSolutionFormValues,
webhookToken = null
} = this.props;
const { showIframe } = this.state;
const envVariables = webhookToken
? `&envVariables=CODEROAD_WEBHOOK_TOKEN=${webhookToken}`
: '';
return (
const isPartiallyCompleted = partiallyCompletedChallenges.some(
challenge => challenge.id === challengeId
);
const isCompleted = completedChallenges.some(
challenge => challenge.id === challengeId
);
return showIframe ? (
<LearnLayout>
<Helmet title={`${blockName}: ${title} | freeCodeCamp.org`} />
<iframe
@@ -87,25 +225,162 @@ class ShowCodeAlly extends Component<ShowCodeAllyProps> {
title='Editor'
/>
</LearnLayout>
) : (
<Hotkeys
innerRef={(c: HTMLElement | null) => (this._container = c)}
nextChallengePath={nextChallengePath}
prevChallengePath={prevChallengePath}
>
<LearnLayout>
<Helmet title={`${blockName}: ${title} | freeCodeCamp.org`} />
<Grid>
<Row>
<Col md={8} mdOffset={2} sm={10} smOffset={1} xs={12}>
<Spacer />
<ChallengeTitle
block={block}
isCompleted={isChallengeCompleted}
superBlock={superBlock}
translationPending={translationPending}
>
{title}
</ChallengeTitle>
<Spacer />
{isSignedIn && <WebhookToken isChallengePage={true} />}
<PrismFormatted text={description} />
<Spacer />
<div className='ca-description'>
<Trans i18nKey='learn.github-required'>
<a
href='https://github.com'
rel='noopener noreferrer'
target='_blank'
title={t('learn.github-link')}
>
placeholder
</a>
</Trans>
</div>
<Spacer />
{isSignedIn && challengeType === challengeTypes.codeAllyCert && (
<>
<div className='ca-description'>
{t('learn.complete-both-steps')}
</div>
<hr />
<Spacer />
<b>{t('learn.step-1')}</b>
{(isPartiallyCompleted || isCompleted) && (
<GreenPass
style={{
height: '15px',
width: '15px',
marginLeft: '7px'
}}
/>
)}
<Spacer />
<div className='ca-description'>
{t('learn.runs-in-vm')}
</div>
<Spacer />
<PrismFormatted text={instructions} />
<Spacer />
</>
)}
<div
className={`ca-btn-padding ${
!isSignedIn ||
challengeType === challengeTypes.codeAllyPractice
? 'ca-btn-margin'
: ''
}`}
>
<Button
block={true}
bsStyle='primary'
onClick={this.showIframe}
>
{challengeType === challengeTypes.codeAllyCert
? t('buttons.click-start-project')
: t('buttons.click-start-course')}
</Button>
</div>
{isSignedIn && challengeType === challengeTypes.codeAllyCert && (
<>
<hr />
<Spacer />
<b>{t('learn.step-2')}</b>
{isCompleted && (
<GreenPass
style={{
height: '15px',
width: '15px',
marginLeft: '7px'
}}
/>
)}
<Spacer />
<div className='ca-description'>
{t('learn.submit-public-url')}
</div>
<Spacer />
<PrismFormatted text={notes} />
<Spacer />
<SolutionForm
challengeType={challengeType}
description={description}
onSubmit={this.handleSubmit}
updateSolutionForm={updateSolutionFormValues}
/>
</>
)}
<ProjectToolPanel />
<br />
<Spacer />
</Col>
<CompletionModal
block={block}
blockName={blockName}
certification={certification}
superBlock={superBlock}
/>
<HelpModal />
</Row>
</Grid>
</LearnLayout>
</Hotkeys>
);
}
}
ShowCodeAlly.displayName = 'ShowCodeAlly';
export default connect(mapStateToProps, mapDispatchToProps)(ShowCodeAlly);
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation()(ShowCodeAlly));
// GraphQL
export const query = graphql`
query CodeAllyChallenge($slug: String!) {
challengeNode(challenge: { fields: { slug: { eq: $slug } } }) {
challenge {
title
block
certification
challengeType
url
description
fields {
blockName
}
helpCategory
id
instructions
notes
superBlock
title
translationPending
url
}
}
}