Files
freeCodeCamp/client/src/templates/Challenges/backend/Show.js

265 lines
6.5 KiB
JavaScript
Raw Normal View History

import React, { Component } from 'react';
import PropTypes from 'prop-types';
2019-01-12 17:41:41 +03:00
import { Grid, Col, Row } from '@freecodecamp/react-bootstrap';
import { createSelector } from 'reselect';
import { connect } from 'react-redux';
2018-09-11 16:10:21 +03:00
import { graphql } from 'gatsby';
import {
executeChallenge,
challengeMounted,
challengeTestsSelector,
consoleOutputSelector,
initConsole,
initTests,
updateBackendFormValues,
updateChallengeMeta,
updateProjectFormValues,
backendNS
} from '../redux';
import { createGuideUrl } from '../utils';
import LearnLayout from '../../../components/layouts/Learn';
import ChallengeTitle from '../components/Challenge-Title';
import ChallengeDescription from '../components/Challenge-Description';
import TestSuite from '../components/Test-Suite';
import Output from '../components/Output';
import CompletionModal from '../components/CompletionModal';
import HelpModal from '../components/HelpModal';
import ProjectToolPanel from '../project/Tool-Panel';
import ProjectForm from '../project/ProjectForm';
import { Form } from '../../../components/formHelpers';
import Spacer from '../../../components/helpers/Spacer';
import { ChallengeNode } from '../../../redux/propTypes';
import { isSignedInSelector } from '../../../redux';
import { backend } from '../../../../utils/challengeTypes';
2018-09-21 08:33:19 +03:00
import '../components/test-frame.css';
const propTypes = {
challengeMounted: PropTypes.func.isRequired,
data: PropTypes.shape({
challengeNode: ChallengeNode
}),
description: PropTypes.string,
executeChallenge: PropTypes.func.isRequired,
id: PropTypes.string,
initConsole: PropTypes.func.isRequired,
initTests: PropTypes.func.isRequired,
isSignedIn: PropTypes.bool,
output: PropTypes.string,
pageContext: PropTypes.shape({
challengeMeta: PropTypes.object
}),
tests: PropTypes.array,
title: PropTypes.string,
updateBackendFormValues: PropTypes.func.isRequired,
updateChallengeMeta: PropTypes.func.isRequired,
updateProjectFormValues: PropTypes.func.isRequired
};
const mapStateToProps = createSelector(
consoleOutputSelector,
challengeTestsSelector,
isSignedInSelector,
(output, tests, isSignedIn) => ({
tests,
output,
isSignedIn
})
);
const mapDispatchToActions = {
challengeMounted,
executeChallenge,
initConsole,
initTests,
updateBackendFormValues,
updateChallengeMeta,
updateProjectFormValues
};
const formFields = ['solution'];
const options = {
required: ['solution'],
types: {
solution: 'url'
}
};
export class BackEnd extends Component {
2019-01-12 17:41:41 +03:00
constructor(props) {
super(props);
this.state = {};
this.updateDimensions = this.updateDimensions.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
2019-01-12 17:41:41 +03:00
}
componentDidMount() {
this.initializeComponent();
2019-01-12 17:41:41 +03:00
window.addEventListener('resize', this.updateDimensions);
}
updateDimensions() {
this.setState({ width: window.innerWidth, height: window.innerHeight });
}
componentWillUnmount() {
window.removeEventListener('resize', this.updateDimensions);
}
componentDidUpdate(prevProps) {
const {
data: {
challengeNode: { title: prevTitle }
}
} = prevProps;
const {
data: {
challengeNode: { title: currentTitle }
}
} = this.props;
if (prevTitle !== currentTitle) {
this.initializeComponent();
}
}
initializeComponent() {
const {
challengeMounted,
initConsole,
initTests,
updateChallengeMeta,
data: {
challengeNode: {
fields: { tests },
challengeType
}
},
2018-09-11 16:19:11 +03:00
pageContext: { challengeMeta }
} = this.props;
initConsole('');
initTests(tests);
updateChallengeMeta({ ...challengeMeta, challengeType });
challengeMounted(challengeMeta.id);
}
handleSubmit(values) {
const { updateBackendFormValues, executeChallenge } = this.props;
updateBackendFormValues(values);
executeChallenge();
}
render() {
const {
data: {
challengeNode: {
fields: { blockName, slug },
challengeType,
title,
description,
instructions
}
},
output,
pageContext: {
challengeMeta: { introPath, nextChallengePath, prevChallengePath }
},
tests,
isSignedIn,
executeChallenge,
updateProjectFormValues
} = this.props;
const buttonCopy = isSignedIn
? 'Submit and go to my next challenge'
: "I've completed this challenge";
const blockNameTitle = `${blockName} - ${title}`;
return (
<LearnLayout>
2019-01-12 17:41:41 +03:00
<Grid>
<Row>
<Col md={8} mdOffset={2} sm={10} smOffset={1} xs={12}>
2019-01-12 17:41:41 +03:00
<Spacer />
<ChallengeTitle
introPath={introPath}
nextChallengePath={nextChallengePath}
prevChallengePath={prevChallengePath}
showPrevNextBtns={true}
>
{blockNameTitle}
</ChallengeTitle>
2019-02-15 17:52:45 +03:00
<ChallengeDescription
description={description}
instructions={instructions}
/>
{challengeType === backend ? (
<Form
buttonText={`${buttonCopy}`}
formFields={formFields}
id={backendNS}
options={options}
submit={this.handleSubmit}
/>
) : (
<ProjectForm
isFrontEnd={false}
onSubmit={executeChallenge}
updateProjectForm={updateProjectFormValues}
/>
)}
2019-02-15 17:52:45 +03:00
<ProjectToolPanel guideUrl={createGuideUrl(slug)} />
<br />
<Output
defaultOutput={`/**
*
* Test output will go here
*
*
*/`}
dimensions={this.state}
height={150}
output={output}
/>
<TestSuite tests={tests} />
2019-01-12 17:41:41 +03:00
<Spacer />
</Col>
<CompletionModal />
<HelpModal />
</Row>
</Grid>
</LearnLayout>
);
}
}
BackEnd.displayName = 'BackEnd';
BackEnd.propTypes = propTypes;
export default connect(
mapStateToProps,
mapDispatchToActions
)(BackEnd);
export const query = graphql`
query BackendChallenge($slug: String!) {
challengeNode(fields: { slug: { eq: $slug } }) {
title
description
instructions
challengeType
fields {
blockName
slug
tests {
text
testString
}
}
}
}
`;