fix(client):format url values on form submit
This commit is contained in:
@ -2,7 +2,12 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { reduxForm } from 'redux-form';
|
import { reduxForm } from 'redux-form';
|
||||||
|
|
||||||
import { FormFields, BlockSaveButton, BlockSaveWrapper } from './';
|
import {
|
||||||
|
FormFields,
|
||||||
|
BlockSaveButton,
|
||||||
|
BlockSaveWrapper,
|
||||||
|
formatUrlValues
|
||||||
|
} from './';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
buttonText: PropTypes.string,
|
buttonText: PropTypes.string,
|
||||||
@ -48,7 +53,9 @@ export function DynamicForm({
|
|||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
id={`dynamic-${id}`}
|
id={`dynamic-${id}`}
|
||||||
onSubmit={handleSubmit(submit)}
|
onSubmit={handleSubmit((values, ...args) =>
|
||||||
|
submit(formatUrlValues(values, options), ...args)
|
||||||
|
)}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
>
|
>
|
||||||
<FormFields
|
<FormFields
|
||||||
|
@ -15,6 +15,16 @@ export function callIfDefined(fn) {
|
|||||||
return value => (value ? fn(value) : value);
|
return value => (value ? fn(value) : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatUrlValues(values, options) {
|
||||||
|
return Object.keys(values).reduce((result, key) => {
|
||||||
|
let value = values[key];
|
||||||
|
if (options.types[key] === 'url') {
|
||||||
|
value = normalizeUrl(value, normalizeOptions);
|
||||||
|
}
|
||||||
|
return { ...result, [key]: value };
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
// formatUrl(url: String) => String
|
// formatUrl(url: String) => String
|
||||||
export function formatUrl(url) {
|
export function formatUrl(url) {
|
||||||
if (typeof url === 'string' && url.length > 4 && url.indexOf('.') !== -1) {
|
if (typeof url === 'string' && url.length > 4 && url.indexOf('.') !== -1) {
|
||||||
|
@ -2,9 +2,8 @@ import React, { Component } from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Grid, Col, Row } from '@freecodecamp/react-bootstrap';
|
import { Grid, Col, Row } from '@freecodecamp/react-bootstrap';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { reduxForm } from 'redux-form';
|
import { connect } from 'react-redux';
|
||||||
import { graphql } from 'gatsby';
|
import { graphql } from 'gatsby';
|
||||||
import normalizeUrl from 'normalize-url';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
executeChallenge,
|
executeChallenge,
|
||||||
@ -28,53 +27,44 @@ import CompletionModal from '../components/CompletionModal';
|
|||||||
import HelpModal from '../components/HelpModal';
|
import HelpModal from '../components/HelpModal';
|
||||||
import ProjectToolPanel from '../project/Tool-Panel';
|
import ProjectToolPanel from '../project/Tool-Panel';
|
||||||
import ProjectForm from '../project/ProjectForm';
|
import ProjectForm from '../project/ProjectForm';
|
||||||
import {
|
import { Form } from '../../../components/formHelpers';
|
||||||
createFormValidator,
|
|
||||||
isValidURL,
|
|
||||||
makeRequired,
|
|
||||||
Form
|
|
||||||
} from '../../../components/formHelpers';
|
|
||||||
import Spacer from '../../../components/helpers/Spacer';
|
import Spacer from '../../../components/helpers/Spacer';
|
||||||
|
import { ChallengeNode } from '../../../redux/propTypes';
|
||||||
|
import { isSignedInSelector } from '../../../redux';
|
||||||
|
|
||||||
import { backend } from '../../../../utils/challengeTypes';
|
import { backend } from '../../../../utils/challengeTypes';
|
||||||
|
|
||||||
import '../components/test-frame.css';
|
import '../components/test-frame.css';
|
||||||
|
|
||||||
// provided by redux form
|
|
||||||
const reduxFormPropTypes = {
|
|
||||||
fields: PropTypes.object,
|
|
||||||
handleSubmit: PropTypes.func.isRequired,
|
|
||||||
resetForm: PropTypes.func.isRequired,
|
|
||||||
submitting: PropTypes.bool
|
|
||||||
};
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
challengeMounted: PropTypes.func.isRequired,
|
challengeMounted: PropTypes.func.isRequired,
|
||||||
|
data: PropTypes.shape({
|
||||||
|
challengeNode: ChallengeNode
|
||||||
|
}),
|
||||||
description: PropTypes.string,
|
description: PropTypes.string,
|
||||||
executeChallenge: PropTypes.func.isRequired,
|
executeChallenge: PropTypes.func.isRequired,
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
initTests: PropTypes.func.isRequired,
|
initTests: PropTypes.func.isRequired,
|
||||||
|
isSignedIn: PropTypes.bool,
|
||||||
output: PropTypes.string,
|
output: PropTypes.string,
|
||||||
|
pageContext: PropTypes.shape({
|
||||||
|
challengeMeta: PropTypes.object
|
||||||
|
}),
|
||||||
tests: PropTypes.array,
|
tests: PropTypes.array,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
updateBackendFormValues: PropTypes.func.isRequired,
|
updateBackendFormValues: PropTypes.func.isRequired,
|
||||||
updateChallengeMeta: PropTypes.func.isRequired,
|
updateChallengeMeta: PropTypes.func.isRequired,
|
||||||
updateProjectFormValues: PropTypes.func.isRequired,
|
updateProjectFormValues: PropTypes.func.isRequired
|
||||||
...reduxFormPropTypes
|
|
||||||
};
|
|
||||||
|
|
||||||
const fields = ['solution'];
|
|
||||||
|
|
||||||
const fieldValidators = {
|
|
||||||
solution: makeRequired(isValidURL)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = createSelector(
|
const mapStateToProps = createSelector(
|
||||||
consoleOutputSelector,
|
consoleOutputSelector,
|
||||||
challengeTestsSelector,
|
challengeTestsSelector,
|
||||||
(output, tests) => ({
|
isSignedInSelector,
|
||||||
|
(output, tests, isSignedIn) => ({
|
||||||
tests,
|
tests,
|
||||||
output
|
output,
|
||||||
|
isSignedIn
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -158,7 +148,6 @@ export class BackEnd extends Component {
|
|||||||
|
|
||||||
handleSubmit(values) {
|
handleSubmit(values) {
|
||||||
const { updateBackendFormValues, executeChallenge } = this.props;
|
const { updateBackendFormValues, executeChallenge } = this.props;
|
||||||
values.solution = normalizeUrl(values.solution);
|
|
||||||
updateBackendFormValues(values);
|
updateBackendFormValues(values);
|
||||||
executeChallenge();
|
executeChallenge();
|
||||||
}
|
}
|
||||||
@ -176,13 +165,12 @@ export class BackEnd extends Component {
|
|||||||
},
|
},
|
||||||
output,
|
output,
|
||||||
tests,
|
tests,
|
||||||
submitting,
|
isSignedIn,
|
||||||
executeChallenge,
|
executeChallenge,
|
||||||
updateProjectFormValues
|
updateProjectFormValues
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
// TODO: Should be tied to user.isSignedIn
|
const buttonCopy = isSignedIn
|
||||||
const buttonCopy = submitting
|
|
||||||
? 'Submit and go to my next challenge'
|
? 'Submit and go to my next challenge'
|
||||||
: "I've completed this challenge";
|
: "I've completed this challenge";
|
||||||
const blockNameTitle = `${blockName} - ${title}`;
|
const blockNameTitle = `${blockName} - ${title}`;
|
||||||
@ -242,12 +230,7 @@ export class BackEnd extends Component {
|
|||||||
BackEnd.displayName = 'BackEnd';
|
BackEnd.displayName = 'BackEnd';
|
||||||
BackEnd.propTypes = propTypes;
|
BackEnd.propTypes = propTypes;
|
||||||
|
|
||||||
export default reduxForm(
|
export default connect(
|
||||||
{
|
|
||||||
form: 'BackEndChallenge',
|
|
||||||
fields,
|
|
||||||
validate: createFormValidator(fieldValidators)
|
|
||||||
},
|
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToActions
|
mapDispatchToActions
|
||||||
)(BackEnd);
|
)(BackEnd);
|
||||||
|
Reference in New Issue
Block a user