Merge pull request #668 from sharetribe/edit-listing-services

Edit listing features form
This commit is contained in:
Hannu Lyytikäinen 2018-01-25 16:29:50 +02:00 committed by GitHub
commit a7932134e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 225 additions and 50 deletions

View file

@ -15,7 +15,7 @@ const FormComponent = props => {
<FieldCheckbox
id="field-checkbox-example-id"
name="field-checkbox-example-name"
text="Check here"
label="Check here"
/>
<Button style={{ marginTop: 24 }} type="submit" disabled={submitDisabled}>

View file

@ -39,7 +39,7 @@ const { node, string } = PropTypes;
IconCheckbox.propTypes = { className: string };
const FieldCheckbox = props => {
const { rootClassName, className, svgClassName, id, name, text } = props;
const { rootClassName, className, svgClassName, id, name, label } = props;
const classes = classNames(rootClassName || css.root, className);
@ -48,7 +48,7 @@ const FieldCheckbox = props => {
<Field id={id} name={name} className={css.input} type="checkbox" component="input" />
<label htmlFor={id} className={css.label}>
<IconCheckbox className={svgClassName} />
<span className={css.text}>{text}</span>
<span className={css.text}>{label}</span>
</label>
</span>
);
@ -58,7 +58,7 @@ FieldCheckbox.defaultProps = {
className: null,
rootClassName: null,
svgClassName: null,
text: null,
label: null,
};
FieldCheckbox.propTypes = {
@ -67,7 +67,7 @@ FieldCheckbox.propTypes = {
svgClassName: string,
id: string.isRequired,
name: string.isRequired,
text: node,
label: node,
};
export default FieldCheckbox;

View file

@ -12,36 +12,36 @@ const componentProps = {
legend: legend,
options: [
{
name: 'towels',
text: 'Towels',
key: 'towels',
label: 'Towels',
},
{
name: 'bathroom',
text: 'Bathfoom',
key: 'bathroom',
label: 'Bathroom',
},
{
name: 'swimming_pool',
text: 'Swimming pool',
key: 'swimming_pool',
label: 'Swimming pool',
},
{
name: 'own_drinks',
text: 'Own drinks allowed',
key: 'own_drinks',
label: 'Own drinks allowed',
},
{
name: 'jacuzzi',
text: 'Jacuzzi',
key: 'jacuzzi',
label: 'Jacuzzi',
},
{
name: 'audiovisual_entertainment',
text: 'Audiovisual entertainment',
key: 'audiovisual_entertainment',
label: 'Audiovisual entertainment',
},
{
name: 'barbeque',
text: 'Barbeque',
key: 'barbeque',
label: 'Barbeque',
},
{
name: 'own_food_allowed',
text: 'Own food allowed',
key: 'own_food_allowed',
label: 'Own food allowed',
},
],
twoColumns: true,

View file

@ -7,41 +7,35 @@
*
*/
import React, { Component } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { FieldCheckbox } from '../../components';
import css from './FieldGroupCheckbox.css';
class FieldGroupCheckbox extends Component {
constructor(props) {
super(props);
this.state = { selected: [] };
}
const FieldGroupCheckbox = props => {
const { rootClassName, className, id, legend, options, twoColumns } = props;
render() {
const { rootClassName, className, id, legend, options, twoColumns } = this.props;
const classes = classNames(rootClassName || css.root, className);
const listClasses = twoColumns ? classNames(css.list, css.twoColumns) : css.list;
const classes = classNames(rootClassName || css.root, className);
const listClasses = twoColumns ? classNames(css.list, css.twoColumns) : css.list;
return (
<fieldset className={classes}>
{legend ? <legend>{legend}</legend> : null}
<ul className={listClasses}>
{options.map(option => {
const fieldId = `${id}.${option.name}`;
return (
<li key={fieldId} className={css.item}>
<FieldCheckbox id={fieldId} name={option.name} text={option.text} />
</li>
);
})}
</ul>
</fieldset>
);
}
}
return (
<fieldset className={classes}>
{legend ? <legend>{legend}</legend> : null}
<ul className={listClasses}>
{options.map(option => {
const fieldId = `${id}.${option.key}`;
return (
<li key={fieldId} className={css.item}>
<FieldCheckbox id={fieldId} name={option.key} label={option.label} />
</li>
);
})}
</ul>
</fieldset>
);
};
FieldGroupCheckbox.defaultProps = {
rootClassName: null,
@ -59,8 +53,8 @@ FieldGroupCheckbox.propTypes = {
legend: node,
options: arrayOf(
shape({
name: string.isRequired,
text: node.isRequired,
key: string.isRequired,
label: node.isRequired,
})
).isRequired,
twoColumns: bool,

View file

@ -1,3 +1,5 @@
import * as custom from './marketplace-custom-config.js';
const env = process.env.REACT_APP_ENV || 'production';
const dev = process.env.REACT_APP_ENV === 'development';
@ -298,6 +300,7 @@ const config = {
facebookAppId,
sentryDsn,
usingSSL,
custom,
};
export default config;

View file

@ -0,0 +1,34 @@
@import '../../marketplace.css';
:root {
--formMargins: {
margin-bottom: 24px;
@media (--viewportMedium) {
margin-bottom: 32px;
}
}
}
.root {
}
.features {
@apply --formMargins;
}
.error {
color: var(--failColor);
}
.submitButton {
margin-top: auto;
margin-bottom: 24px;
flex-shrink: 0;
@media (--viewportLarge) {
display: inline-block;
width: 241px;
margin-top: 100px;
}
}

View file

@ -0,0 +1,18 @@
import EditListingFeaturesForm from './EditListingFeaturesForm';
const initialValueArray = ['towels', 'jacuzzi', 'bathroom'];
export const Amenities = {
component: EditListingFeaturesForm,
props: {
onSubmit: values => console.log('EditListingFeaturesForm submit:', values),
initialValues: initialValueArray.reduce((map, value) => {
map[value] = true;
return map;
}, {}),
saveActionMsg: 'Save amenities',
updated: false,
updateInProgress: false,
},
group: 'forms',
};

View file

@ -0,0 +1,82 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { reduxForm, propTypes as formPropTypes } from 'redux-form';
import { FormattedMessage } from 'react-intl';
import { propTypes } from '../../util/types';
import config from '../../config';
import { Button, FieldGroupCheckbox, Form } from '../../components';
import css from './EditListingFeaturesForm.css';
const EditListingFeaturesFormComponent = props => {
const {
form,
submitting,
disabled,
rootClassName,
className,
handleSubmit,
saveActionMsg,
updated,
updateError,
updateInProgress,
} = props;
const classes = classNames(rootClassName || css.root, className);
const submitReady = updated;
const submitInProgress = submitting || updateInProgress;
const submitDisabled = disabled || submitInProgress;
const errorMessage = updateError ? (
<p className={css.error}>
<FormattedMessage id="EditListingFeaturesForm.updateFailed" />
</p>
) : null;
return (
<Form className={classes} onSubmit={handleSubmit}>
{errorMessage}
<FieldGroupCheckbox
className={css.features}
id={`${form}.amenities`}
options={config.custom.amenities}
/>
<Button
className={css.submitButton}
type="submit"
inProgress={submitInProgress}
disabled={submitDisabled}
ready={submitReady}
>
{saveActionMsg}
</Button>
</Form>
);
};
EditListingFeaturesFormComponent.defaultProps = {
rootClassName: null,
className: null,
updateError: null,
};
const { bool, func, string } = PropTypes;
EditListingFeaturesFormComponent.propTypes = {
...formPropTypes,
rootClassName: string,
className: string,
handleSubmit: func.isRequired,
saveActionMsg: string.isRequired,
updated: bool.isRequired,
updateError: propTypes.error,
updateInProgress: bool.isRequired,
};
const defaultFormName = 'EditListingFeaturesForm';
export default reduxForm({ form: defaultFormName })(EditListingFeaturesFormComponent);

View file

@ -7,6 +7,9 @@ export { default as ContactDetailsPage } from './ContactDetailsPage/ContactDetai
export {
default as EditListingDescriptionForm,
} from './EditListingDescriptionForm/EditListingDescriptionForm';
export {
default as EditListingFeaturesForm,
} from './EditListingFeaturesForm/EditListingFeaturesForm';
export {
default as EditListingLocationForm,
} from './EditListingLocationForm/EditListingLocationForm';

View file

@ -56,6 +56,7 @@ import * as UserCard from './components/UserCard/UserCard.example';
import * as BookingDatesForm from './containers/BookingDatesForm/BookingDatesForm.example';
import * as Colors from './containers/StyleguidePage/Colors.example';
import * as EditListingDescriptionForm from './containers/EditListingDescriptionForm/EditListingDescriptionForm.example';
import * as EditListingFeaturesForm from './containers/EditListingFeaturesForm/EditListingFeaturesForm.example';
import * as EditListingLocationForm from './containers/EditListingLocationForm/EditListingLocationForm.example';
import * as EditListingPhotosForm from './containers/EditListingPhotosForm/EditListingPhotosForm.example';
import * as EditListingPoliciesForm from './containers/EditListingPoliciesForm/EditListingPoliciesForm.example';
@ -84,6 +85,7 @@ export {
CurrencyInputField,
DateRangeInputField,
EditListingDescriptionForm,
EditListingFeaturesForm,
EditListingLocationForm,
EditListingPhotosForm,
EditListingPoliciesForm,

View file

@ -0,0 +1,38 @@
/*
* Marketplace specific configuration.
*/
export const amenities = [
{
key: 'towels',
label: 'Towels',
},
{
key: 'bathroom',
label: 'Bathroom',
},
{
key: 'swimming_pool',
label: 'Swimming pool',
},
{
key: 'own_drinks',
label: 'Own drinks allowed',
},
{
key: 'jacuzzi',
label: 'Jacuzzi',
},
{
key: 'audiovisual_entertainment',
label: 'Audiovisual entertainment',
},
{
key: 'barbeque',
label: 'Barbeque',
},
{
key: 'own_food_allowed',
label: 'Own food allowed',
},
];

View file

@ -119,6 +119,7 @@
"EditListingDescriptionForm.updateFailed": "Failed to update listing. Please try again.",
"EditListingDescriptionPanel.createListingTitle": "Add your sauna",
"EditListingDescriptionPanel.title": "Edit details of {listingTitle}",
"EditListingFeaturesForm.updateFailed": "Failed to update listing. Please try again.",
"EditListingLocationForm.address": "Address",
"EditListingLocationForm.addressNotRecognized": "We didn't recognize this location. Please try another location.",
"EditListingLocationForm.addressPlaceholder": "123 Example Street",