Files
freeCodeCamp/common/app/components/Nav/Nav.jsx

213 lines
4.9 KiB
JavaScript
Raw Normal View History

2015-07-24 21:54:19 -07:00
import React, { PropTypes } from 'react';
2016-03-05 21:06:04 -08:00
import ReactDOM from 'react-dom';
2015-10-27 15:40:04 -07:00
import { LinkContainer } from 'react-router-bootstrap';
2015-07-23 22:58:44 -07:00
import {
Col,
2016-12-30 15:23:58 -08:00
MenuItem,
2015-07-23 22:58:44 -07:00
Nav,
2016-12-30 15:23:58 -08:00
NavDropdown,
NavItem,
2015-07-23 22:58:44 -07:00
Navbar,
2016-12-30 15:23:58 -08:00
NavbarBrand
2015-07-23 22:58:44 -07:00
} from 'react-bootstrap';
import noop from 'lodash/noop';
import navLinks from './links.json';
import AvatarPointsNavItem from './Avatar-Points-Nav-Item.jsx';
2015-06-04 10:53:01 -07:00
const fCClogo = 'https://s3.amazonaws.com/freecodecamp/freecodecamp_logo.svg';
const toggleButtonChild = (
2016-01-27 11:34:44 -08:00
<Col xs={ 12 }>
<span className='hamburger-text'>Menu</span>
</Col>
2015-07-23 22:58:44 -07:00
);
function handleNavLinkEvent(content) {
this.props.trackEvent({
category: 'Nav',
action: 'clicked',
label: `${content} link`
});
}
2016-10-28 22:14:39 -07:00
const propTypes = {
2017-01-02 23:04:07 -08:00
closeDropdown: PropTypes.func.isRequired,
isNavDropdownOpen: PropTypes.bool,
loadCurrentChallenge: PropTypes.func.isRequired,
openDropdown: PropTypes.func.isRequired,
2016-10-28 22:14:39 -07:00
picture: PropTypes.string,
2017-01-02 23:04:07 -08:00
points: PropTypes.number,
2016-10-28 22:14:39 -07:00
showLoading: PropTypes.bool,
2017-01-02 23:04:07 -08:00
signedIn: PropTypes.bool,
2016-10-28 22:14:39 -07:00
trackEvent: PropTypes.func.isRequired,
2017-01-02 23:04:07 -08:00
updateNavHeight: PropTypes.func,
username: PropTypes.string
2016-10-28 22:14:39 -07:00
};
export default class FCCNav extends React.Component {
constructor(...props) {
super(...props);
this.handleMapClickOnMap = this.handleMapClickOnMap.bind(this);
this.handleLogoClick = this.handleLogoClick.bind(this);
navLinks.forEach(({ content }) => {
this[`handle${content}Click`] = handleNavLinkEvent.bind(this, content);
});
}
2015-10-27 15:40:04 -07:00
2016-03-05 21:06:04 -08:00
componentDidMount() {
const navBar = ReactDOM.findDOMNode(this);
this.props.updateNavHeight(navBar.clientHeight);
}
handleMapClickOnMap(e) {
e.preventDefault();
this.props.trackEvent({
category: 'Nav',
action: 'clicked',
label: 'map clicked while on map'
});
}
handleNavClick() {
this.props.trackEvent({
category: 'Nav',
action: 'clicked',
label: 'map clicked while on map'
});
}
handleLogoClick(e) {
e.preventDefault();
this.props.loadCurrentChallenge();
}
2016-12-30 15:23:58 -08:00
renderLink(isNavItem, { isReact, isDropdown, content, link, links, target }) {
const Component = isNavItem ? NavItem : MenuItem;
2017-01-02 23:04:07 -08:00
const {
isNavDropdownOpen,
openDropdown,
closeDropdown
} = this.props;
2016-12-30 15:23:58 -08:00
if (isDropdown) {
// adding a noop to NavDropdown to disable false warning
// about controlled component
2015-10-27 15:40:04 -07:00
return (
2016-12-30 15:23:58 -08:00
<NavDropdown
id={ `nav-${content}-dropdown` }
key={ content }
noCaret={ true }
2017-01-02 23:04:07 -08:00
onClick={ openDropdown }
onClose={ closeDropdown }
onMouseEnter={ openDropdown }
onMouseLeave={ closeDropdown }
onToggle={ noop }
2017-01-02 23:04:07 -08:00
open={ isNavDropdownOpen }
2016-12-30 15:23:58 -08:00
title={ content }
>
{ links.map(this.renderLink.bind(this, false)) }
</NavDropdown>
);
}
if (isReact) {
return (
<LinkContainer
2015-11-13 12:54:46 -08:00
key={ content }
onClick={ this[`handle${content}Click`] }
2016-12-30 15:23:58 -08:00
to={ link }
>
2016-12-30 15:23:58 -08:00
<Component
target={ target || null }
>
{ content }
</Component>
</LinkContainer>
2015-10-27 15:40:04 -07:00
);
2016-12-30 15:23:58 -08:00
}
return (
<Component
href={ link }
key={ content }
onClick={ this[`handle${content}Click`] }
target={ target || null }
>
{ content }
</Component>
);
2016-01-27 11:34:44 -08:00
}
2015-06-04 10:53:01 -07:00
2016-10-28 22:14:39 -07:00
renderSignIn(username, points, picture, showLoading) {
if (showLoading) {
return null;
}
2015-07-24 21:54:19 -07:00
if (username) {
return (
<AvatarPointsNavItem
picture={ picture }
points={ points }
username={ username }
/>
);
2015-06-04 10:53:01 -07:00
} else {
return (
<NavItem
2016-09-08 21:56:46 -07:00
href='/signup'
key='signup'
>
2016-09-08 21:56:46 -07:00
Sign Up
</NavItem>
2015-06-04 10:53:01 -07:00
);
}
2016-01-27 11:34:44 -08:00
}
2015-06-04 10:53:01 -07:00
2015-06-17 21:04:28 -07:00
render() {
const {
username,
points,
picture,
2016-10-28 22:14:39 -07:00
showLoading
} = this.props;
2015-11-19 22:45:31 -08:00
2015-06-04 10:53:01 -07:00
return (
<Navbar
2015-06-17 21:04:28 -07:00
className='nav-height'
fixedTop={ true }
>
<Navbar.Header>
<Navbar.Toggle children={ toggleButtonChild } />
<NavbarBrand>
<a
href='/challenges/current-challenge'
onClick={ this.handleLogoClick }
>
<img
alt='learn to code javascript at freeCodeCamp logo'
className='img-responsive nav-logo'
src={ fCClogo }
/>
</a>
</NavbarBrand>
</Navbar.Header>
<Navbar.Collapse>
2015-07-24 21:54:19 -07:00
<Nav
className='hamburger-dropdown'
navbar={ true }
pullRight={ true }
>
2017-01-02 23:04:07 -08:00
{
navLinks.map(
this.renderLink.bind(this, true)
)
}
2016-10-28 22:14:39 -07:00
{ this.renderSignIn(username, points, picture, showLoading) }
2015-07-24 21:54:19 -07:00
</Nav>
</Navbar.Collapse>
2015-06-04 10:53:01 -07:00
</Navbar>
);
}
2016-01-27 11:34:44 -08:00
}
2016-10-28 22:14:39 -07:00
2017-01-02 23:04:07 -08:00
FCCNav.displayName = 'FCCNav';
2016-10-28 22:14:39 -07:00
FCCNav.propTypes = propTypes;