Feat: Download Solution Button (#191)

* fix: increase spacing in challenge list (#96)

* enh: add button to download user solution on completion modal

* fix: linting

* review: remove dashedName grab from Show.js

can generate dashedName in CompletionModal from challengeMeta

* review: generate download file dashedName from challengeMeta.title

* add className btn-primary-invert

* review: shape files data

we only want key indexhtml contents from files

* review: remove class already defined in global.css

* review: further changes

only grab title from challenge meta
change fiels prop-type to object
remove duplicate class btn-primary-invert from CompletionModal.css
generate download file name using util function dasherize

* review: only show download button if there is something to download

* fix: increase spacing in challenge list (#96)
This commit is contained in:
Stuart Taylor
2018-07-06 10:45:08 +01:00
committed by Mrugesh Mohapatra
parent 00ce364692
commit d8bee6a7ad
3 changed files with 44 additions and 6 deletions

View File

@ -8,19 +8,27 @@ import { Button, Modal } from 'react-bootstrap';
import ga from '../../../analytics';
import GreenPass from './icons/GreenPass';
import { dasherize } from '../../../../utils';
import './completion-modal.css';
import {
closeModal,
submitChallenge,
isCompletionModalOpenSelector,
successMessageSelector
successMessageSelector,
challengeFilesSelector,
challengeMetaSelector
} from '../redux';
const mapStateToProps = createSelector(
challengeFilesSelector,
challengeMetaSelector,
isCompletionModalOpenSelector,
successMessageSelector,
(isOpen, message) => ({
(files, { title }, isOpen, message) => ({
files,
title,
isOpen,
message
})
@ -43,10 +51,12 @@ const mapDispatchToProps = function(dispatch) {
const propTypes = {
close: PropTypes.func.isRequired,
files: PropTypes.object.isRequired,
handleKeypress: PropTypes.func.isRequired,
isOpen: PropTypes.bool,
message: PropTypes.string,
submitChallenge: PropTypes.func.isRequired
submitChallenge: PropTypes.func.isRequired,
title: PropTypes.string
};
export class CompletionModal extends PureComponent {
@ -56,11 +66,21 @@ export class CompletionModal extends PureComponent {
isOpen,
submitChallenge,
handleKeypress,
message
message,
files = {},
title
} = this.props;
if (isOpen) {
ga.modalview('/completion-modal');
}
const showDownloadButton = Object.keys(files).length;
const filesForDownload = Object.keys(files)
.map(key => files[key])
.reduce((allFiles, { path, contents }) => ({
...allFiles,
[path]: contents
}), {});
const dashedName = dasherize(title);
return (
<Modal
animation={false}
@ -91,6 +111,21 @@ export class CompletionModal extends PureComponent {
>
Submit and go to next challenge (Ctrl + Enter)
</Button>
{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
}
</Modal.Footer>
</Modal>
);

View File

@ -9,4 +9,3 @@
height: 30vh;
width: 30vh;
}

View File

@ -2,6 +2,10 @@
margin-top: 1.45rem;
}
.intro-toc .list-group-item {
margin: 5px auto;
}
.intro-toc .list-group-item:hover {
background-color: #eee;
}
@ -10,4 +14,4 @@
text-decoration: none;
text-decoration-style: none;
color: #006400;
}
}