fix: allow form label and name to differ

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Sky020
2020-09-09 17:12:48 +01:00
committed by Ahmad Abdolsaheb
parent d765fa704b
commit c4240cdf2f
6 changed files with 37 additions and 28 deletions

View File

@ -12,7 +12,10 @@ import {
const propTypes = {
buttonText: PropTypes.string,
enableSubmit: PropTypes.bool,
formFields: PropTypes.arrayOf(PropTypes.string).isRequired,
formFields: PropTypes.arrayOf(
PropTypes.shape({ name: PropTypes.string, label: PropTypes.string })
.isRequired
).isRequired,
hideButton: PropTypes.bool,
id: PropTypes.string.isRequired,
initialValues: PropTypes.object,
@ -47,7 +50,7 @@ function DynamicForm({
onSubmit={handleSubmit}
style={{ width: '100%' }}
>
<FormFields fields={formFields} options={options} />
<FormFields formFields={formFields} options={options} />
<BlockSaveWrapper>
{hideButton ? null : (
<BlockSaveButton disabled={(pristine && !enableSubmit) || error}>

View File

@ -8,7 +8,10 @@ import Form from './Form';
const defaultTestProps = {
buttonText: 'Submit',
formFields: ['name', 'website'],
formFields: [
{ name: 'name', label: 'name Label' },
{ name: 'website', label: 'WebSite label' }
],
id: 'my-test-form',
options: {
types: {
@ -23,11 +26,11 @@ const defaultTestProps = {
test('should render', () => {
const { getByLabelText, getByText } = render(<Form {...defaultTestProps} />);
const nameInput = getByLabelText(/name/i);
const nameInput = getByLabelText(/name Label/);
expect(nameInput).not.toBeRequired();
expect(nameInput).toHaveAttribute('type', 'text');
const websiteInput = getByLabelText(/website/i);
const websiteInput = getByLabelText(/WebSite label/);
expect(websiteInput).toBeRequired();
expect(websiteInput).toHaveAttribute('type', 'url');
@ -48,10 +51,10 @@ test('should render with default values', () => {
/>
);
const nameInput = getByLabelText(/name/i);
const nameInput = getByLabelText(/name Label/);
expect(nameInput).toHaveValue(nameValue);
const websiteInput = getByLabelText(/website/i);
const websiteInput = getByLabelText(/WebSite label/);
expect(websiteInput).toHaveValue(websiteValue);
const button = getByText(/submit/i);
@ -68,7 +71,7 @@ test('should submit', () => {
const { getByLabelText, getByText } = render(<Form {...props} />);
const websiteInput = getByLabelText(/website/i);
const websiteInput = getByLabelText(/WebSite label/);
fireEvent.change(websiteInput, { target: { value: websiteValue } });
expect(websiteInput).toHaveValue(websiteValue);

View File

@ -1,5 +1,5 @@
import React from 'react';
import { kebabCase, startCase } from 'lodash';
import { kebabCase } from 'lodash';
import PropTypes from 'prop-types';
import {
Alert,
@ -12,7 +12,10 @@ import {
import { Field } from 'react-final-form';
const propTypes = {
fields: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired,
formFields: PropTypes.arrayOf(
PropTypes.shape({ name: PropTypes.string, label: PropTypes.string })
.isRequired
).isRequired,
options: PropTypes.shape({
ignored: PropTypes.arrayOf(PropTypes.string),
placeholders: PropTypes.objectOf(PropTypes.string),
@ -22,19 +25,20 @@ const propTypes = {
};
function FormFields(props) {
const { fields, options = {} } = props;
const { formFields, options = {} } = props;
const {
ignored = [],
placeholders = {},
required = [],
types = {}
} = options;
return (
<div>
{fields
.filter(field => !ignored.includes(field))
.map(name => (
<Field key={`${name}-field`} name={name}>
{formFields
.filter(formField => !ignored.includes(formField.name))
.map(({ name, label }) => (
<Field key={`${kebabCase(name)}-field`} name={name}>
{({ input: { value, onChange }, meta: { pristine, error } }) => {
const key = kebabCase(name);
const type = name in types ? types[name] : 'text';
@ -44,9 +48,7 @@ function FormFields(props) {
<Col key={key} xs={12}>
<FormGroup>
{type === 'hidden' ? null : (
<ControlLabel htmlFor={key}>
{startCase(name)}
</ControlLabel>
<ControlLabel htmlFor={key}>{label}</ControlLabel>
)}
<FormControl
componentClass={type === 'textarea' ? type : 'input'}

View File

@ -9,7 +9,6 @@ export { default as FormFields } from './FormFields.js';
const normalizeOptions = {
stripWWW: false
};
// callIfDefined(fn: (Any) => Any) => (value: Any) => Any
export function callIfDefined(fn) {
return value => (value ? fn(value) : value);
@ -24,7 +23,6 @@ export function formatUrlValues(values, options) {
return { ...result, [key]: value };
}, {});
}
// formatUrl(url: String) => String
export function formatUrl(url) {
if (typeof url === 'string' && url.length > 4 && url.indexOf('.') !== -1) {
@ -41,21 +39,17 @@ export function formatUrl(url) {
}
return url;
}
export function isValidURL(data) {
/* eslint-disable camelcase */
return isURL(data, { require_protocol: true });
/* eslint-enable camelcase */
}
export function makeOptional(validator) {
return val => (val ? validator(val) : true);
}
export function makeRequired(validator) {
return val => (val ? validator(val) : false);
}
export function createFormValidator(fieldValidators) {
const fieldKeys = Object.keys(fieldValidators);
return values =>
@ -69,7 +63,6 @@ export function createFormValidator(fieldValidators) {
.filter(Boolean)
.reduce((errors, error) => ({ ...errors, ...error }), {});
}
export function getValidationState(field) {
if (field.pristine) {
return null;

View File

@ -415,6 +415,11 @@ export class CertificationSettings extends Component {
{ types: {} }
);
const formFields = challengeTitles.map(title => ({
name: title,
label: title
}));
const fullForm = filledforms === challengeTitles.length;
const createClickHandler = certLocation => e => {
@ -436,7 +441,7 @@ export class CertificationSettings extends Component {
<Form
buttonText={fullForm ? 'Claim Certification' : 'Save Progress'}
enableSubmit={fullForm}
formFields={challengeTitles}
formFields={formFields}
hideButton={isCertClaimed}
id={superBlock}
initialValues={{

View File

@ -18,8 +18,11 @@ const propTypes = {
};
// back end challenges and front end projects use a single form field
const solutionField = ['solution'];
const backEndProjectFields = ['solution', 'githubLink'];
const solutionField = [{ name: 'solution', label: 'Solution Link' }];
const backEndProjectFields = [
{ name: 'solution', label: 'Solution Link' },
{ name: 'githubLink', label: 'GitHub Link' }
];
const options = {
types: {