mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-10-24 12:13:31 +08:00
feat(nav): remove sidecar
This commit is contained in:
@@ -3,13 +3,10 @@ import { Button, Row } from 'react-bootstrap';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import MapDrawer from './components/Map-Drawer.jsx';
|
||||
import {
|
||||
fetchUser,
|
||||
initWindowHeight,
|
||||
updateNavHeight,
|
||||
toggleMapDrawer,
|
||||
toggleMainChat,
|
||||
updateAppLang,
|
||||
trackEvent,
|
||||
loadCurrentChallenge
|
||||
@@ -26,8 +23,6 @@ const mapDispatchToProps = {
|
||||
updateNavHeight,
|
||||
fetchUser,
|
||||
submitChallenge,
|
||||
toggleMapDrawer,
|
||||
toggleMainChat,
|
||||
updateAppLang,
|
||||
trackEvent,
|
||||
loadCurrentChallenge
|
||||
@@ -37,23 +32,17 @@ const mapStateToProps = createSelector(
|
||||
userSelector,
|
||||
state => state.app.isSignInAttempted,
|
||||
state => state.app.toast,
|
||||
state => state.app.isMapDrawerOpen,
|
||||
state => state.app.isMapAlreadyLoaded,
|
||||
state => state.challengesApp.toast,
|
||||
(
|
||||
{ user: { username, points, picture } },
|
||||
isSignInAttempted,
|
||||
toast,
|
||||
isMapDrawerOpen,
|
||||
isMapAlreadyLoaded,
|
||||
) => ({
|
||||
username,
|
||||
points,
|
||||
picture,
|
||||
toast,
|
||||
showLoading: !isSignInAttempted,
|
||||
isMapDrawerOpen,
|
||||
isMapAlreadyLoaded,
|
||||
isSignedIn: !!username
|
||||
})
|
||||
);
|
||||
@@ -68,10 +57,6 @@ const propTypes = {
|
||||
updateNavHeight: PropTypes.func,
|
||||
initWindowHeight: PropTypes.func,
|
||||
submitChallenge: PropTypes.func,
|
||||
isMapDrawerOpen: PropTypes.bool,
|
||||
isMapAlreadyLoaded: PropTypes.bool,
|
||||
toggleMapDrawer: PropTypes.func,
|
||||
toggleMainChat: PropTypes.func,
|
||||
fetchUser: PropTypes.func,
|
||||
showLoading: PropTypes.bool,
|
||||
params: PropTypes.object,
|
||||
@@ -79,7 +64,6 @@ const propTypes = {
|
||||
trackEvent: PropTypes.func.isRequired,
|
||||
loadCurrentChallenge: PropTypes.func.isRequired
|
||||
};
|
||||
const contextTypes = { router: PropTypes.object };
|
||||
|
||||
// export plain class for testing
|
||||
export class FreeCodeCamp extends React.Component {
|
||||
@@ -112,30 +96,19 @@ export class FreeCodeCamp extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { router } = this.context;
|
||||
const {
|
||||
username,
|
||||
points,
|
||||
picture,
|
||||
updateNavHeight,
|
||||
isMapDrawerOpen,
|
||||
isMapAlreadyLoaded,
|
||||
toggleMapDrawer,
|
||||
toggleMainChat,
|
||||
showLoading,
|
||||
params: { lang },
|
||||
trackEvent,
|
||||
loadCurrentChallenge
|
||||
} = this.props;
|
||||
const navProps = {
|
||||
isOnMap: router.isActive(`/${lang}/map`),
|
||||
username,
|
||||
points,
|
||||
picture,
|
||||
updateNavHeight,
|
||||
toggleMapDrawer,
|
||||
toggleMainChat,
|
||||
showLoading,
|
||||
trackEvent,
|
||||
loadCurrentChallenge
|
||||
};
|
||||
@@ -146,11 +119,6 @@ export class FreeCodeCamp extends React.Component {
|
||||
<Row>
|
||||
{ this.props.children }
|
||||
</Row>
|
||||
<MapDrawer
|
||||
isAlreadyLoaded={ isMapAlreadyLoaded }
|
||||
isOpen={ isMapDrawerOpen }
|
||||
toggleMapDrawer={ toggleMapDrawer }
|
||||
/>
|
||||
<Toasts />
|
||||
</div>
|
||||
);
|
||||
@@ -158,7 +126,6 @@ export class FreeCodeCamp extends React.Component {
|
||||
}
|
||||
|
||||
FreeCodeCamp.displayName = 'FreeCodeCamp';
|
||||
FreeCodeCamp.contextTypes = contextTypes;
|
||||
FreeCodeCamp.propTypes = propTypes;
|
||||
|
||||
export default connect(
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
export default class Drawer extends React.Component {
|
||||
static displayName = 'Drawer';
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
isOpen: PropTypes.bool,
|
||||
closeDrawer: PropTypes.func,
|
||||
closeAria: PropTypes.string,
|
||||
newTabLink: PropTypes.string,
|
||||
newTabAria: PropTypes.string
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
isOpen,
|
||||
closeDrawer,
|
||||
closeAria,
|
||||
children,
|
||||
newTabAria,
|
||||
newTabLink
|
||||
} = this.props;
|
||||
const drawerClass = classnames({
|
||||
drawer: true,
|
||||
'is-collapsed': !isOpen
|
||||
});
|
||||
return (
|
||||
<aside className={ drawerClass }>
|
||||
<div className='drawer-action-bar'>
|
||||
<a
|
||||
aria-label={ newTabAria }
|
||||
className='drawer-action-item drawer-action-pop-out'
|
||||
href={ newTabLink }
|
||||
target='_blank'
|
||||
/>
|
||||
<button
|
||||
aria-label={ closeAria }
|
||||
className='drawer-action-item drawer-action-collapse'
|
||||
onClick={ closeDrawer }
|
||||
/>
|
||||
</div>
|
||||
<div className='drawer-content'>
|
||||
{ children }
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import { Alert } from 'react-bootstrap';
|
||||
|
||||
export default React.createClass({
|
||||
displayName: 'FlashQueue',
|
||||
|
||||
propTypes: {
|
||||
messages: PropTypes.array
|
||||
},
|
||||
|
||||
renderMessages(messages) {
|
||||
return messages.map(() => {
|
||||
return (
|
||||
<Alert />
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
const { messages = [] } = this.props;
|
||||
return (
|
||||
<div>
|
||||
{ this.renderMessages(messages) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
import NoSSR from 'react-no-ssr';
|
||||
|
||||
import Drawer from './Drawer.jsx';
|
||||
import ShowMap from '../routes/challenges/components/map/Map.jsx';
|
||||
|
||||
export default class MapDrawer extends React.Component {
|
||||
static displayName = 'MapDrawer';
|
||||
static propTypes = {
|
||||
isOpen: PropTypes.bool,
|
||||
isAlreadyLoaded: PropTypes.bool,
|
||||
toggleMapDrawer: PropTypes.func
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isOpen, isAlreadyLoaded, toggleMapDrawer } = this.props;
|
||||
return (
|
||||
<Drawer
|
||||
closeAria='close map aside'
|
||||
closeDrawer={ toggleMapDrawer }
|
||||
isOpen={ isOpen }
|
||||
newTabAria='open map in new tab'
|
||||
newTabLink='/map'
|
||||
>
|
||||
<NoSSR>
|
||||
<div>
|
||||
{ isAlreadyLoaded || isOpen ? <ShowMap /> : null }
|
||||
</div>
|
||||
</NoSSR>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
|
||||
import navLinks from './links.json';
|
||||
import AvatarPointsNavItem from './Avatar-Points-Nav-Item.jsx';
|
||||
import NoPropsPassthrough from '../../utils/No-Props-Passthrough.jsx';
|
||||
|
||||
const fCClogo = 'https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg';
|
||||
|
||||
@@ -34,10 +33,7 @@ const propTypes = {
|
||||
picture: PropTypes.string,
|
||||
signedIn: PropTypes.bool,
|
||||
username: PropTypes.string,
|
||||
isOnMap: PropTypes.bool,
|
||||
updateNavHeight: PropTypes.func,
|
||||
toggleMapDrawer: PropTypes.func,
|
||||
toggleMainChat: PropTypes.func,
|
||||
showLoading: PropTypes.bool,
|
||||
trackEvent: PropTypes.func.isRequired,
|
||||
loadCurrentChallenge: PropTypes.func.isRequired
|
||||
@@ -80,59 +76,6 @@ export default class FCCNav extends React.Component {
|
||||
this.props.loadCurrentChallenge();
|
||||
}
|
||||
|
||||
renderMapLink(isOnMap, toggleMapDrawer) {
|
||||
if (isOnMap) {
|
||||
return (
|
||||
<NoPropsPassthrough>
|
||||
<li role='presentation'>
|
||||
<a
|
||||
href='#'
|
||||
onClick={ this.handleMapClickOnMap }
|
||||
>
|
||||
Map
|
||||
</a>
|
||||
</li>
|
||||
</NoPropsPassthrough>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<LinkContainer
|
||||
eventKey={ 1 }
|
||||
to='/map'
|
||||
>
|
||||
<NavItem
|
||||
onClick={ e => {
|
||||
if (!(e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
toggleMapDrawer();
|
||||
}
|
||||
}}
|
||||
target='/map'
|
||||
>
|
||||
Map
|
||||
</NavItem>
|
||||
</LinkContainer>
|
||||
);
|
||||
}
|
||||
|
||||
renderChat(toggleMainChat) {
|
||||
return (
|
||||
<NavItem
|
||||
eventKey={ 2 }
|
||||
href='//gitter.im/freecodecamp/freecodecamp'
|
||||
onClick={ e => {
|
||||
if (!(e.ctrlKey || e.metaKey)) {
|
||||
e.preventDefault();
|
||||
toggleMainChat();
|
||||
}
|
||||
}}
|
||||
target='_blank'
|
||||
>
|
||||
Chat
|
||||
</NavItem>
|
||||
);
|
||||
}
|
||||
|
||||
renderLinks() {
|
||||
return navLinks.map(({ content, link, react, target }, index) => {
|
||||
if (react) {
|
||||
@@ -195,9 +138,6 @@ export default class FCCNav extends React.Component {
|
||||
username,
|
||||
points,
|
||||
picture,
|
||||
isOnMap,
|
||||
toggleMapDrawer,
|
||||
toggleMainChat,
|
||||
showLoading
|
||||
} = this.props;
|
||||
|
||||
@@ -227,8 +167,6 @@ export default class FCCNav extends React.Component {
|
||||
navbar={ true }
|
||||
pullRight={ true }
|
||||
>
|
||||
{ this.renderMapLink(isOnMap, toggleMapDrawer) }
|
||||
{ this.renderChat(toggleMainChat) }
|
||||
{ this.renderLinks() }
|
||||
{ this.renderSignIn(username, points, picture, showLoading) }
|
||||
</Nav>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
[{
|
||||
"content": "Map",
|
||||
"link": "/map",
|
||||
"react": true
|
||||
},{
|
||||
"content": "Chat",
|
||||
"link": "https://gitter.im/freecodecamp/home",
|
||||
"target": "_blank"
|
||||
},{
|
||||
"content": "Forum",
|
||||
"link": "http://forum.freecodecamp.com/",
|
||||
"link": "https://forum.freecodecamp.com/",
|
||||
"target": "_blank"
|
||||
},{
|
||||
"content": "About",
|
||||
|
||||
@@ -136,63 +136,6 @@ export const doActionOnError = actionCreator => error => Observable.of(
|
||||
actionCreator()
|
||||
);
|
||||
|
||||
|
||||
// drawers
|
||||
export const toggleMapDrawer = createAction(
|
||||
types.toggleMapDrawer,
|
||||
null,
|
||||
() => createEventMeta({
|
||||
category: 'Nav',
|
||||
action: 'toggled',
|
||||
label: 'Map drawer toggled'
|
||||
})
|
||||
);
|
||||
export const closeMapDrawer = createAction(
|
||||
types.closeMapDrawer,
|
||||
null,
|
||||
() => createEventMeta({
|
||||
category: 'Nav',
|
||||
action: 'clicked',
|
||||
label: 'Map drawer closed'
|
||||
})
|
||||
);
|
||||
export const toggleMainChat = createAction(
|
||||
types.toggleMainChat,
|
||||
null,
|
||||
() => createEventMeta({
|
||||
category: 'Nav',
|
||||
action: 'toggled',
|
||||
label: 'Main chat toggled'
|
||||
})
|
||||
);
|
||||
export const toggleHelpChat = createAction(
|
||||
types.toggleHelpChat,
|
||||
null,
|
||||
() => createEventMeta({
|
||||
category: 'Challenge',
|
||||
action: 'toggled',
|
||||
label: 'help chat toggled'
|
||||
})
|
||||
);
|
||||
export const openHelpChat = createAction(
|
||||
types.openHelpChat,
|
||||
null,
|
||||
() => createEventMeta({
|
||||
category: 'Challenge',
|
||||
action: 'opened',
|
||||
label: 'help chat opened'
|
||||
})
|
||||
);
|
||||
export const closeHelpChat = createAction(
|
||||
types.closeHelpChat,
|
||||
null,
|
||||
() => createEventMeta({
|
||||
category: 'Challenge',
|
||||
action: 'closed',
|
||||
label: 'help chat closed'
|
||||
})
|
||||
);
|
||||
|
||||
export const toggleNightMode = createAction(
|
||||
types.toggleNightMode,
|
||||
// we use this function to avoid hanging onto the eventObject
|
||||
|
||||
@@ -9,8 +9,6 @@ const initialState = {
|
||||
csrfToken: '',
|
||||
windowHeight: 0,
|
||||
navHeight: 0,
|
||||
isMainChatOpen: false,
|
||||
isHelpChatOpen: false,
|
||||
theme: 'default'
|
||||
};
|
||||
|
||||
@@ -51,31 +49,6 @@ export default handleActions(
|
||||
...state,
|
||||
navHeight
|
||||
}),
|
||||
[types.toggleMapDrawer]: state => ({
|
||||
...state,
|
||||
isMapAlreadyLoaded: true,
|
||||
isMapDrawerOpen: !state.isMapDrawerOpen
|
||||
}),
|
||||
[types.closeMapDrawer]: state => ({
|
||||
...state,
|
||||
isMapDrawerOpen: false
|
||||
}),
|
||||
[types.toggleMainChat]: state => ({
|
||||
...state,
|
||||
isMainChatOpen: !state.isMainChatOpen
|
||||
}),
|
||||
[types.toggleHelpChat]: state => ({
|
||||
...state,
|
||||
isHelpChatOpen: !state.isHelpChatOpen
|
||||
}),
|
||||
[types.openHelpChat]: state => ({
|
||||
...state,
|
||||
isHelpChatOpen: true
|
||||
}),
|
||||
[types.closeHelpChat]: state => ({
|
||||
...state,
|
||||
isHelpChatOpen: false
|
||||
}),
|
||||
[types.delayedRedirect]: (state, { payload }) => ({
|
||||
...state,
|
||||
delayedRedirect: payload
|
||||
|
||||
@@ -30,20 +30,6 @@ export default createTypes([
|
||||
'updateChallengesData',
|
||||
'updateHikesData',
|
||||
|
||||
// drawers
|
||||
'toggleMapDrawer',
|
||||
'closeMapDrawer',
|
||||
'toggleWikiDrawer',
|
||||
|
||||
// chat
|
||||
'openMainChat',
|
||||
'closeMainChat',
|
||||
'toggleMainChat',
|
||||
|
||||
'openHelpChat',
|
||||
'closeHelpChat',
|
||||
'toggleHelpChat',
|
||||
|
||||
// night mode
|
||||
'toggleNightMode',
|
||||
'updateTheme',
|
||||
|
||||
@@ -16,13 +16,11 @@ import {
|
||||
unlockUntrustedCode
|
||||
} from '../../redux/actions';
|
||||
import { makeToast } from '../../../../toasts/redux/actions';
|
||||
import { toggleHelpChat } from '../../../../redux/actions';
|
||||
|
||||
const bindableActions = {
|
||||
const mapDispatchToProps = {
|
||||
makeToast,
|
||||
executeChallenge,
|
||||
updateHint,
|
||||
toggleHelpChat,
|
||||
openBugModal,
|
||||
unlockUntrustedCode
|
||||
};
|
||||
@@ -34,6 +32,7 @@ const mapStateToProps = createSelector(
|
||||
state => state.challengesApp.output,
|
||||
state => state.challengesApp.hintIndex,
|
||||
state => state.challengesApp.isCodeLocked,
|
||||
state => state.challengesApp.helpChatRoom,
|
||||
(
|
||||
{
|
||||
challenge: {
|
||||
@@ -47,7 +46,8 @@ const mapStateToProps = createSelector(
|
||||
tests,
|
||||
output,
|
||||
hintIndex,
|
||||
isCodeLocked
|
||||
isCodeLocked,
|
||||
helpChatRoom
|
||||
) => ({
|
||||
title,
|
||||
description,
|
||||
@@ -55,7 +55,8 @@ const mapStateToProps = createSelector(
|
||||
tests,
|
||||
output,
|
||||
hint: hints[hintIndex],
|
||||
isCodeLocked
|
||||
isCodeLocked,
|
||||
helpChatRoom
|
||||
})
|
||||
);
|
||||
|
||||
@@ -69,17 +70,18 @@ export class SidePanel extends PureComponent {
|
||||
static propTypes = {
|
||||
description: PropTypes.arrayOf(PropTypes.string),
|
||||
height: PropTypes.number,
|
||||
helpChatRoom: PropTypes.string,
|
||||
hint: PropTypes.string,
|
||||
isCodeLocked: PropTypes.bool,
|
||||
output: PropTypes.string,
|
||||
tests: PropTypes.arrayOf(PropTypes.object),
|
||||
title: PropTypes.string,
|
||||
output: PropTypes.string,
|
||||
hint: PropTypes.string,
|
||||
updateHint: PropTypes.func,
|
||||
makeToast: PropTypes.func,
|
||||
toggleHelpChat: PropTypes.func,
|
||||
|
||||
executeChallenge: PropTypes.func,
|
||||
openBugModal: PropTypes.func,
|
||||
makeToast: PropTypes.func,
|
||||
unlockUntrustedCode: PropTypes.func,
|
||||
isCodeLocked: PropTypes.bool,
|
||||
executeChallenge: PropTypes.func
|
||||
updateHint: PropTypes.func
|
||||
};
|
||||
|
||||
renderDescription(description = [ 'Happy Coding!' ], descriptionRegex) {
|
||||
@@ -119,7 +121,7 @@ export class SidePanel extends PureComponent {
|
||||
executeChallenge,
|
||||
updateHint,
|
||||
makeToast,
|
||||
toggleHelpChat,
|
||||
helpChatRoom,
|
||||
openBugModal,
|
||||
isCodeLocked,
|
||||
unlockUntrustedCode
|
||||
@@ -150,11 +152,11 @@ export class SidePanel extends PureComponent {
|
||||
</div>
|
||||
<ToolPanel
|
||||
executeChallenge={ executeChallenge }
|
||||
helpChatRoom={ helpChatRoom }
|
||||
hint={ hint }
|
||||
isCodeLocked={ isCodeLocked }
|
||||
makeToast={ makeToast }
|
||||
openBugModal={ openBugModal }
|
||||
toggleHelpChat={ toggleHelpChat }
|
||||
unlockUntrustedCode={ unlockUntrustedCode }
|
||||
updateHint={ updateHint }
|
||||
/>
|
||||
@@ -168,5 +170,5 @@ export class SidePanel extends PureComponent {
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
bindableActions
|
||||
mapDispatchToProps
|
||||
)(SidePanel);
|
||||
|
||||
@@ -9,25 +9,24 @@ const unlockWarning = (
|
||||
</h4>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
const propTypes = {
|
||||
executeChallenge: PropTypes.func.isRequired,
|
||||
helpChatRoom: PropTypes.string,
|
||||
hint: PropTypes.string,
|
||||
isCodeLocked: PropTypes.bool,
|
||||
makeToast: PropTypes.func.isRequired,
|
||||
openBugModal: PropTypes.func.isRequired,
|
||||
unlockUntrustedCode: PropTypes.func.isRequired,
|
||||
updateHint: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default class ToolPanel extends PureComponent {
|
||||
constructor(...props) {
|
||||
super(...props);
|
||||
this.makeHint = this.makeHint.bind(this);
|
||||
this.makeReset = this.makeReset.bind(this);
|
||||
}
|
||||
static displayName = 'ToolPanel';
|
||||
|
||||
static propTypes = {
|
||||
executeChallenge: PropTypes.func.isRequired,
|
||||
updateHint: PropTypes.func.isRequired,
|
||||
hint: PropTypes.string,
|
||||
isCodeLocked: PropTypes.bool,
|
||||
unlockUntrustedCode: PropTypes.func.isRequired,
|
||||
toggleHelpChat: PropTypes.func.isRequired,
|
||||
openBugModal: PropTypes.func.isRequired,
|
||||
makeToast: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
makeHint() {
|
||||
this.props.makeToast({
|
||||
message: this.props.hint,
|
||||
@@ -93,10 +92,10 @@ export default class ToolPanel extends PureComponent {
|
||||
|
||||
render() {
|
||||
const {
|
||||
executeChallenge,
|
||||
helpChatRoom,
|
||||
hint,
|
||||
isCodeLocked,
|
||||
executeChallenge,
|
||||
toggleHelpChat,
|
||||
openBugModal,
|
||||
unlockUntrustedCode
|
||||
} = this.props;
|
||||
@@ -126,8 +125,9 @@ export default class ToolPanel extends PureComponent {
|
||||
<Button
|
||||
bsSize='large'
|
||||
bsStyle='primary'
|
||||
componentClass='label'
|
||||
onClick={ toggleHelpChat }
|
||||
componentClass='a'
|
||||
href={ `https://gitter.im/freecodecamp/${helpChatRoom}` }
|
||||
target='_blank'
|
||||
>
|
||||
Help
|
||||
</Button>
|
||||
@@ -145,3 +145,6 @@ export default class ToolPanel extends PureComponent {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ToolPanel.displayName = 'ToolPanel';
|
||||
ToolPanel.propTypes = propTypes;
|
||||
|
||||
@@ -9,9 +9,21 @@ import debug from 'debug';
|
||||
import { updateCurrentChallenge } from '../../redux/actions';
|
||||
import { makePanelHiddenSelector } from '../../redux/selectors';
|
||||
import { userSelector } from '../../../../redux/selectors';
|
||||
import { closeMapDrawer } from '../../../../redux/actions';
|
||||
|
||||
const bindableActions = { closeMapDrawer, updateCurrentChallenge };
|
||||
const propTypes = {
|
||||
block: PropTypes.string,
|
||||
challenge: PropTypes.object,
|
||||
dashedName: PropTypes.string,
|
||||
isComingSoon: PropTypes.bool,
|
||||
isCompleted: PropTypes.bool,
|
||||
isDev: PropTypes.bool,
|
||||
isHidden: PropTypes.bool,
|
||||
isLocked: PropTypes.bool,
|
||||
isRequired: PropTypes.bool,
|
||||
title: PropTypes.string,
|
||||
updateCurrentChallenge: PropTypes.func.isRequired
|
||||
};
|
||||
const mapDispatchToProps = { updateCurrentChallenge };
|
||||
const makeMapStateToProps = () => createSelector(
|
||||
userSelector,
|
||||
(_, props) => props.dashedName,
|
||||
@@ -48,24 +60,8 @@ export class Challenge extends PureComponent {
|
||||
super(...args);
|
||||
this.handleChallengeClick = this.handleChallengeClick.bind(this);
|
||||
}
|
||||
static displayName = 'Challenge';
|
||||
static propTypes = {
|
||||
title: PropTypes.string,
|
||||
dashedName: PropTypes.string,
|
||||
block: PropTypes.string,
|
||||
isLocked: PropTypes.bool,
|
||||
isRequired: PropTypes.bool,
|
||||
isComingSoon: PropTypes.bool,
|
||||
isCompleted: PropTypes.bool,
|
||||
isDev: PropTypes.bool,
|
||||
isHidden: PropTypes.bool,
|
||||
challenge: PropTypes.object,
|
||||
updateCurrentChallenge: PropTypes.func.isRequired,
|
||||
closeMapDrawer: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
handleChallengeClick() {
|
||||
this.props.closeMapDrawer();
|
||||
this.props.updateCurrentChallenge(this.props.challenge);
|
||||
}
|
||||
|
||||
@@ -161,4 +157,10 @@ export class Challenge extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(makeMapStateToProps, bindableActions)(Challenge);
|
||||
Challenge.propTypes = propTypes;
|
||||
Challenge.dispalyName = 'Challenge';
|
||||
|
||||
export default connect(
|
||||
makeMapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Challenge);
|
||||
|
||||
@@ -15,40 +15,40 @@ import {
|
||||
simpleProject,
|
||||
frontEndProject
|
||||
} from '../../../../utils/challengeTypes';
|
||||
import { toggleHelpChat } from '../../../../redux/actions';
|
||||
|
||||
const bindableActions = {
|
||||
const propTypes = {
|
||||
isSignedIn: PropTypes.bool,
|
||||
isSimple: PropTypes.bool,
|
||||
isFrontEnd: PropTypes.bool,
|
||||
isSubmitting: PropTypes.bool,
|
||||
helpChatRoom: PropTypes.string.isRequired,
|
||||
openBugModal: PropTypes.func.isRequired,
|
||||
submitChallenge: PropTypes.func.isRequired
|
||||
};
|
||||
const mapDispatchToProps = {
|
||||
submitChallenge,
|
||||
toggleHelpChat,
|
||||
openBugModal
|
||||
};
|
||||
const mapStateToProps = createSelector(
|
||||
challengeSelector,
|
||||
state => state.app.isSignedIn,
|
||||
state => state.challengesApp.isSubmitting,
|
||||
state => state.challengesApp.helpChatRoom,
|
||||
(
|
||||
{ challenge: { challengeType = simpleProject } },
|
||||
isSignedIn,
|
||||
isSubmitting
|
||||
isSubmitting,
|
||||
helpChatRoom,
|
||||
) => ({
|
||||
isSignedIn,
|
||||
isSubmitting,
|
||||
helpChatRoom,
|
||||
isSimple: challengeType === simpleProject,
|
||||
isFrontEnd: challengeType === frontEndProject
|
||||
})
|
||||
);
|
||||
|
||||
export class ToolPanel extends PureComponent {
|
||||
static propTypes = {
|
||||
isSignedIn: PropTypes.bool,
|
||||
isSimple: PropTypes.bool,
|
||||
isFrontEnd: PropTypes.bool,
|
||||
isSubmitting: PropTypes.bool,
|
||||
toggleHelpChat: PropTypes.func.isRequired,
|
||||
openBugModal: PropTypes.func.isRequired,
|
||||
submitChallenge: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
renderSubmitButton(isSignedIn, submitChallenge) {
|
||||
const buttonCopy = isSignedIn ?
|
||||
'Submit and go to my next challenge' :
|
||||
@@ -71,8 +71,8 @@ export class ToolPanel extends PureComponent {
|
||||
isSimple,
|
||||
isSignedIn,
|
||||
isSubmitting,
|
||||
helpChatRoom,
|
||||
submitChallenge,
|
||||
toggleHelpChat,
|
||||
openBugModal
|
||||
} = this.props;
|
||||
|
||||
@@ -89,8 +89,9 @@ export class ToolPanel extends PureComponent {
|
||||
<Button
|
||||
bsStyle='primary'
|
||||
className='btn-primary-ghost btn-big'
|
||||
componentClass='div'
|
||||
onClick={ toggleHelpChat }
|
||||
componentClass='a'
|
||||
href={ `https://gitter.im/freecodecamp/${helpChatRoom}` }
|
||||
target='_blank'
|
||||
>
|
||||
Help
|
||||
</Button>
|
||||
@@ -108,7 +109,10 @@ export class ToolPanel extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
ToolPanel.propTypes = propTypes;
|
||||
ToolPanel.displayName = 'ToolPanel';
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
bindableActions
|
||||
mapDispatchToProps
|
||||
)(ToolPanel);
|
||||
|
||||
Reference in New Issue
Block a user