Merge pull request #16796 from Bouncey/feat/completionModalProjects
fix(projectCompletion): Open completion modal for Project submissionpull/16831/merge
commit
23d9ceb399
|
@ -1,19 +1,15 @@
|
|||
import { combineReducers } from 'berkeleys-redux-utils';
|
||||
import { reducer as formReducer } from 'redux-form';
|
||||
|
||||
import app from './redux';
|
||||
import entities from './entities';
|
||||
import form from './redux-form-reducer';
|
||||
import map from './Map/redux';
|
||||
import nav from './Nav/redux';
|
||||
import routes from './routes/redux';
|
||||
import toasts from './Toasts/redux';
|
||||
import files from './files';
|
||||
import flash from './Flash/redux';
|
||||
// not ideal but should go away once we move to react-redux-form
|
||||
import { projectNormalizer } from './routes/Challenges/redux';
|
||||
|
||||
const _formReducer = formReducer.normalize({ ...projectNormalizer });
|
||||
_formReducer.toString = () => 'form';
|
||||
|
||||
export default combineReducers(
|
||||
app,
|
||||
|
@ -24,5 +20,5 @@ export default combineReducers(
|
|||
toasts,
|
||||
files,
|
||||
flash,
|
||||
_formReducer
|
||||
form
|
||||
);
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import { composeReducers } from 'berkeleys-redux-utils';
|
||||
import { reducer as formReducer } from 'redux-form';
|
||||
|
||||
import {
|
||||
projectNormalizer,
|
||||
types as challenge
|
||||
} from './routes/Challenges/redux';
|
||||
|
||||
const normailizedFormReducer = formReducer.normalize({ ...projectNormalizer });
|
||||
|
||||
const pluggedInFormReducer = formReducer.plugin({
|
||||
NewFrontEndProject: (state, action) => {
|
||||
if (action.type === challenge.moveToNextChallenge) {
|
||||
return {
|
||||
...state,
|
||||
solution: {}
|
||||
};
|
||||
}
|
||||
return state;
|
||||
},
|
||||
NewBackEndProject: (state, action) => {
|
||||
if (action.type === challenge.moveToNextChallenge) {
|
||||
return {
|
||||
...state,
|
||||
solution: {},
|
||||
githubLink: {}
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
||||
});
|
||||
|
||||
export default composeReducers(
|
||||
'form',
|
||||
normailizedFormReducer,
|
||||
pluggedInFormReducer
|
||||
);
|
|
@ -3,11 +3,14 @@ import { ofType } from 'redux-epic';
|
|||
|
||||
import {
|
||||
backendFormValuesSelector,
|
||||
frontendProjectFormValuesSelector,
|
||||
backendProjectFormValuesSelector,
|
||||
challengeMetaSelector,
|
||||
moveToNextChallenge,
|
||||
submitChallengeComplete,
|
||||
testsSelector,
|
||||
types
|
||||
types,
|
||||
closeChallengeModal
|
||||
} from './';
|
||||
|
||||
import {
|
||||
|
@ -69,7 +72,18 @@ function submitModern(type, state) {
|
|||
);
|
||||
}
|
||||
|
||||
function submitProject(type, state, { solution, githubLink }) {
|
||||
function submitProject(type, state) {
|
||||
if (type === types.checkChallenge) {
|
||||
return Observable.empty();
|
||||
}
|
||||
const {
|
||||
solution: frontEndSolution = ''
|
||||
} = frontendProjectFormValuesSelector(state);
|
||||
const {
|
||||
solution: backendSolution = '',
|
||||
githubLink = ''
|
||||
} = backendProjectFormValuesSelector(state);
|
||||
const solution = frontEndSolution ? frontEndSolution : backendSolution;
|
||||
const { id, challengeType } = challengeSelector(state);
|
||||
const { username } = userSelector(state);
|
||||
const csrfToken = csrfSelector(state);
|
||||
|
@ -77,11 +91,16 @@ function submitProject(type, state, { solution, githubLink }) {
|
|||
if (challengeType === backEndProject) {
|
||||
challengeInfo.githubLink = githubLink;
|
||||
}
|
||||
return postChallenge(
|
||||
'/project-completed',
|
||||
username,
|
||||
csrfToken,
|
||||
challengeInfo
|
||||
return Observable.merge(
|
||||
postChallenge(
|
||||
'/project-completed',
|
||||
username,
|
||||
csrfToken,
|
||||
challengeInfo
|
||||
),
|
||||
Observable.of(
|
||||
closeChallengeModal()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ export const types = createTypes([
|
|||
'updateHint',
|
||||
'unlockUntrustedCode',
|
||||
'closeChallengeModal',
|
||||
'openChallengeModal',
|
||||
'updateSuccessMessage',
|
||||
// |- modern
|
||||
'modernEditorUpdated',
|
||||
|
@ -119,6 +120,7 @@ export const modernEditorUpdated = createAction(
|
|||
);
|
||||
// challenges
|
||||
export const closeChallengeModal = createAction(types.closeChallengeModal);
|
||||
export const openChallengeModal = createAction(types.openChallengeModal);
|
||||
export const updateHint = createAction(types.updateHint);
|
||||
export const unlockUntrustedCode = createAction(
|
||||
types.unlockUntrustedCode,
|
||||
|
@ -258,6 +260,10 @@ export const challengeTemplateSelector = state =>
|
|||
|
||||
export const backendFormValuesSelector = state =>
|
||||
getValues(state.form.BackEndChallenge);
|
||||
export const frontendProjectFormValuesSelector = state =>
|
||||
getValues(state.form.NewFrontEndProject) || {};
|
||||
export const backendProjectFormValuesSelector = state =>
|
||||
getValues(state.form.NewBackEndProject) || {};
|
||||
|
||||
export default combineReducers(
|
||||
handleActions(
|
||||
|
@ -286,6 +292,10 @@ export default combineReducers(
|
|||
tests.every(test => test.pass && !test.err)
|
||||
)
|
||||
}),
|
||||
[types.openChallengeModal]: state => ({
|
||||
...state,
|
||||
isChallengeModalOpen: true
|
||||
}),
|
||||
[types.closeChallengeModal]: state => ({
|
||||
...state,
|
||||
isChallengeModalOpen: false
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
|
||||
import { showProjectSubmit } from './redux';
|
||||
import SolutionInput from '../../Solution-Input.jsx';
|
||||
import { submitChallenge } from '../../redux';
|
||||
import { openChallengeModal } from '../../redux';
|
||||
import {
|
||||
isValidURL,
|
||||
makeRequired,
|
||||
|
@ -22,13 +22,14 @@ const propTypes = {
|
|||
handleSubmit: PropTypes.func,
|
||||
isSignedIn: PropTypes.bool,
|
||||
isSubmitting: PropTypes.bool,
|
||||
openChallengeModal: PropTypes.func.isRequired,
|
||||
resetForm: PropTypes.func,
|
||||
showProjectSubmit: PropTypes.func,
|
||||
submitChallenge: PropTypes.func
|
||||
};
|
||||
|
||||
const bindableActions = {
|
||||
submitChallenge,
|
||||
openChallengeModal,
|
||||
showProjectSubmit
|
||||
};
|
||||
const frontEndFields = [ 'solution' ];
|
||||
|
@ -49,8 +50,7 @@ const backEndFieldValidators = {
|
|||
export function _FrontEndForm({
|
||||
fields,
|
||||
handleSubmit,
|
||||
submitChallenge,
|
||||
resetForm,
|
||||
openChallengeModal,
|
||||
isSubmitting,
|
||||
showProjectSubmit
|
||||
}) {
|
||||
|
@ -60,12 +60,7 @@ export function _FrontEndForm({
|
|||
return (
|
||||
<form
|
||||
name='NewFrontEndProject'
|
||||
onSubmit={
|
||||
handleSubmit((value) => {
|
||||
submitChallenge(value);
|
||||
resetForm('NewFrontEndProject');
|
||||
})
|
||||
}
|
||||
onSubmit={ handleSubmit(openChallengeModal) }
|
||||
>
|
||||
{
|
||||
isSubmitting ?
|
||||
|
@ -103,8 +98,7 @@ export const FrontEndForm = reduxForm(
|
|||
export function _BackEndForm({
|
||||
fields: { solution, githubLink },
|
||||
handleSubmit,
|
||||
submitChallenge,
|
||||
resetForm,
|
||||
openChallengeModal,
|
||||
isSubmitting,
|
||||
showProjectSubmit
|
||||
}) {
|
||||
|
@ -114,12 +108,7 @@ export function _BackEndForm({
|
|||
return (
|
||||
<form
|
||||
name='NewBackEndProject'
|
||||
onSubmit={
|
||||
handleSubmit((values) => {
|
||||
submitChallenge(values);
|
||||
resetForm('NewBackEndProject');
|
||||
})
|
||||
}
|
||||
onSubmit={ handleSubmit(openChallengeModal) }
|
||||
>
|
||||
{
|
||||
isSubmitting ?
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
import { submittingSelector } from './redux';
|
||||
|
||||
import {
|
||||
submitChallenge,
|
||||
openChallengeModal,
|
||||
|
||||
openHelpModal,
|
||||
chatRoomSelector,
|
||||
|
@ -36,12 +36,12 @@ const propTypes = {
|
|||
isSignedIn: PropTypes.bool,
|
||||
isSimple: PropTypes.bool,
|
||||
isSubmitting: PropTypes.bool,
|
||||
openHelpModal: PropTypes.func.isRequired,
|
||||
submitChallenge: PropTypes.func.isRequired
|
||||
openChallengeModal: PropTypes.func.isRequired,
|
||||
openHelpModal: PropTypes.func.isRequired
|
||||
};
|
||||
const mapDispatchToProps = {
|
||||
openHelpModal,
|
||||
submitChallenge
|
||||
openChallengeModal,
|
||||
openHelpModal
|
||||
};
|
||||
const mapStateToProps = createSelector(
|
||||
challengeSelector,
|
||||
|
@ -66,7 +66,7 @@ const mapStateToProps = createSelector(
|
|||
);
|
||||
|
||||
export class ToolPanel extends PureComponent {
|
||||
renderSubmitButton(isSignedIn, submitChallenge) {
|
||||
renderSubmitButton(isSignedIn, openChallengeModal) {
|
||||
const buttonCopy = isSignedIn ?
|
||||
'Submit and go to my next challenge' :
|
||||
"I've completed this challenge";
|
||||
|
@ -75,7 +75,7 @@ export class ToolPanel extends PureComponent {
|
|||
block={ true }
|
||||
bsStyle='primary'
|
||||
className='btn-big'
|
||||
onClick={ submitChallenge }
|
||||
onClick={ openChallengeModal }
|
||||
>
|
||||
{ buttonCopy } (ctrl + enter)
|
||||
</Button>
|
||||
|
@ -91,7 +91,7 @@ export class ToolPanel extends PureComponent {
|
|||
isSignedIn,
|
||||
isSubmitting,
|
||||
openHelpModal,
|
||||
submitChallenge
|
||||
openChallengeModal
|
||||
} = this.props;
|
||||
|
||||
const FormElement = isFrontEnd ? FrontEndForm : BackEndForm;
|
||||
|
@ -99,7 +99,7 @@ export class ToolPanel extends PureComponent {
|
|||
<div>
|
||||
{
|
||||
isSimple ?
|
||||
this.renderSubmitButton(isSignedIn, submitChallenge) :
|
||||
this.renderSubmitButton(isSignedIn, openChallengeModal) :
|
||||
<FormElement isSubmitting={ isSubmitting }/>
|
||||
}
|
||||
<ButtonSpacer />
|
||||
|
|
Loading…
Reference in New Issue