diff --git a/common/static/common/js/components/BlockBrowser/data/reducers/index.js b/common/static/common/js/components/BlockBrowser/data/reducers/index.js index 7d14e63052cd..365e9153edd5 100644 --- a/common/static/common/js/components/BlockBrowser/data/reducers/index.js +++ b/common/static/common/js/components/BlockBrowser/data/reducers/index.js @@ -18,7 +18,7 @@ export const buildBlockTree = (blocks, excludeBlockTypes) => { return blockTree(blocks.root, null); }; -const blocks = (state = {}, action) => { +export const blocks = (state = {}, action) => { switch (action.type) { case courseBlocksActions.fetch.SUCCESS: return buildBlockTree(action.blocks, action.excludeBlockTypes); @@ -27,7 +27,7 @@ const blocks = (state = {}, action) => { } }; -const selectedBlock = (state = null, action) => { +export const selectedBlock = (state = null, action) => { switch (action.type) { case courseBlocksActions.SELECT_BLOCK: return action.blockId; @@ -37,7 +37,7 @@ const selectedBlock = (state = null, action) => { }; -const rootBlock = (state = null, action) => { +export const rootBlock = (state = null, action) => { switch (action.type) { case courseBlocksActions.fetch.SUCCESS: return action.blocks.root; diff --git a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/.eslintrc.js b/lms/djangoapps/instructor/static/instructor/.eslintrc.js similarity index 100% rename from lms/djangoapps/instructor/static/instructor/ProblemBrowser/.eslintrc.js rename to lms/djangoapps/instructor/static/instructor/.eslintrc.js diff --git a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/Main.jsx b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/Main.jsx index aca0041c9948..bbc7c8efeebb 100644 --- a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/Main.jsx +++ b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/Main.jsx @@ -1,15 +1,20 @@ /* global gettext */ import { Button } from '@edx/paragon'; -import { BlockBrowser } from 'BlockBrowser'; +import BlockBrowserContainer from 'BlockBrowser/components/BlockBrowser/BlockBrowserContainer'; import * as PropTypes from 'prop-types'; import * as React from 'react'; +import { PopupModalContainer } from '../Popup/PopupModalContainer'; export default class Main extends React.Component { constructor(props) { super(props); this.handleToggleDropdown = this.handleToggleDropdown.bind(this); + this.showPopup = this.showPopup.bind(this); + this.hidePopup = this.hidePopup.bind(this); this.state = { + popupOpen: false, showDropdown: false, + taskForBlock: null, }; } @@ -22,19 +27,51 @@ export default class Main extends React.Component { this.setState({ showDropdown: false }); } + showPopup() { + if (this.state.taskForBlock !== this.props.selectedBlock) { + this.props.createProblemResponsesReportTask( + this.props.initialEndpoint, + this.props.taskStatusEndpoint, + this.props.selectedBlock, + ); + } + this.setState({ popupOpen: true, taskForBlock: this.props.selectedBlock }); + } + + hidePopup() { + if (this.props.timeout != null) { + clearTimeout(this.props.timeout); + } + this.setState({ popupOpen: false, taskForBlock: null }); + this.props.resetProblemResponsesReportTask(); + } + render() { const { selectedBlock, onSelectBlock } = this.props; return (
-
); } @@ -42,13 +79,19 @@ export default class Main extends React.Component { Main.propTypes = { courseId: PropTypes.string.isRequired, + createProblemResponsesReportTask: PropTypes.func.isRequired, excludeBlockTypes: PropTypes.arrayOf(PropTypes.string), fetchCourseBlocks: PropTypes.func.isRequired, + initialEndpoint: PropTypes.string.isRequired, onSelectBlock: PropTypes.func.isRequired, selectedBlock: PropTypes.string, + resetProblemResponsesReportTask: PropTypes.func.isRequired, + taskStatusEndpoint: PropTypes.string.isRequired, + timeout: PropTypes.number, }; Main.defaultProps = { excludeBlockTypes: null, selectedBlock: null, + timeout: null, }; diff --git a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/MainContainer.jsx b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/MainContainer.jsx index a36b31978be9..6257b7130f70 100644 --- a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/MainContainer.jsx +++ b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Main/MainContainer.jsx @@ -1,17 +1,25 @@ import { fetchCourseBlocks, selectBlock } from 'BlockBrowser/data/actions/courseBlocks'; import { connect } from 'react-redux'; - +import { createProblemResponsesReportTask, reset } from '../../data/actions/problemResponses'; import Main from './Main'; const mapStateToProps = state => ({ selectedBlock: state.selectedBlock, + timeout: state.popupTask.timeout, }); const mapDispatchToProps = dispatch => ({ onSelectBlock: blockId => dispatch(selectBlock(blockId)), - fetchCourseBlocks: (courseId, excludeBlockTypes) => - dispatch(fetchCourseBlocks(courseId, excludeBlockTypes)), + fetchCourseBlocks: + (courseId, excludeBlockTypes) => + dispatch(fetchCourseBlocks(courseId, excludeBlockTypes)), + createProblemResponsesReportTask: + (initialEndpoint, taskStatusEndpoint, problemLocation) => + dispatch( + createProblemResponsesReportTask(initialEndpoint, taskStatusEndpoint, problemLocation), + ), + resetProblemResponsesReportTask: () => dispatch(reset), }); const MainContainer = connect( diff --git a/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Popup/PopupModal.jsx b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Popup/PopupModal.jsx new file mode 100644 index 000000000000..691e92c6fe79 --- /dev/null +++ b/lms/djangoapps/instructor/static/instructor/ProblemBrowser/components/Popup/PopupModal.jsx @@ -0,0 +1,82 @@ +/* global gettext */ +import { Button, Modal } from '@edx/paragon/static'; +import * as classNames from 'classnames'; +import * as PropTypes from 'prop-types'; +import * as React from 'react'; + +const PopupModal = ({ open, onHide, message, error, succeeded, reportPath, reportPreview }) => { + const previewButton = ( +