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:
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user