Files
freeCodeCamp/common/app/routes/challenges/Show.jsx

154 lines
3.7 KiB
JavaScript
Raw Normal View History

import React, { PropTypes } from 'react';
import { compose } from 'redux';
import { contain } from 'redux-epic';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
2016-03-05 21:06:04 -08:00
import PureComponent from 'react-pure-render/component';
import Classic from './views/classic';
import Step from './views/step';
import Project from './views/project';
import Video from './views/video';
import BackEnd from './views/backend';
2016-06-03 18:37:53 -07:00
import {
fetchChallenge,
fetchChallenges,
replaceChallenge,
resetUi
} from './redux/actions';
import { challengeSelector } from './redux/selectors';
import { updateTitle } from '../../redux/actions';
import { makeToast } from '../../toasts/redux/actions';
2016-06-03 14:12:56 -07:00
const views = {
backend: BackEnd,
2016-06-03 18:37:53 -07:00
classic: Classic,
2016-06-07 20:41:42 -07:00
project: Project,
simple: Project,
step: Step,
video: Video
2016-06-03 14:12:56 -07:00
};
const mapDispatchToProps = {
2016-06-01 15:52:08 -07:00
fetchChallenge,
fetchChallenges,
2016-11-06 10:41:37 +00:00
makeToast,
replaceChallenge,
resetUi,
updateTitle
};
const mapStateToProps = createSelector(
challengeSelector,
2016-05-10 13:17:57 -07:00
state => state.challengesApp.challenge,
state => state.challengesApp.superBlocks,
2016-11-06 10:41:37 +00:00
state => state.app.lang,
(
{
2016-10-29 00:46:45 +01:00
challenge: { isTranslated } = {},
viewType,
title
2016-11-06 10:41:37 +00:00
},
challenge,
superBlocks = [],
lang
) => ({
lang,
isTranslated,
title,
2016-06-03 14:12:56 -07:00
challenge,
viewType,
areChallengesLoaded: superBlocks.length > 0
2016-06-03 14:12:56 -07:00
})
);
const fetchOptions = {
fetchAction: 'fetchChallenge',
2016-06-09 16:02:51 -07:00
getActionArgs({ params: { block, dashedName } }) {
return [ dashedName, block ];
},
isPrimed({ challenge }) {
2016-05-10 13:17:57 -07:00
return !!challenge;
}
};
2016-11-06 10:41:37 +00:00
const link = 'http://forum.freecodecamp.com/t/' +
'guidelines-for-translating-free-code-camp' +
'-to-any-language/19111';
2017-01-12 06:54:43 +00:00
const propTypes = {
areChallengesLoaded: PropTypes.bool,
fetchChallenges: PropTypes.func.isRequired,
isStep: PropTypes.bool,
isTranslated: PropTypes.bool,
lang: PropTypes.string.isRequired,
makeToast: PropTypes.func.isRequired,
params: PropTypes.object.isRequired,
replaceChallenge: PropTypes.func.isRequired,
resetUi: PropTypes.func.isRequired,
title: PropTypes.string,
updateTitle: PropTypes.func.isRequired,
viewType: PropTypes.string
2017-01-12 06:54:43 +00:00
};
export class Show extends PureComponent {
2016-03-05 21:06:04 -08:00
componentWillMount() {
2016-10-29 00:46:45 +01:00
const { lang, isTranslated, makeToast } = this.props;
2016-11-06 10:41:37 +00:00
if (lang !== 'en' && !isTranslated) {
makeToast({
message: 'We haven\'t translated this challenge yet.',
action: <a href={ link } target='_blank'>Help Us</a>,
timeout: 15000
});
}
}
2016-06-01 15:52:08 -07:00
componentDidMount() {
if (!this.props.areChallengesLoaded) {
this.props.fetchChallenges();
}
2016-10-29 00:46:45 +01:00
if (this.props.title) {
this.props.updateTitle(this.props.title);
}
2016-06-01 15:52:08 -07:00
}
componentWillUnmount() {
this.props.resetUi();
}
componentWillReceiveProps(nextProps) {
2016-10-29 00:46:45 +01:00
const { title } = nextProps;
const { block, dashedName } = nextProps.params;
2016-11-06 10:41:37 +00:00
const { lang, isTranslated } = nextProps;
const { resetUi, updateTitle, replaceChallenge, makeToast } = this.props;
if (this.props.params.dashedName !== dashedName) {
2016-10-29 00:46:45 +01:00
updateTitle(title);
resetUi();
replaceChallenge({ dashedName, block });
2016-11-06 10:41:37 +00:00
if (lang !== 'en' && !isTranslated) {
makeToast({
message: 'We haven\'t translated this challenge yet.',
action: <a href={ link } target='_blank'>Help Us</a>,
timeout: 15000
});
}
}
}
2016-06-01 15:52:08 -07:00
render() {
2016-06-03 14:12:56 -07:00
const { viewType } = this.props;
const View = views[viewType] || Classic;
return <View />;
2016-06-01 15:52:08 -07:00
}
2016-03-05 21:06:04 -08:00
}
Show.displayName = 'Show(ChallengeView)';
Show.propTypes = propTypes;
2017-01-12 06:54:43 +00:00
export default compose(
connect(mapStateToProps, mapDispatchToProps),
contain(fetchOptions)
)(Show);