Files
freeCodeCamp/client/src/templates/Challenges/components/CompletionModal.js

141 lines
3.6 KiB
JavaScript
Raw Normal View History

2018-04-06 14:51:52 +01:00
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import noop from 'lodash/noop';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { Button, Modal } from '@freecodecamp/react-bootstrap';
2018-04-06 14:51:52 +01:00
import ga from '../../../analytics';
import GreenPass from './icons/GreenPass';
2018-04-06 14:51:52 +01:00
import { dasherize } from '../../../../utils';
import './completion-modal.css';
2018-04-06 14:51:52 +01:00
import {
closeModal,
submitChallenge,
isCompletionModalOpenSelector,
successMessageSelector,
challengeFilesSelector,
challengeMetaSelector
} from '../redux';
2018-04-06 14:51:52 +01:00
const mapStateToProps = createSelector(
challengeFilesSelector,
challengeMetaSelector,
2018-04-06 14:51:52 +01:00
isCompletionModalOpenSelector,
successMessageSelector,
(files, { title }, isOpen, message) => ({
files,
title,
2018-04-06 14:51:52 +01:00
isOpen,
message
})
);
const mapDispatchToProps = function(dispatch) {
const dispatchers = {
close: () => dispatch(closeModal('completion')),
handleKeypress: e => {
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {
dispatch(submitChallenge());
}
},
submitChallenge: () => {
dispatch(submitChallenge());
}
};
return () => dispatchers;
};
const propTypes = {
close: PropTypes.func.isRequired,
files: PropTypes.object.isRequired,
2018-04-06 14:51:52 +01:00
handleKeypress: PropTypes.func.isRequired,
isOpen: PropTypes.bool,
message: PropTypes.string,
submitChallenge: PropTypes.func.isRequired,
title: PropTypes.string
2018-04-06 14:51:52 +01:00
};
export class CompletionModal extends PureComponent {
render() {
const {
close,
isOpen,
submitChallenge,
handleKeypress,
message,
files = {},
title
2018-04-06 14:51:52 +01:00
} = this.props;
if (isOpen) {
ga.modalview('/completion-modal');
}
const showDownloadButton = Object.keys(files).length;
const filesForDownload = Object.keys(files)
.map(key => files[key])
2018-09-13 22:09:12 +03:00
.reduce(
(allFiles, { path, contents }) => ({
...allFiles,
[path]: contents
}),
{}
);
const dashedName = dasherize(title);
2018-04-06 14:51:52 +01:00
return (
<Modal
animation={false}
bsSize='lg'
dialogClassName='challenge-success-modal'
2018-04-06 14:51:52 +01:00
keyboard={true}
onHide={close}
onKeyDown={isOpen ? handleKeypress : noop}
show={isOpen}
>
<Modal.Header
className='challenge-list-header fcc-modal'
closeButton={true}
>
<Modal.Title className='text-center'>{message}</Modal.Title>
2018-04-06 14:51:52 +01:00
</Modal.Header>
<Modal.Body className='completion-modal-body'>
<div className='success-icon-wrapper'>
<GreenPass />
2018-04-06 14:51:52 +01:00
</div>
</Modal.Body>
<Modal.Footer>
<Button
block={true}
bsSize='large'
bsStyle='primary'
onClick={submitChallenge}
>
Submit and go to next challenge (Ctrl + Enter)
</Button>
2018-09-13 22:09:12 +03:00
{showDownloadButton ? (
<Button
block={true}
bsSize='lg'
bsStyle='primary'
className='btn-primary-invert'
download={`${dashedName}.json`}
href={`data:text/json;charset=utf-8,${encodeURIComponent(
JSON.stringify(filesForDownload)
)}`}
>
Download my solution
</Button>
) : null}
2018-04-06 14:51:52 +01:00
</Modal.Footer>
</Modal>
);
}
}
CompletionModal.displayName = 'CompletionModal';
CompletionModal.propTypes = propTypes;
export default connect(mapStateToProps, mapDispatchToProps)(CompletionModal);