fix(projectCopmletion): Open completion modal for Project submission
This commit is contained in:
@ -1,19 +1,15 @@
|
|||||||
import { combineReducers } from 'berkeleys-redux-utils';
|
import { combineReducers } from 'berkeleys-redux-utils';
|
||||||
import { reducer as formReducer } from 'redux-form';
|
|
||||||
|
|
||||||
import app from './redux';
|
import app from './redux';
|
||||||
import entities from './entities';
|
import entities from './entities';
|
||||||
|
import form from './redux-form-reducer';
|
||||||
import map from './Map/redux';
|
import map from './Map/redux';
|
||||||
import nav from './Nav/redux';
|
import nav from './Nav/redux';
|
||||||
import routes from './routes/redux';
|
import routes from './routes/redux';
|
||||||
import toasts from './Toasts/redux';
|
import toasts from './Toasts/redux';
|
||||||
import files from './files';
|
import files from './files';
|
||||||
import flash from './Flash/redux';
|
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(
|
export default combineReducers(
|
||||||
app,
|
app,
|
||||||
@ -24,5 +20,5 @@ export default combineReducers(
|
|||||||
toasts,
|
toasts,
|
||||||
files,
|
files,
|
||||||
flash,
|
flash,
|
||||||
_formReducer
|
form
|
||||||
);
|
);
|
||||||
|
37
common/app/redux-form-reducer.js
Normal file
37
common/app/redux-form-reducer.js
Normal file
@ -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 {
|
import {
|
||||||
backendFormValuesSelector,
|
backendFormValuesSelector,
|
||||||
|
frontendProjectFormValuesSelector,
|
||||||
|
backendProjectFormValuesSelector,
|
||||||
challengeMetaSelector,
|
challengeMetaSelector,
|
||||||
moveToNextChallenge,
|
moveToNextChallenge,
|
||||||
submitChallengeComplete,
|
submitChallengeComplete,
|
||||||
testsSelector,
|
testsSelector,
|
||||||
types
|
types,
|
||||||
|
closeChallengeModal
|
||||||
} from './';
|
} from './';
|
||||||
|
|
||||||
import {
|
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 { id, challengeType } = challengeSelector(state);
|
||||||
const { username } = userSelector(state);
|
const { username } = userSelector(state);
|
||||||
const csrfToken = csrfSelector(state);
|
const csrfToken = csrfSelector(state);
|
||||||
@ -77,11 +91,16 @@ function submitProject(type, state, { solution, githubLink }) {
|
|||||||
if (challengeType === backEndProject) {
|
if (challengeType === backEndProject) {
|
||||||
challengeInfo.githubLink = githubLink;
|
challengeInfo.githubLink = githubLink;
|
||||||
}
|
}
|
||||||
return postChallenge(
|
return Observable.merge(
|
||||||
|
postChallenge(
|
||||||
'/project-completed',
|
'/project-completed',
|
||||||
username,
|
username,
|
||||||
csrfToken,
|
csrfToken,
|
||||||
challengeInfo
|
challengeInfo
|
||||||
|
),
|
||||||
|
Observable.of(
|
||||||
|
closeChallengeModal()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,7 @@ export const types = createTypes([
|
|||||||
'updateHint',
|
'updateHint',
|
||||||
'unlockUntrustedCode',
|
'unlockUntrustedCode',
|
||||||
'closeChallengeModal',
|
'closeChallengeModal',
|
||||||
|
'openChallengeModal',
|
||||||
'updateSuccessMessage',
|
'updateSuccessMessage',
|
||||||
// |- modern
|
// |- modern
|
||||||
'modernEditorUpdated',
|
'modernEditorUpdated',
|
||||||
@ -119,6 +120,7 @@ export const modernEditorUpdated = createAction(
|
|||||||
);
|
);
|
||||||
// challenges
|
// challenges
|
||||||
export const closeChallengeModal = createAction(types.closeChallengeModal);
|
export const closeChallengeModal = createAction(types.closeChallengeModal);
|
||||||
|
export const openChallengeModal = createAction(types.openChallengeModal);
|
||||||
export const updateHint = createAction(types.updateHint);
|
export const updateHint = createAction(types.updateHint);
|
||||||
export const unlockUntrustedCode = createAction(
|
export const unlockUntrustedCode = createAction(
|
||||||
types.unlockUntrustedCode,
|
types.unlockUntrustedCode,
|
||||||
@ -258,6 +260,10 @@ export const challengeTemplateSelector = state =>
|
|||||||
|
|
||||||
export const backendFormValuesSelector = state =>
|
export const backendFormValuesSelector = state =>
|
||||||
getValues(state.form.BackEndChallenge);
|
getValues(state.form.BackEndChallenge);
|
||||||
|
export const frontendProjectFormValuesSelector = state =>
|
||||||
|
getValues(state.form.NewFrontEndProject) || {};
|
||||||
|
export const backendProjectFormValuesSelector = state =>
|
||||||
|
getValues(state.form.NewBackEndProject) || {};
|
||||||
|
|
||||||
export default combineReducers(
|
export default combineReducers(
|
||||||
handleActions(
|
handleActions(
|
||||||
@ -286,6 +292,10 @@ export default combineReducers(
|
|||||||
tests.every(test => test.pass && !test.err)
|
tests.every(test => test.pass && !test.err)
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
[types.openChallengeModal]: state => ({
|
||||||
|
...state,
|
||||||
|
isChallengeModalOpen: true
|
||||||
|
}),
|
||||||
[types.closeChallengeModal]: state => ({
|
[types.closeChallengeModal]: state => ({
|
||||||
...state,
|
...state,
|
||||||
isChallengeModalOpen: false
|
isChallengeModalOpen: false
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
|
|
||||||
import { showProjectSubmit } from './redux';
|
import { showProjectSubmit } from './redux';
|
||||||
import SolutionInput from '../../Solution-Input.jsx';
|
import SolutionInput from '../../Solution-Input.jsx';
|
||||||
import { submitChallenge } from '../../redux';
|
import { openChallengeModal } from '../../redux';
|
||||||
import {
|
import {
|
||||||
isValidURL,
|
isValidURL,
|
||||||
makeRequired,
|
makeRequired,
|
||||||
@ -22,13 +22,14 @@ const propTypes = {
|
|||||||
handleSubmit: PropTypes.func,
|
handleSubmit: PropTypes.func,
|
||||||
isSignedIn: PropTypes.bool,
|
isSignedIn: PropTypes.bool,
|
||||||
isSubmitting: PropTypes.bool,
|
isSubmitting: PropTypes.bool,
|
||||||
|
openChallengeModal: PropTypes.func.isRequired,
|
||||||
resetForm: PropTypes.func,
|
resetForm: PropTypes.func,
|
||||||
showProjectSubmit: PropTypes.func,
|
showProjectSubmit: PropTypes.func,
|
||||||
submitChallenge: PropTypes.func
|
submitChallenge: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
const bindableActions = {
|
const bindableActions = {
|
||||||
submitChallenge,
|
openChallengeModal,
|
||||||
showProjectSubmit
|
showProjectSubmit
|
||||||
};
|
};
|
||||||
const frontEndFields = [ 'solution' ];
|
const frontEndFields = [ 'solution' ];
|
||||||
@ -49,8 +50,7 @@ const backEndFieldValidators = {
|
|||||||
export function _FrontEndForm({
|
export function _FrontEndForm({
|
||||||
fields,
|
fields,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
submitChallenge,
|
openChallengeModal,
|
||||||
resetForm,
|
|
||||||
isSubmitting,
|
isSubmitting,
|
||||||
showProjectSubmit
|
showProjectSubmit
|
||||||
}) {
|
}) {
|
||||||
@ -60,12 +60,7 @@ export function _FrontEndForm({
|
|||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
name='NewFrontEndProject'
|
name='NewFrontEndProject'
|
||||||
onSubmit={
|
onSubmit={ handleSubmit(openChallengeModal) }
|
||||||
handleSubmit((value) => {
|
|
||||||
submitChallenge(value);
|
|
||||||
resetForm('NewFrontEndProject');
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
isSubmitting ?
|
isSubmitting ?
|
||||||
@ -103,8 +98,7 @@ export const FrontEndForm = reduxForm(
|
|||||||
export function _BackEndForm({
|
export function _BackEndForm({
|
||||||
fields: { solution, githubLink },
|
fields: { solution, githubLink },
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
submitChallenge,
|
openChallengeModal,
|
||||||
resetForm,
|
|
||||||
isSubmitting,
|
isSubmitting,
|
||||||
showProjectSubmit
|
showProjectSubmit
|
||||||
}) {
|
}) {
|
||||||
@ -114,12 +108,7 @@ export function _BackEndForm({
|
|||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
name='NewBackEndProject'
|
name='NewBackEndProject'
|
||||||
onSubmit={
|
onSubmit={ handleSubmit(openChallengeModal) }
|
||||||
handleSubmit((values) => {
|
|
||||||
submitChallenge(values);
|
|
||||||
resetForm('NewBackEndProject');
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
isSubmitting ?
|
isSubmitting ?
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
import { submittingSelector } from './redux';
|
import { submittingSelector } from './redux';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
submitChallenge,
|
openChallengeModal,
|
||||||
|
|
||||||
openHelpModal,
|
openHelpModal,
|
||||||
chatRoomSelector,
|
chatRoomSelector,
|
||||||
@ -35,12 +35,12 @@ const propTypes = {
|
|||||||
isSignedIn: PropTypes.bool,
|
isSignedIn: PropTypes.bool,
|
||||||
isSimple: PropTypes.bool,
|
isSimple: PropTypes.bool,
|
||||||
isSubmitting: PropTypes.bool,
|
isSubmitting: PropTypes.bool,
|
||||||
openHelpModal: PropTypes.func.isRequired,
|
openChallengeModal: PropTypes.func.isRequired,
|
||||||
submitChallenge: PropTypes.func.isRequired
|
openHelpModal: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
openHelpModal,
|
openChallengeModal,
|
||||||
submitChallenge
|
openHelpModal
|
||||||
};
|
};
|
||||||
const mapStateToProps = createSelector(
|
const mapStateToProps = createSelector(
|
||||||
challengeSelector,
|
challengeSelector,
|
||||||
@ -65,7 +65,7 @@ const mapStateToProps = createSelector(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export class ToolPanel extends PureComponent {
|
export class ToolPanel extends PureComponent {
|
||||||
renderSubmitButton(isSignedIn, submitChallenge) {
|
renderSubmitButton(isSignedIn, openChallengeModal) {
|
||||||
const buttonCopy = isSignedIn ?
|
const buttonCopy = isSignedIn ?
|
||||||
'Submit and go to my next challenge' :
|
'Submit and go to my next challenge' :
|
||||||
"I've completed this challenge";
|
"I've completed this challenge";
|
||||||
@ -74,7 +74,7 @@ export class ToolPanel extends PureComponent {
|
|||||||
block={ true }
|
block={ true }
|
||||||
bsStyle='primary'
|
bsStyle='primary'
|
||||||
className='btn-big'
|
className='btn-big'
|
||||||
onClick={ submitChallenge }
|
onClick={ openChallengeModal }
|
||||||
>
|
>
|
||||||
{ buttonCopy } (ctrl + enter)
|
{ buttonCopy } (ctrl + enter)
|
||||||
</Button>
|
</Button>
|
||||||
@ -90,7 +90,7 @@ export class ToolPanel extends PureComponent {
|
|||||||
isSignedIn,
|
isSignedIn,
|
||||||
isSubmitting,
|
isSubmitting,
|
||||||
openHelpModal,
|
openHelpModal,
|
||||||
submitChallenge
|
openChallengeModal
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const FormElement = isFrontEnd ? FrontEndForm : BackEndForm;
|
const FormElement = isFrontEnd ? FrontEndForm : BackEndForm;
|
||||||
@ -98,7 +98,7 @@ export class ToolPanel extends PureComponent {
|
|||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
isSimple ?
|
isSimple ?
|
||||||
this.renderSubmitButton(isSignedIn, submitChallenge) :
|
this.renderSubmitButton(isSignedIn, openChallengeModal) :
|
||||||
<FormElement isSubmitting={ isSubmitting }/>
|
<FormElement isSubmitting={ isSubmitting }/>
|
||||||
}
|
}
|
||||||
<div className='button-spacer' />
|
<div className='button-spacer' />
|
||||||
|
Reference in New Issue
Block a user