diff --git a/src/examples.js b/src/examples.js index 87ab1e3e..e567c349 100644 --- a/src/examples.js +++ b/src/examples.js @@ -73,6 +73,7 @@ import * as EditListingPoliciesForm from './forms/EditListingPoliciesForm/EditLi import * as EditListingPricingForm from './forms/EditListingPricingForm/EditListingPricingForm.example'; import * as EmailVerificationForm from './forms/EmailVerificationForm/EmailVerificationForm.example'; import * as EnquiryForm from './forms/EnquiryForm/EnquiryForm.example'; +import * as FilterForm from './forms/FilterForm/FilterForm.example'; import * as LoginForm from './forms/LoginForm/LoginForm.example'; import * as PasswordRecoveryForm from './forms/PasswordRecoveryForm/PasswordRecoveryForm.example'; import * as PasswordResetForm from './forms/PasswordResetForm/PasswordResetForm.example'; @@ -118,6 +119,7 @@ export { FieldReviewRating, FieldSelect, FieldTextInput, + FilterForm, Footer, IconAdd, IconBannedUser, diff --git a/src/forms/FilterForm/FilterForm.css b/src/forms/FilterForm/FilterForm.css new file mode 100644 index 00000000..8fb5f9ff --- /dev/null +++ b/src/forms/FilterForm/FilterForm.css @@ -0,0 +1,81 @@ +@import '../../marketplace.css'; + +.root { +} + +.contentWrapper { + margin-bottom: 24px; +} + +.buttonsWrapper { + display: flex; + padding: 0 30px 16px 30px; +} + +.clearButton { + @apply --marketplaceH4FontStyles; + font-weight: var(--fontWeightMedium); + color: var(--matterColorAnti); + + /* Layout */ + margin: 0 auto 0 0; + padding: 0; + + /* Override button styles */ + outline: none; + border: none; + cursor: pointer; + + &:focus, + &:hover { + color: var(--matterColor); + transition: width var(--transitionStyleButton); + } +} + +.cancelButton { + @apply --marketplaceH4FontStyles; + font-weight: var(--fontWeightMedium); + color: var(--matterColorAnti); + + /* Layout */ + margin: 0; + padding: 0; + + /* Override button styles */ + outline: none; + border: none; + cursor: pointer; + + /* clearButton will add all available space between cancelButton, + * but some hard coded margin is still needed + */ + margin-left: 48px; + + &:focus, + &:hover { + color: var(--matterColor); + transition: width var(--transitionStyleButton); + } +} + +.submitButton { + @apply --marketplaceH4FontStyles; + font-weight: var(--fontWeightMedium); + color: var(--marketplaceColor); + + /* Layout */ + margin: 0 0 0 19px; + padding: 0; + + /* Override button styles */ + outline: none; + border: none; + cursor: pointer; + + &:focus, + &:hover { + color: var(--marketplaceColorDark); + transition: width var(--transitionStyleButton); + } +} diff --git a/src/forms/FilterForm/FilterForm.example.js b/src/forms/FilterForm/FilterForm.example.js new file mode 100644 index 00000000..4dea9a08 --- /dev/null +++ b/src/forms/FilterForm/FilterForm.example.js @@ -0,0 +1,51 @@ +import React from 'react'; +import FilterForm from './FilterForm'; +import { FieldTextInput } from '../../components'; + +const field = ( + +); + +export const FilterFormExample = { + component: FilterForm, + props: { + id: 'FilterFormExample', + liveEdit: false, + showAsPopup: true, + contentPlacementOffset: -14, + onSubmit: values => { + console.log(values); + }, + onCancel: () => { + console.log('onCancel called'); + }, + onClear: () => { + console.log('onClear called'); + }, + label: 'Example label', + children: field, + }, + group: 'forms', +}; + +export const FilterFormExampleLiveEdit = { + component: FilterForm, + props: { + id: 'FilterFormExampleLiveEdit', + liveEdit: true, + showAsPopup: false, + contentPlacementOffset: -14, + onChange: values => { + console.log(values); + }, + label: 'Example label', + children: field, + }, + group: 'forms', +}; diff --git a/src/forms/FilterForm/FilterForm.js b/src/forms/FilterForm/FilterForm.js new file mode 100644 index 00000000..a3730870 --- /dev/null +++ b/src/forms/FilterForm/FilterForm.js @@ -0,0 +1,115 @@ +import React from 'react'; +import { bool, func, node, object } from 'prop-types'; +import classNames from 'classnames'; +import { Form as FinalForm, FormSpy } from 'react-final-form'; +import { injectIntl, intlShape } from 'react-intl'; + +import { Form } from '../../components'; +import css from './FilterForm.css'; + +const FilterFormComponent = props => { + const { liveEdit, onChange, onSubmit, onCancel, onClear, ...rest } = props; + + if (liveEdit && !onChange) { + throw new Error('FilterForm: if liveEdit is true you need to provide onChange function'); + } + + if (!liveEdit && !(onCancel && onClear && onSubmit)) { + throw new Error( + 'FilterForm: if liveEdit is false you need to provide onCancel, onClear, and onSubmit functions' + ); + } + + const handleChange = formState => { + if (formState.dirty) { + onChange(formState.values); + } + }; + + const formCallbacks = liveEdit ? { onSubmit: () => null } : { onSubmit, onCancel, onClear }; + return ( + { + const { + id, + form, + handleSubmit, + onClear, + onCancel, + style, + paddingClasses, + intl, + children, + } = formRenderProps; + + const handleCancel = () => { + // reset the final form to initialValues + form.reset(); + onCancel(); + }; + + const clear = intl.formatMessage({ id: 'FilterForm.clear' }); + const cancel = intl.formatMessage({ id: 'FilterForm.cancel' }); + const submit = intl.formatMessage({ id: 'FilterForm.submit' }); + + const classes = classNames(css.root); + + return ( +
+
{children}
+ + {liveEdit ? ( + + ) : ( +
+ + + +
+ )} + + ); + }} + /> + ); +}; + +FilterFormComponent.defaultProps = { + liveEdit: false, + style: null, + onCancel: null, + onChange: null, + onClear: null, + onSubmit: null, +}; + +FilterFormComponent.propTypes = { + liveEdit: bool, + onCancel: func, + onChange: func, + onClear: func, + onSubmit: func, + style: object, + children: node.isRequired, + + // form injectIntl + intl: intlShape.isRequired, +}; + +const FilterForm = injectIntl(FilterFormComponent); + +export default FilterForm; diff --git a/src/forms/index.js b/src/forms/index.js index 399596fa..198f53de 100644 --- a/src/forms/index.js +++ b/src/forms/index.js @@ -9,6 +9,7 @@ export { default as EditListingPoliciesForm } from './EditListingPoliciesForm/Ed export { default as EditListingPricingForm } from './EditListingPricingForm/EditListingPricingForm'; export { default as EmailVerificationForm } from './EmailVerificationForm/EmailVerificationForm'; export { default as EnquiryForm } from './EnquiryForm/EnquiryForm'; +export { default as FilterForm } from './FilterForm/FilterForm'; export { default as LocationSearchForm } from './LocationSearchForm/LocationSearchForm'; export { default as LoginForm } from './LoginForm/LoginForm'; export { default as PasswordChangeForm } from './PasswordChangeForm/PasswordChangeForm'; diff --git a/src/translations/en.json b/src/translations/en.json index ec37bd63..2035811a 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -256,6 +256,9 @@ "FieldReviewRating.star3": "OK - 3 stars", "FieldReviewRating.star4": "Good - 4 stars", "FieldReviewRating.star5": "Awesome - 5 stars", + "FilterForm.cancel": "Cancel", + "FilterForm.clear": "Clear", + "FilterForm.submit": "Apply", "Footer.copyright": "© Sharetribe", "Footer.goToFacebook": "Go to Facebook page", "Footer.goToInstagram": "Go to Instagram page",