Files
freeCodeCamp/packages/learn/src/templates/Challenges/views/classic/Show.js

179 lines
4.4 KiB
JavaScript
Raw Normal View History

2018-04-06 14:51:52 +01:00
/* global graphql */
import React, { Fragment, PureComponent } from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { createSelector } from 'reselect';
import { connect } from 'react-redux';
import Helmet from 'react-helmet';
import { ReflexContainer, ReflexSplitter, ReflexElement } from 'react-reflex';
import Editor from './Editor';
import Preview from '../components/Preview';
import SidePanel from '../components/Side-Panel';
import CompletionModal from '../components/CompletionModal';
import { challengeTypes } from '../../../../../utils/challengeTypes';
import { ChallengeNode } from '../../../../redux/propTypes';
import {
createFiles,
challengeFilesSelector,
initTests,
updateChallengeMeta
} from '../../redux';
import './classic.css';
const mapStateToProps = createSelector(challengeFilesSelector, files => ({
files
}));
const mapDispatchToProps = dispatch =>
bindActionCreators({ createFiles, initTests, updateChallengeMeta }, dispatch);
const propTypes = {
createFiles: PropTypes.func.isRequired,
data: PropTypes.shape({
challengeNode: ChallengeNode
}),
files: PropTypes.shape({
key: PropTypes.string
}),
initTests: PropTypes.func.isRequired,
pathContext: PropTypes.shape({
challengeMeta: PropTypes.shape({
nextchallengePath: PropTypes.string
})
}),
updateChallengeMeta: PropTypes.func.isRequired
};
class ShowClassic extends PureComponent {
componentDidMount() {
const {
createFiles,
initTests,
updateChallengeMeta,
data: { challengeNode: { files, fields: { tests } } },
pathContext: { challengeMeta }
} = this.props;
createFiles(files);
initTests(tests);
updateChallengeMeta(challengeMeta);
}
2018-04-06 15:45:49 +01:00
componentDidUpdate(prevProps) {
const { data: { challengeNode: { title: prevTitle } } } = prevProps;
const {
createFiles,
initTests,
updateChallengeMeta,
data: {
challengeNode: { files, title: currentTitle, fields: { tests } }
},
pathContext: { challengeMeta }
} = this.props;
if (prevTitle !== currentTitle) {
createFiles(files);
initTests(tests);
updateChallengeMeta(challengeMeta);
}
}
2018-04-06 14:51:52 +01:00
render() {
const {
data: {
challengeNode: {
challengeType,
fields: { blockName },
title,
description,
guideUrl
}
},
files
} = this.props;
const editors = Object.keys(files)
.map(key => files[key])
.map((file, index) => (
<Fragment key={file.key + index}>
{index !== 0 && <ReflexSplitter />}
<ReflexElement flex={1}>
<Editor {...file} fileKey={file.key} />
</ReflexElement>
</Fragment>
));
const showPreview = challengeType === challengeTypes.html;
const blockNameTitle = `${blockName} - ${title}`;
return (
<Fragment>
<Helmet title={`${blockNameTitle} | Learn freeCodeCamp}`} />
<ReflexContainer orientation='vertical'>
<ReflexElement flex={1}>
<SidePanel
className='full-height'
description={description}
guideUrl={guideUrl}
title={blockNameTitle}
/>
</ReflexElement>
<ReflexSplitter />
<ReflexElement flex={1}>
<ReflexContainer orientation='horizontal'>
{editors}
</ReflexContainer>
</ReflexElement>
{showPreview && <ReflexSplitter />}
{showPreview && (
<ReflexElement flex={0.3} maxSize={325}>
<Preview className='full-height' />
</ReflexElement>
)}
</ReflexContainer>
<CompletionModal />
</Fragment>
);
}
}
ShowClassic.displayName = 'ShowClassic';
ShowClassic.propTypes = propTypes;
export default connect(mapStateToProps, mapDispatchToProps)(ShowClassic);
export const query = graphql`
query ClassicChallenge($slug: String!) {
challengeNode(fields: { slug: { eq: $slug } }) {
title
guideUrl
description
challengeType
fields {
blockName
tests {
text
testString
}
}
files {
indexhtml {
key
ext
name
contents
head
tail
}
indexjs {
key
ext
name
contents
head
tail
}
}
}
}
`;