fix(client): merge and update the learn map (#36822)

This commit is contained in:
mrugesh
2019-09-21 19:09:48 +05:30
committed by Ahmad Abdolsaheb
parent a5b176be88
commit e54a7fb350
16 changed files with 561 additions and 581 deletions

View File

@@ -30,8 +30,8 @@ describe('<NavLinks />', () => {
it('renders to the DOM', () => {
expect(root).toBeTruthy();
});
it('has 2 a tags', () => {
expect(aTags.length === 2).toBeTruthy();
it('has 3 a tags', () => {
expect(aTags.length === 3).toBeTruthy();
});
it('has link to portfolio', () => {

View File

@@ -26,7 +26,7 @@ const createOnClick = (navigate, isSignedIn) => e => {
e.preventDefault();
gtagReportConversion();
if (isSignedIn) {
return gatsbyNavigate('/');
return gatsbyNavigate('/learn');
}
return navigate(`${apiLocation}/signin`);
};

View File

@@ -5,6 +5,9 @@ export function NavLinks() {
return (
<div className='main-nav-group'>
<ul className={'nav-list display-flex'} role='menu'>
<li className='nav-theme' role='menuitem'>
<Link to='/learn'>Projects</Link>
</li>
<li className='nav-theme' role='menuitem'>
<Link to='/'>Light</Link>
</li>

View File

@@ -1,99 +0,0 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
import uniq from 'lodash/uniq';
import { createSelector } from 'reselect';
import SuperBlock from './components/SuperBlock';
import Spacer from '../helpers/Spacer';
import './map.css';
import { ChallengeNode } from '../../redux/propTypes';
import { toggleSuperBlock, toggleBlock, resetExpansion } from './redux';
import { currentChallengeIdSelector } from '../../redux';
const propTypes = {
currentChallengeId: PropTypes.string,
introNodes: PropTypes.arrayOf(
PropTypes.shape({
fields: PropTypes.shape({ slug: PropTypes.string.isRequired }),
frontmatter: PropTypes.shape({
title: PropTypes.string.isRequired,
block: PropTypes.string.isRequired
})
})
),
nodes: PropTypes.arrayOf(ChallengeNode),
resetExpansion: PropTypes.func,
toggleBlock: PropTypes.func.isRequired,
toggleSuperBlock: PropTypes.func.isRequired
};
const mapStateToProps = state => {
return createSelector(
currentChallengeIdSelector,
currentChallengeId => ({
currentChallengeId
})
)(state);
};
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
resetExpansion,
toggleSuperBlock,
toggleBlock
},
dispatch
);
}
export class Map extends Component {
componentDidMount() {
this.initializeExpandedState(this.props.currentChallengeId);
}
initializeExpandedState(currentChallengeId) {
this.props.resetExpansion();
const { superBlock, block } = currentChallengeId
? this.props.nodes.find(node => node.id === currentChallengeId)
: this.props.nodes[0];
this.props.toggleBlock(block);
this.props.toggleSuperBlock(superBlock);
}
renderSuperBlocks(superBlocks) {
const { nodes, introNodes } = this.props;
return superBlocks.map(superBlock => (
<SuperBlock
introNodes={introNodes}
key={superBlock}
nodes={nodes}
superBlock={superBlock}
/>
));
}
render() {
const { nodes } = this.props;
const superBlocks = uniq(nodes.map(({ superBlock }) => superBlock));
return (
<div className='map-ui'>
<ul>
{this.renderSuperBlocks(superBlocks)}
<Spacer />
</ul>
</div>
);
}
}
Map.displayName = 'Map';
Map.propTypes = propTypes;
export default connect(
mapStateToProps,
mapDispatchToProps
)(Map);

View File

@@ -6,8 +6,8 @@ import Enzyme, { shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import store from 'store';
import { Map } from './Map';
import mockNodes from '../../__mocks__/map-nodes';
import { Map } from './';
import mockChallengeNodes from '../../__mocks__/challenge-nodes';
import mockIntroNodes from '../../__mocks__/intro-nodes';
Enzyme.configure({ adapter: new Adapter() });
@@ -15,7 +15,7 @@ const renderer = new ShallowRenderer();
const baseProps = {
introNodes: mockIntroNodes,
nodes: mockNodes,
nodes: mockChallengeNodes,
toggleBlock: () => {},
toggleSuperBlock: () => {},
resetExpansion: () => {}
@@ -25,7 +25,7 @@ test('<Map /> snapshot', () => {
const componentToRender = (
<Map
introNodes={mockIntroNodes}
nodes={mockNodes}
nodes={mockChallengeNodes}
toggleBlock={() => {}}
toggleSuperBlock={() => {}}
/>
@@ -45,7 +45,7 @@ describe('<Map/>', () => {
store.clearAll();
});
// 7 was chosen because it has a different superblock from the first node.
const currentChallengeId = mockNodes[7].id;
const currentChallengeId = mockChallengeNodes[7].id;
it('should expand the block with the most recent challenge', () => {
const blockSpy = jest.fn();
@@ -59,10 +59,10 @@ describe('<Map/>', () => {
const mapToRender = <Map {...props} />;
shallow(mapToRender);
expect(blockSpy).toHaveBeenCalledTimes(1);
expect(blockSpy).toHaveBeenCalledWith(mockNodes[7].block);
expect(blockSpy).toHaveBeenCalledWith(mockChallengeNodes[7].block);
expect(superSpy).toHaveBeenCalledTimes(1);
expect(superSpy).toHaveBeenCalledWith(mockNodes[7].superBlock);
expect(superSpy).toHaveBeenCalledWith(mockChallengeNodes[7].superBlock);
});
it('should use the currentChallengeId prop if it exists', () => {
@@ -85,13 +85,13 @@ describe('<Map/>', () => {
const mapToRender = <Map {...props} />;
shallow(mapToRender);
expect(blockSpy).toHaveBeenCalledTimes(1);
expect(blockSpy).toHaveBeenCalledWith(mockNodes[0].block);
expect(blockSpy).toHaveBeenCalledWith(mockChallengeNodes[0].block);
expect(superSpy).toHaveBeenCalledTimes(1);
expect(superSpy).toHaveBeenCalledWith(mockNodes[0].superBlock);
expect(superSpy).toHaveBeenCalledWith(mockChallengeNodes[0].superBlock);
});
it('calls resetExpansion when initialising', () => {
it('calls resetExpansion when initializing', () => {
const expansionSpy = jest.fn();
const props = {
...baseProps,

View File

@@ -1,321 +1,334 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Map /> snapshot: Map 1`] = `
<div
className="map-ui"
<Row
bsClass="row"
componentClass="div"
>
<ul>
<Connect(SuperBlock)
introNodes={
Array [
Object {
"fields": Object {
"slug": "/super-block-one/block-a",
},
"frontmatter": Object {
"block": "Block A",
"title": "Introduction to Block A",
},
},
Object {
"fields": Object {
"slug": "/super-block-one/block-b",
},
"frontmatter": Object {
"block": "Block B",
"title": "Introduction to Block B",
},
},
Object {
"fields": Object {
"slug": "/super-block-one/block-c",
},
"frontmatter": Object {
"block": "Block C",
"title": "Introduction to Block C",
},
},
]
}
nodes={
Array [
Object {
"block": "block-a",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-one",
},
"id": "a",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-two",
},
"id": "b",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge Two",
},
Object {
"block": "block-b",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-one",
},
"id": "c",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-b",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-two",
},
"id": "d",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge Two",
},
Object {
"block": "block-c",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block C",
"slug": "/super-block-one/block-c/challenge-one",
},
"id": "e",
"isPrivate": true,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-one",
},
"id": "f",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-two",
},
"id": "g",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge Two",
},
Object {
"block": "block-b",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-one",
},
"id": "h",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge One",
},
Object {
"block": "block-b",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-two",
},
"id": "i",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge Two",
},
]
}
superBlock="Super Block One"
/>
<Connect(SuperBlock)
introNodes={
Array [
Object {
"fields": Object {
"slug": "/super-block-one/block-a",
},
"frontmatter": Object {
"block": "Block A",
"title": "Introduction to Block A",
},
},
Object {
"fields": Object {
"slug": "/super-block-one/block-b",
},
"frontmatter": Object {
"block": "Block B",
"title": "Introduction to Block B",
},
},
Object {
"fields": Object {
"slug": "/super-block-one/block-c",
},
"frontmatter": Object {
"block": "Block C",
"title": "Introduction to Block C",
},
},
]
}
nodes={
Array [
Object {
"block": "block-a",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-one",
},
"id": "a",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-two",
},
"id": "b",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge Two",
},
Object {
"block": "block-b",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-one",
},
"id": "c",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-b",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-two",
},
"id": "d",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge Two",
},
Object {
"block": "block-c",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block C",
"slug": "/super-block-one/block-c/challenge-one",
},
"id": "e",
"isPrivate": true,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-one",
},
"id": "f",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-two",
},
"id": "g",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge Two",
},
Object {
"block": "block-b",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-one",
},
"id": "h",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge One",
},
Object {
"block": "block-b",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-two",
},
"id": "i",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge Two",
},
]
}
superBlock="Super Block Two"
/>
<Spacer />
</ul>
</div>
<Col
bsClass="col"
componentClass="div"
sm={10}
smOffset={1}
xs={12}
>
<div
className="map-ui"
>
<ul>
<Connect(SuperBlock)
introNodes={
Array [
Object {
"fields": Object {
"slug": "/super-block-one/block-a",
},
"frontmatter": Object {
"block": "Block A",
"title": "Introduction to Block A",
},
},
Object {
"fields": Object {
"slug": "/super-block-one/block-b",
},
"frontmatter": Object {
"block": "Block B",
"title": "Introduction to Block B",
},
},
Object {
"fields": Object {
"slug": "/super-block-one/block-c",
},
"frontmatter": Object {
"block": "Block C",
"title": "Introduction to Block C",
},
},
]
}
nodes={
Array [
Object {
"block": "block-a",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-one",
},
"id": "a",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-two",
},
"id": "b",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge Two",
},
Object {
"block": "block-b",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-one",
},
"id": "c",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-b",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-two",
},
"id": "d",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge Two",
},
Object {
"block": "block-c",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block C",
"slug": "/super-block-one/block-c/challenge-one",
},
"id": "e",
"isPrivate": true,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-one",
},
"id": "f",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-two",
},
"id": "g",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge Two",
},
Object {
"block": "block-b",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-one",
},
"id": "h",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge One",
},
Object {
"block": "block-b",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-two",
},
"id": "i",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge Two",
},
]
}
superBlock="Super Block One"
/>
<Connect(SuperBlock)
introNodes={
Array [
Object {
"fields": Object {
"slug": "/super-block-one/block-a",
},
"frontmatter": Object {
"block": "Block A",
"title": "Introduction to Block A",
},
},
Object {
"fields": Object {
"slug": "/super-block-one/block-b",
},
"frontmatter": Object {
"block": "Block B",
"title": "Introduction to Block B",
},
},
Object {
"fields": Object {
"slug": "/super-block-one/block-c",
},
"frontmatter": Object {
"block": "Block C",
"title": "Introduction to Block C",
},
},
]
}
nodes={
Array [
Object {
"block": "block-a",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-one",
},
"id": "a",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-two",
},
"id": "b",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge Two",
},
Object {
"block": "block-b",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-one",
},
"id": "c",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-b",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-two",
},
"id": "d",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge Two",
},
Object {
"block": "block-c",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block C",
"slug": "/super-block-one/block-c/challenge-one",
},
"id": "e",
"isPrivate": true,
"isRequired": false,
"superBlock": "Super Block One",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-one",
},
"id": "f",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge One",
},
Object {
"block": "block-a",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block A",
"slug": "/super-block-one/block-a/challenge-two",
},
"id": "g",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge Two",
},
Object {
"block": "block-b",
"dashedName": "challenge-one",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-one",
},
"id": "h",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge One",
},
Object {
"block": "block-b",
"dashedName": "challenge-two",
"fields": Object {
"blockName": "Block B",
"slug": "/super-block-one/block-b/challenge-two",
},
"id": "i",
"isPrivate": false,
"isRequired": false,
"superBlock": "Super Block Two",
"title": "Challenge Two",
},
]
}
superBlock="Super Block Two"
/>
<Spacer />
</ul>
</div>
</Col>
</Row>
`;

View File

@@ -7,7 +7,7 @@ import Adapter from 'enzyme-adapter-react-16';
import sinon from 'sinon';
import { Block } from './Block';
import mockNodes from '../../../__mocks__/map-nodes';
import mockChallengeNodes from '../../../__mocks__/challenge-nodes';
import mockIntroNodes from '../../../__mocks__/intro-nodes';
import mockCompleted from '../../../__mocks__/completedChallengesMock';
@@ -20,7 +20,7 @@ test('<Block /> not expanded snapshot', () => {
const componentToRender = (
<Block
blockDashedName='block-a'
challenges={mockNodes.filter(node => node.block === 'block-a')}
challenges={mockChallengeNodes.filter(node => node.block === 'block-a')}
completedChallenges={mockCompleted}
intro={mockIntroNodes[0]}
isExpanded={false}
@@ -39,7 +39,7 @@ test('<Block expanded snapshot', () => {
const componentToRender = (
<Block
blockDashedName='block-a'
challenges={mockNodes.filter(node => node.block === 'block-a')}
challenges={mockChallengeNodes.filter(node => node.block === 'block-a')}
completedChallenges={mockCompleted}
intro={mockIntroNodes[0]}
isExpanded={true}
@@ -58,7 +58,7 @@ test('<Block /> should handle toggle clicks correctly', () => {
const toggleMapSpy = sinon.spy();
const props = {
blockDashedName: 'block-a',
challenges: mockNodes.filter(node => node.block === 'block-a'),
challenges: mockChallengeNodes.filter(node => node.block === 'block-a'),
completedChallenges: mockCompleted,
intro: mockIntroNodes[0],
isExpanded: false,

View File

@@ -7,7 +7,7 @@ import Adapter from 'enzyme-adapter-react-16';
import sinon from 'sinon';
import { SuperBlock } from './SuperBlock';
import mockNodes from '../../../__mocks__/map-nodes';
import mockChallengeNodes from '../../../__mocks__/challenge-nodes';
import mockIntroNodes from '../../../__mocks__/intro-nodes';
Enzyme.configure({ adapter: new Adapter() });
@@ -18,7 +18,7 @@ test('<SuperBlock /> not expanded snapshot', () => {
const props = {
introNodes: mockIntroNodes,
isExpanded: false,
nodes: mockNodes,
nodes: mockChallengeNodes,
superBlock: 'Super Block One',
toggleSuperBlock: toggleSpy
};
@@ -33,7 +33,7 @@ test('<SuperBlock /> expanded snapshot', () => {
const props = {
introNodes: mockIntroNodes,
isExpanded: true,
nodes: mockNodes,
nodes: mockChallengeNodes,
superBlock: 'Super Block One',
toggleSuperBlock: toggleSpy
};
@@ -48,7 +48,7 @@ test('<SuperBlock should handle toggle clicks correctly', () => {
const props = {
introNodes: mockIntroNodes,
isExpanded: false,
nodes: mockNodes,
nodes: mockChallengeNodes,
superBlock: 'Super Block One',
toggleSuperBlock: toggleSpy
};

View File

@@ -1 +1,104 @@
export default from './Map.js';
import React, { Component } from 'react';
import { Row, Col } from '@freecodecamp/react-bootstrap';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
import uniq from 'lodash/uniq';
import { createSelector } from 'reselect';
import SuperBlock from './components/SuperBlock';
import Spacer from '../helpers/Spacer';
import './map.css';
import { ChallengeNode } from '../../redux/propTypes';
import { toggleSuperBlock, toggleBlock, resetExpansion } from './redux';
import { currentChallengeIdSelector } from '../../redux';
const propTypes = {
currentChallengeId: PropTypes.string,
introNodes: PropTypes.arrayOf(
PropTypes.shape({
fields: PropTypes.shape({ slug: PropTypes.string.isRequired }),
frontmatter: PropTypes.shape({
title: PropTypes.string.isRequired,
block: PropTypes.string.isRequired
})
})
),
nodes: PropTypes.arrayOf(ChallengeNode),
resetExpansion: PropTypes.func,
toggleBlock: PropTypes.func.isRequired,
toggleSuperBlock: PropTypes.func.isRequired
};
const mapStateToProps = state => {
return createSelector(
currentChallengeIdSelector,
currentChallengeId => ({
currentChallengeId
})
)(state);
};
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
resetExpansion,
toggleSuperBlock,
toggleBlock
},
dispatch
);
}
export class Map extends Component {
componentDidMount() {
this.initializeExpandedState(this.props.currentChallengeId);
}
initializeExpandedState(currentChallengeId) {
this.props.resetExpansion();
const { superBlock, block } = currentChallengeId
? this.props.nodes.find(node => node.id === currentChallengeId)
: this.props.nodes[0];
this.props.toggleBlock(block);
this.props.toggleSuperBlock(superBlock);
}
renderSuperBlocks(superBlocks) {
const { nodes, introNodes } = this.props;
return superBlocks.map(superBlock => (
<SuperBlock
introNodes={introNodes}
key={superBlock}
nodes={nodes}
superBlock={superBlock}
/>
));
}
render() {
const { nodes } = this.props;
const superBlocks = uniq(nodes.map(({ superBlock }) => superBlock));
return (
<Row>
<Col sm={10} smOffset={1} xs={12}>
<div className='map-ui'>
<ul>
{this.renderSuperBlocks(superBlocks)}
<Spacer />
</ul>
</div>
</Col>
</Row>
);
}
}
Map.displayName = 'Map';
Map.propTypes = propTypes;
export default connect(
mapStateToProps,
mapDispatchToProps
)(Map);

View File

@@ -1,27 +1,40 @@
/* global expect */
import React from 'react';
import renderer from 'react-test-renderer';
import ShallowRenderer from 'react-test-renderer/shallow';
import 'jest-dom/extend-expect';
import { IndexPage } from '../../pages';
import { LearnPage } from '../../pages/learn';
import Welcome from './';
import mockChallengeNodes from '../../__mocks__/challenge-nodes';
import mockIntroNodes from '../../__mocks__/intro-nodes';
describe('<Welcome />', () => {
it('renders when visiting index page and logged in', () => {
const container = renderer
.create(<IndexPage {...loggedInProps} />)
.toTree();
expect(container.rendered.type.displayName === 'Welcome').toBeTruthy();
const shallow = new ShallowRenderer();
shallow.render(<LearnPage {...loggedInProps} />);
const result = shallow.getRenderOutput();
expect(result.type.displayName === 'LearnLayout').toBeTruthy();
});
it('has four links', () => {
const container = renderer.create(<Welcome name={'developmentuser'} />)
it('has a header', () => {
const container = renderer.create(<Welcome name={'Development User'} />)
.root;
expect(container.findAllByType('a').length === 4).toBeTruthy();
expect(container.findAllByType('h1').length === 1).toBeTruthy();
});
it('has a blockquote', () => {
const container = renderer.create(<Welcome name={'Development User'} />)
.root;
expect(container.findAllByType('blockquote').length === 1).toBeTruthy();
});
});
const nodes = mockChallengeNodes.map(node => {
return { node };
});
const loggedInProps = {
fetchState: {
complete: true,
@@ -31,7 +44,17 @@ const loggedInProps = {
},
isSignedIn: true,
user: {
acceptedPrivacyTerms: true,
username: 'developmentuser'
name: 'Development User'
},
data: {
challengeNode: {
fields: {
slug:
// eslint-disable-next-line max-len
'/learn/responsive-web-design/basic-html-and-html5/say-hello-to-html-elements'
}
},
allChallengeNode: { edges: nodes },
allMarkdownRemark: { edges: [{ mdEdges: mockIntroNodes }] }
}
};

View File

@@ -1,9 +1,8 @@
import React, { Fragment } from 'react';
import { Grid, Row, Col } from '@freecodecamp/react-bootstrap';
import Helmet from 'react-helmet';
import { Row, Col } from '@freecodecamp/react-bootstrap';
import PropTypes from 'prop-types';
import { Spacer, Link } from '../helpers';
import { Spacer } from '../helpers';
import { randomQuote } from '../../utils/get-words';
import './welcome.css';
@@ -12,68 +11,35 @@ function Welcome({ name }) {
const { quote, author } = randomQuote();
return (
<Fragment>
<Helmet>
<title>Welcome | freeCodeCamp.org</title>
</Helmet>
<main>
<Grid>
<Row>
<Col sm={10} smOffset={1} xs={12}>
<Spacer />
<h1 className='text-center big-heading'>
Welcome {name ? name : 'Camper'}!
</h1>
</Col>
</Row>
<Row>
<Col sm={10} smOffset={1} xs={12}>
<Spacer />
<Row className='text-center quote-partial'>
<Col sm={10} smOffset={1} xs={12}>
<blockquote className='blockquote'>
<span>
<q>{quote}</q>
<footer className='quote-author blockquote-footer'>
<cite>{author}</cite>
</footer>
</span>
</blockquote>
</Col>
</Row>
<Row>
<Col sm={10} smOffset={1} xs={12}>
<Spacer />
<h2 className='text-center medium-heading'>
What would you like to do today?
</h2>
</Col>
</Row>
<h1 className='text-center big-heading'>
{name ? 'Welcome back ' + name : 'Welcome to freeCodeCamp.org'}
</h1>
</Col>
</Row>
<Spacer />
<Row className='text-center quote-partial'>
<Col sm={10} smOffset={1} xs={12}>
<blockquote className='blockquote'>
<span>
<q>{quote}</q>
<footer className='quote-author blockquote-footer'>
<cite>{author}</cite>
</footer>
</span>
</blockquote>
</Col>
</Row>
<Row>
<Col sm={10} smOffset={1} xs={12}>
<Spacer />
<Row>
<Col sm={10} smOffset={1} xs={12}>
<Link className='btn btn-lg btn-primary btn-block' to='/learn'>
Build Projects and Earn Certifications
</Link>
<Link className='btn btn-lg btn-primary btn-block' to='/settings'>
Update Your Developer Portfolio
</Link>
<Link
className='btn btn-lg btn-primary btn-block'
external={true}
to='/news'
>
Read Developer News
</Link>
<Link
className='btn btn-lg btn-primary btn-block'
external={true}
to='/forum'
>
Help Developers on the Forum
</Link>
</Col>
</Row>
<Spacer size={4} />
</Grid>
</main>
<h2 className='text-center medium-heading'>
What would you like to do today?
</h2>
</Col>
</Row>
</Fragment>
);
}