Merge pull request #12497 from Bouncey/fix/update-eslint-plugin-react

Enable react/sort-prop-types rule
This commit is contained in:
Berkeley Martinez
2017-02-27 14:00:38 -08:00
committed by GitHub
33 changed files with 322 additions and 273 deletions

View File

@ -189,6 +189,7 @@
"react/prop-types": 2, "react/prop-types": 2,
"react/react-in-jsx-scope": 2, "react/react-in-jsx-scope": 2,
"react/self-closing-comp": 2, "react/self-closing-comp": 2,
"react/sort-prop-types": 2,
"import/default": 2, "import/default": 2,
"import/export": 2, "import/export": 2,

View File

@ -56,23 +56,23 @@ const mapStateToProps = createSelector(
const propTypes = { const propTypes = {
children: PropTypes.node, children: PropTypes.node,
username: PropTypes.string, closeDropdown: PropTypes.func.isRequired,
isSignedIn: PropTypes.bool,
points: PropTypes.number,
picture: PropTypes.string,
toast: PropTypes.object,
updateNavHeight: PropTypes.func,
initWindowHeight: PropTypes.func,
submitChallenge: PropTypes.func,
fetchUser: PropTypes.func, fetchUser: PropTypes.func,
showLoading: PropTypes.bool, initWindowHeight: PropTypes.func,
params: PropTypes.object, isNavDropdownOpen: PropTypes.bool,
updateAppLang: PropTypes.func.isRequired, isSignedIn: PropTypes.bool,
trackEvent: PropTypes.func.isRequired,
loadCurrentChallenge: PropTypes.func.isRequired, loadCurrentChallenge: PropTypes.func.isRequired,
openDropdown: PropTypes.func.isRequired, openDropdown: PropTypes.func.isRequired,
closeDropdown: PropTypes.func.isRequired, params: PropTypes.object,
isNavDropdownOpen: PropTypes.bool picture: PropTypes.string,
points: PropTypes.number,
showLoading: PropTypes.bool,
submitChallenge: PropTypes.func,
toast: PropTypes.object,
trackEvent: PropTypes.func.isRequired,
updateAppLang: PropTypes.func.isRequired,
updateNavHeight: PropTypes.func,
username: PropTypes.string
}; };
// export plain class for testing // export plain class for testing

View File

@ -3,6 +3,13 @@ import { Link } from 'react-router';
// this is separated out to prevent react bootstrap's // this is separated out to prevent react bootstrap's
// NavBar from injecting unknown props to the li component // NavBar from injecting unknown props to the li component
const propTypes = {
picture: PropTypes.string,
points: PropTypes.number,
username: PropTypes.string
};
export default function AvatarPointsNavItem({ picture, points, username }) { export default function AvatarPointsNavItem({ picture, points, username }) {
return ( return (
<li <li
@ -25,8 +32,5 @@ export default function AvatarPointsNavItem({ picture, points, username }) {
); );
} }
AvatarPointsNavItem.propTypes = { AvatarPointsNavItem.displayName = 'AvatarPointsNavItem';
username: PropTypes.string, AvatarPointsNavItem.propTypes = propTypes;
picture: PropTypes.string,
points: PropTypes.number
};

View File

@ -2,13 +2,13 @@ import React, { PropTypes } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { hardGoTo } from '../../redux/actions'; import { hardGoTo } from '../../redux/actions';
export class NotFound extends React.Component { const propTypes = {
static displayName = 'NotFound'; hardGoTo: PropTypes.func,
location: PropTypes.object
};
export class NotFound extends React.Component {
static propTypes = {
location: PropTypes.object,
hardGoTo: PropTypes.func
};
componentWillMount() { componentWillMount() {
this.props.hardGoTo(this.props.location.pathname); this.props.hardGoTo(this.props.location.pathname);
@ -19,4 +19,7 @@ export class NotFound extends React.Component {
} }
} }
NotFound.displayName = 'NotFound';
NotFound.propTypes = propTypes;
export default connect(null, { hardGoTo })(NotFound); export default connect(null, { hardGoTo })(NotFound);

View File

@ -8,13 +8,14 @@ const mapStateToProps = state => ({ isOpen: state.challengesApp.isBugOpen });
const actions = { createIssue, openIssueSearch, closeBugModal }; const actions = { createIssue, openIssueSearch, closeBugModal };
const bugLink = 'http://forum.freecodecamp.com/t/how-to-report-a-bug/19543'; const bugLink = 'http://forum.freecodecamp.com/t/how-to-report-a-bug/19543';
export class BugModal extends PureComponent { const propTypes = {
static propTypes = {
isOpen: PropTypes.bool,
closeBugModal: PropTypes.func, closeBugModal: PropTypes.func,
openIssueSearch: PropTypes.func, createIssue: PropTypes.func,
createIssue: PropTypes.func isOpen: PropTypes.bool,
}; openIssueSearch: PropTypes.func
};
export class BugModal extends PureComponent {
render() { render() {
const { const {
@ -81,4 +82,7 @@ export class BugModal extends PureComponent {
} }
} }
BugModal.displayName = 'BugModal';
BugModal.propTypes = propTypes;
export default connect(mapStateToProps, actions)(BugModal); export default connect(mapStateToProps, actions)(BugModal);

View File

@ -12,6 +12,11 @@ const defaultOptions = {
lineWrapping: true lineWrapping: true
}; };
const propTypes = {
defaultOutput: PropTypes.string,
output: PropTypes.string
};
export default class Output extends PureComponent { export default class Output extends PureComponent {
render() { render() {
const { output, defaultOutput } = this.props; const { output, defaultOutput } = this.props;
@ -29,7 +34,4 @@ export default class Output extends PureComponent {
} }
Output.displayName = 'Output'; Output.displayName = 'Output';
Output.propTypes = { Output.propTypes = propTypes;
output: PropTypes.string,
defaultOutput: PropTypes.string
};

View File

@ -77,24 +77,23 @@ const link = 'http://forum.freecodecamp.com/t/' +
'guidelines-for-translating-free-code-camp' + 'guidelines-for-translating-free-code-camp' +
'-to-any-language/19111'; '-to-any-language/19111';
export class Challenges extends PureComponent { const propTypes = {
static displayName = 'Challenges';
static propTypes = {
title: PropTypes.string,
viewType: PropTypes.string,
isStep: PropTypes.bool,
fetchChallenges: PropTypes.func.isRequired,
replaceChallenge: PropTypes.func.isRequired,
params: PropTypes.object.isRequired,
areChallengesLoaded: PropTypes.bool, areChallengesLoaded: PropTypes.bool,
resetUi: PropTypes.func.isRequired, fetchChallenges: PropTypes.func.isRequired,
updateTitle: PropTypes.func.isRequired, isStep: PropTypes.bool,
makeToast: PropTypes.func.isRequired, isTranslated: PropTypes.bool,
lang: PropTypes.string.isRequired, lang: PropTypes.string.isRequired,
isTranslated: PropTypes.bool 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
}; };
export class Challenges extends PureComponent {
componentWillMount() { componentWillMount() {
const { lang, isTranslated, makeToast } = this.props; const { lang, isTranslated, makeToast } = this.props;
if (lang !== 'en' && !isTranslated) { if (lang !== 'en' && !isTranslated) {
@ -153,6 +152,9 @@ export class Challenges extends PureComponent {
} }
} }
Challenges.displayName = 'Challenges';
Challenges.propTypes = propTypes;
export default compose( export default compose(
connect(mapStateToProps, bindableActions), connect(mapStateToProps, bindableActions),
contain(fetchOptions) contain(fetchOptions)

View File

@ -2,6 +2,11 @@ import React, { PropTypes } from 'react';
import { HelpBlock, FormGroup, FormControl } from 'react-bootstrap'; import { HelpBlock, FormGroup, FormControl } from 'react-bootstrap';
import { getValidationState, DOMOnlyProps } from '../../../utils/form'; import { getValidationState, DOMOnlyProps } from '../../../utils/form';
const propTypes = {
placeholder: PropTypes.string,
solution: PropTypes.object
};
export default function SolutionInput({ solution, placeholder }) { export default function SolutionInput({ solution, placeholder }) {
const validationState = getValidationState(solution); const validationState = getValidationState(solution);
return ( return (
@ -24,7 +29,5 @@ export default function SolutionInput({ solution, placeholder }) {
); );
} }
SolutionInput.propTypes = { SolutionInput.displayName = 'SolutionInput';
solution: PropTypes.object, SolutionInput.propTypes = propTypes;
placeholder: PropTypes.string
};

View File

@ -19,19 +19,23 @@ import {
createFormValidator createFormValidator
} from '../../../../utils/form.js'; } from '../../../../utils/form.js';
const propTypes = { // provided by redux form
id: PropTypes.string, const reduxFormPropTypes = {
title: PropTypes.string,
description: PropTypes.arrayOf(PropTypes.string),
tests: PropTypes.array,
output: PropTypes.string,
executeChallenge: PropTypes.func.isRequired,
submitChallenge: PropTypes.func.isRequired,
// provided by redux form
submitting: PropTypes.bool,
fields: PropTypes.object, fields: PropTypes.object,
handleSubmit: PropTypes.func.isRequired,
resetForm: PropTypes.func.isRequired, resetForm: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired submitting: PropTypes.bool
};
const propTypes = {
description: PropTypes.arrayOf(PropTypes.string),
executeChallenge: PropTypes.func.isRequired,
id: PropTypes.string,
output: PropTypes.string,
submitChallenge: PropTypes.func.isRequired,
tests: PropTypes.array,
title: PropTypes.string,
...reduxFormPropTypes
}; };
const fields = [ 'solution' ]; const fields = [ 'solution' ];

View File

@ -57,24 +57,23 @@ const bindableActions = {
updateSuccessMessage updateSuccessMessage
}; };
export class Challenge extends PureComponent { const propTypes = {
static displayName = 'Challenge';
static propTypes = {
id: PropTypes.string,
showPreview: PropTypes.bool,
content: PropTypes.string,
mode: PropTypes.string,
file: PropTypes.object,
updateFile: PropTypes.func,
executeChallenge: PropTypes.func,
loadCode: PropTypes.func,
submitChallenge: PropTypes.func,
isChallengeModalOpen: PropTypes.bool,
closeChallengeModal: PropTypes.func, closeChallengeModal: PropTypes.func,
content: PropTypes.string,
executeChallenge: PropTypes.func,
file: PropTypes.object,
id: PropTypes.string,
isChallengeModalOpen: PropTypes.bool,
loadCode: PropTypes.func,
mode: PropTypes.string,
showPreview: PropTypes.bool,
submitChallenge: PropTypes.func,
successMessage: PropTypes.string, successMessage: PropTypes.string,
updateFile: PropTypes.func,
updateSuccessMessage: PropTypes.func updateSuccessMessage: PropTypes.func
}; };
export class Challenge extends PureComponent {
componentDidMount() { componentDidMount() {
this.props.loadCode(); this.props.loadCode();
@ -148,4 +147,7 @@ export class Challenge extends PureComponent {
} }
} }
Challenge.displayName = 'Challenge';
Challenge.propTypes = propTypes;
export default connect(mapStateToProps, bindableActions)(Challenge); export default connect(mapStateToProps, bindableActions)(Challenge);

View File

@ -32,25 +32,25 @@ const options = {
gutters: ['CodeMirror-lint-markers'] gutters: ['CodeMirror-lint-markers']
}; };
const defaultProps = {
content: '// Happy Coding!',
mode: 'javascript'
};
const propTypes = {
content: PropTypes.string,
executeChallenge: PropTypes.func,
height: PropTypes.number,
mode: PropTypes.string,
updateFile: PropTypes.func
};
export class Editor extends PureComponent { export class Editor extends PureComponent {
constructor(...args) { constructor(...args) {
super(...args); super(...args);
this._editorContent$ = new Subject(); this._editorContent$ = new Subject();
this.handleChange = this.handleChange.bind(this); this.handleChange = this.handleChange.bind(this);
} }
static displayName = 'Editor';
static propTypes = {
executeChallenge: PropTypes.func,
height: PropTypes.number,
content: PropTypes.string,
mode: PropTypes.string,
updateFile: PropTypes.func
};
static defaultProps = {
content: '// Happy Coding!',
mode: 'javascript'
};
createOptions = createSelector( createOptions = createSelector(
state => state.options, state => state.options,
@ -148,4 +148,9 @@ export class Editor extends PureComponent {
} }
} }
Editor.defaultProps = defaultProps;
Editor.displayName = 'Editor';
Editor.propTypes = propTypes;
export default connect(mapStateToProps)(Editor); export default connect(mapStateToProps)(Editor);

View File

@ -2,9 +2,8 @@ import React from 'react';
import PureComponent from 'react-pure-render/component'; import PureComponent from 'react-pure-render/component';
const mainId = 'fcc-main-frame'; const mainId = 'fcc-main-frame';
export default class extends PureComponent {
static displayName = 'Preview';
export default class Preview extends PureComponent {
render() { render() {
return ( return (
<div <div
@ -25,3 +24,5 @@ export default class extends PureComponent {
); );
} }
} }
Preview.displayName = 'Preview';

View File

@ -60,26 +60,23 @@ const mapStateToProps = createSelector(
helpChatRoom helpChatRoom
}) })
); );
const propTypes = {
export class SidePanel extends PureComponent {
static displayName = 'SidePanel';
static propTypes = {
description: PropTypes.arrayOf(PropTypes.string), description: PropTypes.arrayOf(PropTypes.string),
executeChallenge: PropTypes.func,
height: PropTypes.number, height: PropTypes.number,
helpChatRoom: PropTypes.string, helpChatRoom: PropTypes.string,
hint: PropTypes.string, hint: PropTypes.string,
isCodeLocked: PropTypes.bool, isCodeLocked: PropTypes.bool,
makeToast: PropTypes.func,
openBugModal: PropTypes.func,
output: PropTypes.string, output: PropTypes.string,
tests: PropTypes.arrayOf(PropTypes.object), tests: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string, title: PropTypes.string,
executeChallenge: PropTypes.func,
openBugModal: PropTypes.func,
makeToast: PropTypes.func,
unlockUntrustedCode: PropTypes.func, unlockUntrustedCode: PropTypes.func,
updateHint: PropTypes.func updateHint: PropTypes.func
}; };
export class SidePanel extends PureComponent {
renderDescription(description = [ 'Happy Coding!' ]) { renderDescription(description = [ 'Happy Coding!' ]) {
return description.map((line, index) => { return description.map((line, index) => {
@ -174,6 +171,9 @@ export class SidePanel extends PureComponent {
} }
} }
SidePanel.displayName = 'SidePanel';
SidePanel.propTypes = propTypes;
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps

View File

@ -29,22 +29,21 @@ const makeMapStateToProps = () => createSelector(
}; };
} }
); );
const propTypes = {
challenges: PropTypes.array,
dashedName: PropTypes.string,
isHidden: PropTypes.bool,
isOpen: PropTypes.bool,
time: PropTypes.string,
title: PropTypes.string,
toggleThisPanel: PropTypes.func
};
export class Block extends PureComponent { export class Block extends PureComponent {
constructor(...props) { constructor(...props) {
super(...props); super(...props);
this.handleSelect = this.handleSelect.bind(this); this.handleSelect = this.handleSelect.bind(this);
} }
static displayName = 'Block';
static propTypes = {
title: PropTypes.string,
dashedName: PropTypes.string,
time: PropTypes.string,
isOpen: PropTypes.bool,
isHidden: PropTypes.bool,
challenges: PropTypes.array,
toggleThisPanel: PropTypes.func
};
handleSelect(eventKey, e) { handleSelect(eventKey, e) {
e.preventDefault(); e.preventDefault();
this.props.toggleThisPanel(eventKey); this.props.toggleThisPanel(eventKey);
@ -108,4 +107,7 @@ export class Block extends PureComponent {
} }
} }
Block.displayName = 'Block';
Block.propTypes = propTypes;
export default connect(makeMapStateToProps, dispatchActions)(Block); export default connect(makeMapStateToProps, dispatchActions)(Block);

View File

@ -23,21 +23,21 @@ const mapStateToProps = state => ({
isAllCollapsed: state.challengesApp.mapUi.isAllCollapsed, isAllCollapsed: state.challengesApp.mapUi.isAllCollapsed,
filter: state.challengesApp.filter filter: state.challengesApp.filter
}); });
const propTypes = {
clearFilter: PropTypes.func,
collapseAll: PropTypes.func,
expandAll: PropTypes.func,
filter: PropTypes.string,
isAllCollapsed: PropTypes.bool,
updateFilter: PropTypes.func
};
export class Header extends PureComponent { export class Header extends PureComponent {
constructor(...props) { constructor(...props) {
super(...props); super(...props);
this.handleKeyDown = this.handleKeyDown.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleClearButton = this.handleClearButton.bind(this); this.handleClearButton = this.handleClearButton.bind(this);
} }
static displayName = 'MapHeader';
static propTypes = {
isAllCollapsed: PropTypes.bool,
filter: PropTypes.string,
clearFilter: PropTypes.func,
updateFilter: PropTypes.func,
collapseAll: PropTypes.func,
expandAll: PropTypes.func
};
handleKeyDown(e) { handleKeyDown(e) {
if (e.keyCode === ESC) { if (e.keyCode === ESC) {
@ -116,4 +116,8 @@ export class Header extends PureComponent {
); );
} }
} }
Header.displayName = 'MapHeader';
Header.propTypes = propTypes;
export default connect(mapStateToProps, bindableActions)(Header); export default connect(mapStateToProps, bindableActions)(Header);

View File

@ -27,16 +27,15 @@ const fetchOptions = {
return Array.isArray(superBlocks) && superBlocks.length > 1; return Array.isArray(superBlocks) && superBlocks.length > 1;
} }
}; };
export class ShowMap extends PureComponent { const propTypes = {
static displayName = 'Map'; fetchChallenges: PropTypes.func.isRequired,
static propTypes = {
superBlocks: PropTypes.array,
height: PropTypes.number, height: PropTypes.number,
updateTitle: PropTypes.func.isRequired,
params: PropTypes.object, params: PropTypes.object,
fetchChallenges: PropTypes.func.isRequired superBlocks: PropTypes.array,
}; updateTitle: PropTypes.func.isRequired
};
export class ShowMap extends PureComponent {
componentWillMount() { componentWillMount() {
// if no params then map is open in drawer // if no params then map is open in drawer
// do not update title // do not update title
@ -81,6 +80,9 @@ export class ShowMap extends PureComponent {
} }
} }
ShowMap.displayName = 'Map';
ShowMap.propTypes = propTypes;
export default compose( export default compose(
connect(mapStateToProps, bindableActions), connect(mapStateToProps, bindableActions),
contain(fetchOptions) contain(fetchOptions)

View File

@ -36,22 +36,21 @@ const makeMapStateToProps = () => {
); );
}; };
const propTypes = {
blocks: PropTypes.array,
dashedName: PropTypes.string,
isHidden: PropTypes.bool,
isOpen: PropTypes.bool,
message: PropTypes.string,
title: PropTypes.string,
toggleThisPanel: PropTypes.func
};
export class SuperBlock extends PureComponent { export class SuperBlock extends PureComponent {
constructor(...props) { constructor(...props) {
super(...props); super(...props);
this.handleSelect = this.handleSelect.bind(this); this.handleSelect = this.handleSelect.bind(this);
} }
static displayName = 'SuperBlock';
static propTypes = {
title: PropTypes.string,
dashedName: PropTypes.string,
blocks: PropTypes.array,
isOpen: PropTypes.bool,
isHidden: PropTypes.bool,
message: PropTypes.string,
toggleThisPanel: PropTypes.func
};
handleSelect(eventKey, e) { handleSelect(eventKey, e) {
e.preventDefault(); e.preventDefault();
this.props.toggleThisPanel(eventKey); this.props.toggleThisPanel(eventKey);
@ -126,6 +125,9 @@ export class SuperBlock extends PureComponent {
} }
} }
SuperBlock.displayName = 'SuperBlock';
SuperBlock.propTypes = propTypes;
export default connect( export default connect(
makeMapStateToProps, makeMapStateToProps,
dispatchActions dispatchActions

View File

@ -16,13 +16,13 @@ import {
import { submitChallenge, showProjectSubmit } from '../../redux/actions'; import { submitChallenge, showProjectSubmit } from '../../redux/actions';
const propTypes = { const propTypes = {
isSignedIn: PropTypes.bool,
isSubmitting: PropTypes.bool,
showProjectSubmit: PropTypes.func,
fields: PropTypes.object, fields: PropTypes.object,
handleSubmit: PropTypes.func, handleSubmit: PropTypes.func,
submitChallenge: PropTypes.func, isSignedIn: PropTypes.bool,
resetForm: PropTypes.func isSubmitting: PropTypes.bool,
resetForm: PropTypes.func,
showProjectSubmit: PropTypes.func,
submitChallenge: PropTypes.func
}; };
const bindableActions = { const bindableActions = {

View File

@ -29,17 +29,15 @@ const mapStateToProps = createSelector(
description description
}) })
); );
const propTypes = {
description: PropTypes.arrayOf(PropTypes.string),
id: PropTypes.string,
isCompleted: PropTypes.bool,
title: PropTypes.string,
videoId: PropTypes.string
};
export class Project extends PureComponent { export class Project extends PureComponent {
static displayName = 'Project';
static propTypes = {
id: PropTypes.string,
videoId: PropTypes.string,
title: PropTypes.string,
description: PropTypes.arrayOf(PropTypes.string),
isCompleted: PropTypes.bool
};
render() { render() {
const { const {
id, id,
@ -78,6 +76,9 @@ export class Project extends PureComponent {
} }
} }
Project.displayName = 'Project';
Project.propTypes = propTypes;
export default connect( export default connect(
mapStateToProps mapStateToProps
)(Project); )(Project);

View File

@ -2,14 +2,14 @@ import React, { PropTypes } from 'react';
import PureComponent from 'react-pure-render/component'; import PureComponent from 'react-pure-render/component';
export default class SidePanel extends PureComponent { const propTypes = {
static propTypes = {
title: PropTypes.string,
description: PropTypes.arrayOf(PropTypes.string), description: PropTypes.arrayOf(PropTypes.string),
isCompleted: PropTypes.bool, isCompleted: PropTypes.bool,
isSignedIn: PropTypes.bool isSignedIn: PropTypes.bool,
}; title: PropTypes.string
};
export default class SidePanel extends PureComponent {
renderIcon(isCompleted) { renderIcon(isCompleted) {
if (!isCompleted) { if (!isCompleted) {
return null; return null;
@ -48,3 +48,6 @@ export default class SidePanel extends PureComponent {
); );
} }
} }
SidePanel.displayName = 'ProjectSidePanel';
SidePanel.propTypes = propTypes;

View File

@ -17,11 +17,11 @@ import {
} from '../../../../utils/challengeTypes'; } from '../../../../utils/challengeTypes';
const propTypes = { const propTypes = {
helpChatRoom: PropTypes.string.isRequired,
isFrontEnd: PropTypes.bool,
isSignedIn: PropTypes.bool, isSignedIn: PropTypes.bool,
isSimple: PropTypes.bool, isSimple: PropTypes.bool,
isFrontEnd: PropTypes.bool,
isSubmitting: PropTypes.bool, isSubmitting: PropTypes.bool,
helpChatRoom: PropTypes.string.isRequired,
openBugModal: PropTypes.func.isRequired, openBugModal: PropTypes.func.isRequired,
submitChallenge: PropTypes.func.isRequired submitChallenge: PropTypes.func.isRequired
}; };
@ -109,8 +109,8 @@ export class ToolPanel extends PureComponent {
} }
} }
ToolPanel.displayName = 'ProjectToolPanel';
ToolPanel.propTypes = propTypes; ToolPanel.propTypes = propTypes;
ToolPanel.displayName = 'ToolPanel';
export default connect( export default connect(
mapStateToProps, mapStateToProps,

View File

@ -62,9 +62,9 @@ const propTypes = {
numOfSteps: PropTypes.number, numOfSteps: PropTypes.number,
openLightBoxImage: PropTypes.func.isRequired, openLightBoxImage: PropTypes.func.isRequired,
step: PropTypes.array, step: PropTypes.array,
steps: PropTypes.array,
stepBackward: PropTypes.func, stepBackward: PropTypes.func,
stepForward: PropTypes.func, stepForward: PropTypes.func,
steps: PropTypes.array,
submitChallenge: PropTypes.func.isRequired, submitChallenge: PropTypes.func.isRequired,
updateUnlockedSteps: PropTypes.func.isRequired updateUnlockedSteps: PropTypes.func.isRequired
}; };

View File

@ -31,20 +31,15 @@ const embedOpts = {
width: '853', width: '853',
height: '480' height: '480'
}; };
const propTypes = {
dashedName: PropTypes.string,
description: PropTypes.array,
id: PropTypes.string,
toggleQuestionView: PropTypes.func,
videoId: PropTypes.string
};
export class Lecture extends React.Component { export class Lecture extends React.Component {
static displayName = 'Lecture';
static propTypes = {
// actions
toggleQuestionView: PropTypes.func,
// ui
id: PropTypes.string,
videoId: PropTypes.string,
description: PropTypes.array,
dashedName: PropTypes.string
};
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
const { props } = this; const { props } = this;
return nextProps.id !== props.id; return nextProps.id !== props.id;
@ -111,6 +106,9 @@ export class Lecture extends React.Component {
} }
} }
Lecture.displayName = 'Lecture';
Lecture.propTypes = propTypes;
export default connect( export default connect(
mapStateToProps, mapStateToProps,
{ toggleQuestionView } { toggleQuestionView }

View File

@ -47,27 +47,22 @@ const mapStateToProps = createSelector(
isSignedIn isSignedIn
}) })
); );
const propTypes = {
class Question extends React.Component {
static displayName = 'Questions';
static propTypes = {
// actions
answerQuestion: PropTypes.func, answerQuestion: PropTypes.func,
releaseQuestion: PropTypes.func, currentQuestion: PropTypes.number,
moveQuestion: PropTypes.func,
grabQuestion: PropTypes.func,
// ui state
tests: PropTypes.array,
mouse: PropTypes.array,
delta: PropTypes.array, delta: PropTypes.array,
grabQuestion: PropTypes.func,
isCorrect: PropTypes.bool, isCorrect: PropTypes.bool,
isPressed: PropTypes.bool, isPressed: PropTypes.bool,
isSignedIn: PropTypes.bool, isSignedIn: PropTypes.bool,
currentQuestion: PropTypes.number, mouse: PropTypes.array,
shouldShakeQuestion: PropTypes.bool moveQuestion: PropTypes.func,
}; releaseQuestion: PropTypes.func,
shouldShakeQuestion: PropTypes.bool,
tests: PropTypes.array
};
class Question extends React.Component {
handleMouseUp(e, answer, info) { handleMouseUp(e, answer, info) {
e.stopPropagation(); e.stopPropagation();
if (!this.props.isPressed) { if (!this.props.isPressed) {
@ -191,4 +186,7 @@ class Question extends React.Component {
} }
} }
Question.displayName = 'Question';
Question.propTypes = propTypes;
export default connect(mapStateToProps, actionsToBind)(Question); export default connect(mapStateToProps, actionsToBind)(Question);

View File

@ -18,21 +18,15 @@ const mapStateToProps = createSelector(
shouldShowQuestions shouldShowQuestions
}) })
); );
const propTypes = {
// export plain component for testing
export class Video extends React.Component {
static displayName = 'Video';
static propTypes = {
// actions
resetUi: PropTypes.func,
// ui
title: PropTypes.string,
params: PropTypes.object, params: PropTypes.object,
resetUi: PropTypes.func,
shouldShowQuestions: PropTypes.bool, shouldShowQuestions: PropTypes.bool,
title: PropTypes.string,
updateTitle: PropTypes.func updateTitle: PropTypes.func
}; };
export class Video extends React.Component {
componentWillMount() { componentWillMount() {
const { updateTitle, title } = this.props; const { updateTitle, title } = this.props;
updateTitle(title); updateTitle(title);
@ -78,7 +72,9 @@ export class Video extends React.Component {
} }
} }
// export redux aware component Video.displayName = 'Video';
Video.propTypes = propTypes;
export default connect( export default connect(
mapStateToProps, mapStateToProps,
bindableActions bindableActions

View File

@ -4,6 +4,16 @@ import { Button, Row, Col } from 'react-bootstrap';
import FA from 'react-fontawesome'; import FA from 'react-fontawesome';
import classnames from 'classnames'; import classnames from 'classnames';
const propTypes = {
email: PropTypes.string,
sendMonthlyEmail: PropTypes.bool,
sendNotificationEmail: PropTypes.bool,
sendQuincyEmail: PropTypes.bool,
toggleMonthlyEmail: PropTypes.func.isRequired,
toggleNotificationEmail: PropTypes.func.isRequired,
toggleQuincyEmail: PropTypes.func.isRequired
};
export function UpdateEmailButton() { export function UpdateEmailButton() {
return ( return (
<Link <Link
@ -138,12 +148,5 @@ export default function EmailSettings({
); );
} }
EmailSettings.propTypes = { EmailSettings.displayName = 'EmailSettings';
email: PropTypes.string, EmailSettings.propTypes = propTypes;
sendMonthlyEmail: PropTypes.bool,
sendNotificationEmail: PropTypes.bool,
sendQuincyEmail: PropTypes.bool,
toggleMonthlyEmail: PropTypes.func.isRequired,
toggleNotificationEmail: PropTypes.func.isRequired,
toggleQuincyEmail: PropTypes.func.isRequired
};

View File

@ -100,6 +100,7 @@ export class LanguageSettings extends React.Component {
} }
} }
LanguageSettings.displayName = 'LanguageSettings';
LanguageSettings.propTypes = propTypes; LanguageSettings.propTypes = propTypes;
export default reduxForm( export default reduxForm(

View File

@ -2,6 +2,11 @@ import React, { PropTypes } from 'react';
import { Button, Row, Col } from 'react-bootstrap'; import { Button, Row, Col } from 'react-bootstrap';
import classnames from 'classnames'; import classnames from 'classnames';
const propTypes = {
isLocked: PropTypes.bool,
toggle: PropTypes.func.isRequired
};
export default function LockSettings({ isLocked, toggle }) { export default function LockSettings({ isLocked, toggle }) {
const className = classnames({ const className = classnames({
'positive-20': true, 'positive-20': true,
@ -32,7 +37,5 @@ export default function LockSettings({ isLocked, toggle }) {
); );
} }
LockSettings.propTypes = { LockSettings.displayName = 'LockSettings';
isLocked: PropTypes.bool, LockSettings.propTypes = propTypes;
toggle: PropTypes.func.isRequired
};

View File

@ -58,25 +58,25 @@ const mapStateToProps = createSelector(
); );
const propTypes = { const propTypes = {
children: PropTypes.element, children: PropTypes.element,
username: PropTypes.string,
isLocked: PropTypes.bool,
isGithubCool: PropTypes.bool,
isTwitter: PropTypes.bool,
isLinkedIn: PropTypes.bool,
showLoading: PropTypes.bool,
email: PropTypes.string, email: PropTypes.string,
initialLang: PropTypes.string,
isGithubCool: PropTypes.bool,
isLinkedIn: PropTypes.bool,
isLocked: PropTypes.bool,
isTwitter: PropTypes.bool,
lang: PropTypes.string,
sendMonthlyEmail: PropTypes.bool, sendMonthlyEmail: PropTypes.bool,
sendNotificationEmail: PropTypes.bool, sendNotificationEmail: PropTypes.bool,
sendQuincyEmail: PropTypes.bool, sendQuincyEmail: PropTypes.bool,
updateTitle: PropTypes.func.isRequired, showLoading: PropTypes.bool,
toggleNightMode: PropTypes.func.isRequired,
toggleIsLocked: PropTypes.func.isRequired, toggleIsLocked: PropTypes.func.isRequired,
toggleQuincyEmail: PropTypes.func.isRequired,
toggleMonthlyEmail: PropTypes.func.isRequired, toggleMonthlyEmail: PropTypes.func.isRequired,
toggleNightMode: PropTypes.func.isRequired,
toggleNotificationEmail: PropTypes.func.isRequired, toggleNotificationEmail: PropTypes.func.isRequired,
lang: PropTypes.string, toggleQuincyEmail: PropTypes.func.isRequired,
initialLang: PropTypes.string, updateMyLang: PropTypes.func,
updateMyLang: PropTypes.func updateTitle: PropTypes.func.isRequired,
username: PropTypes.string
}; };
export class Settings extends React.Component { export class Settings extends React.Component {

View File

@ -3,6 +3,12 @@ import { Button } from 'react-bootstrap';
import FA from 'react-fontawesome'; import FA from 'react-fontawesome';
import classnames from 'classnames'; import classnames from 'classnames';
const propTypes = {
isGithubCool: PropTypes.bool,
isLinkedIn: PropTypes.bool,
isTwitter: PropTypes.bool
};
export default function SocialSettings({ export default function SocialSettings({
isGithubCool, isGithubCool,
isTwitter, isTwitter,
@ -65,8 +71,5 @@ export default function SocialSettings({
return (<div>{ buttons }</div>); return (<div>{ buttons }</div>);
} }
SocialSettings.propTypes = { SocialSettings.displayName = 'SocialSettings';
isGithubCool: PropTypes.bool, SocialSettings.propTypes = propTypes;
isTwitter: PropTypes.bool,
isLinkedIn: PropTypes.bool
};

View File

@ -35,22 +35,20 @@ const mapStateToProps = state => {
isVerified: !!emailVerified isVerified: !!emailVerified
}; };
}; };
const propTypes = {
fields: PropTypes.object.isRequired,
handleSubmit: PropTypes.func.isRequired,
isEmailThere: PropTypes.bool,
isVerified: PropTypes.bool,
submitting: PropTypes.bool,
updateMyEmail: PropTypes.func.isRequired
};
export class UpdateEmail extends React.Component { export class UpdateEmail extends React.Component {
constructor(...props) { constructor(...props) {
super(...props); super(...props);
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
} }
static displayName = 'UpdateEmail';
static propTypes = {
isEmailThere: PropTypes.bool,
isVerified: PropTypes.bool,
fields: PropTypes.object.isRequired,
submitting: PropTypes.bool,
handleSubmit: PropTypes.func.isRequired,
updateMyEmail: PropTypes.func.isRequired
};
handleSubmit(e) { handleSubmit(e) {
e.preventDefault(); e.preventDefault();
this.props.handleSubmit(({ email }) => this.props.updateMyEmail(email))(e); this.props.handleSubmit(({ email }) => this.props.updateMyEmail(email))(e);
@ -133,6 +131,9 @@ export class UpdateEmail extends React.Component {
} }
} }
UpdateEmail.displayName = 'UpdateEmail';
UpdateEmail.propTypes = propTypes;
export default reduxForm( export default reduxForm(
{ {
form: 'update-email', form: 'update-email',

View File

@ -58,18 +58,16 @@ const addDispatchableActionsToToast = createSelector(
}; };
}) })
); );
const propTypes = {
dispatch: PropTypes.func,
toasts: PropTypes.arrayOf(PropTypes.object)
};
export class Toasts extends React.Component { export class Toasts extends React.Component {
constructor(...props) { constructor(...props) {
super(...props); super(...props);
this.handleDismiss = this.handleDismiss.bind(this); this.handleDismiss = this.handleDismiss.bind(this);
} }
static displayName = 'Toasts';
static propTypes = {
toasts: PropTypes.arrayOf(PropTypes.object),
dispatch: PropTypes.func
};
styleFactory(index, style) { styleFactory(index, style) {
return { ...style, bottom: `${4 + index * 8}rem` }; return { ...style, bottom: `${4 + index * 8}rem` };
} }
@ -93,4 +91,7 @@ export class Toasts extends React.Component {
} }
} }
Toasts.displayName = 'Toasts';
Toasts.propTypes = propTypes;
export default connect(mapStateToProps)(Toasts); export default connect(mapStateToProps)(Toasts);

View File

@ -133,7 +133,7 @@
"eslint": "^3.1.0", "eslint": "^3.1.0",
"eslint-plugin-import": "^2.0.1", "eslint-plugin-import": "^2.0.1",
"eslint-plugin-prefer-object-spread": "^1.1.0", "eslint-plugin-prefer-object-spread": "^1.1.0",
"eslint-plugin-react": "^6.2.0", "eslint-plugin-react": "^6.9.0",
"gulp": "^3.9.0", "gulp": "^3.9.0",
"gulp-babel": "^6.1.1", "gulp-babel": "^6.1.1",
"gulp-concat": "^2.6.0", "gulp-concat": "^2.6.0",