mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-29 21:21:19 +10:00
Remove EditListingForm
This commit is contained in:
parent
9ea6dc42e9
commit
5561a42568
8 changed files with 0 additions and 446 deletions
|
|
@ -1,41 +0,0 @@
|
|||
.addImageWrapper {
|
||||
float: left;
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
margin: 5px;
|
||||
|
||||
&::after {
|
||||
content: ".";
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
height: 0;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
.addImage {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
background-color: lightgrey;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.addImageInput {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.imageRequiredWrapper {
|
||||
width: 100%;
|
||||
clear: both;
|
||||
}
|
||||
.imageRequiredError {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.submitButton {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
/* eslint-disable no-console */
|
||||
import EditListingForm from './EditListingForm';
|
||||
|
||||
export const Empty = {
|
||||
component: EditListingForm,
|
||||
props: {
|
||||
stripeConnected: false,
|
||||
onImageUpload: values => {
|
||||
console.log(`onImageUpload with id (${values.id}) and file name (${values.file.name})`);
|
||||
},
|
||||
onSubmit: values => {
|
||||
console.log('Submit EditListingForm with (unformatted) values:', values);
|
||||
},
|
||||
onUpdateImageOrder: imageOrder => {
|
||||
console.log('onUpdateImageOrder with new imageOrder:', imageOrder);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,258 +0,0 @@
|
|||
import React, { Component, PropTypes } from 'react';
|
||||
import { compose } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Field, reduxForm, formValueSelector, propTypes as formPropTypes } from 'redux-form';
|
||||
import { intlShape, injectIntl } from 'react-intl';
|
||||
import { isEqual } from 'lodash';
|
||||
import { arrayMove } from 'react-sortable-hoc';
|
||||
import config from '../../config';
|
||||
import * as propTypes from '../../util/propTypes';
|
||||
import { enhancedField } from '../../util/forms';
|
||||
import {
|
||||
noEmptyArray,
|
||||
maxLength,
|
||||
required,
|
||||
autocompleteSearchRequired,
|
||||
autocompletePlaceSelected,
|
||||
} from '../../util/validators';
|
||||
import {
|
||||
AddImages,
|
||||
CurrencyInput,
|
||||
LocationAutocompleteInput,
|
||||
Button,
|
||||
Input,
|
||||
StripeBankAccountToken,
|
||||
} from '../../components';
|
||||
import css from './EditListingForm.css';
|
||||
|
||||
const ACCEPT_IMAGES = 'image/*';
|
||||
const TITLE_MAX_LENGTH = 60;
|
||||
|
||||
const { bool, func, object, shape, string } = PropTypes;
|
||||
|
||||
// Add image wrapper. Label is the only visible element, file input is hidden.
|
||||
const RenderAddImage = props => {
|
||||
const { accept, input, label, type } = props;
|
||||
const { name, onChange } = input;
|
||||
const inputProps = { accept, id: name, name, onChange, type };
|
||||
return (
|
||||
<div className={css.addImageWrapper}>
|
||||
<Input {...inputProps} className={css.addImageInput} />
|
||||
<label htmlFor={name} className={css.addImage}>{label}</label>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
RenderAddImage.propTypes = {
|
||||
accept: string.isRequired,
|
||||
input: shape({
|
||||
value: object,
|
||||
onChange: func.isRequired,
|
||||
name: string.isRequired,
|
||||
}).isRequired,
|
||||
label: string.isRequired,
|
||||
type: string.isRequired,
|
||||
};
|
||||
|
||||
export class EditListingFormComponent extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleInitialize = this.handleInitialize.bind(this);
|
||||
this.onImageUploadHandler = this.onImageUploadHandler.bind(this);
|
||||
this.onSortEnd = this.onSortEnd.bind(this);
|
||||
|
||||
// We must create the enhanced components outside the render function
|
||||
// to avoid losing focus.
|
||||
// See: https://github.com/erikras/redux-form/releases/tag/v6.0.0-alpha.14
|
||||
this.EnhancedInput = enhancedField('input');
|
||||
this.EnhancedTextArea = enhancedField('textarea');
|
||||
this.EnhancedCurrencyInput = enhancedField(CurrencyInput);
|
||||
this.EnhancedLocationAutocompleteInput = enhancedField(LocationAutocompleteInput);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.handleInitialize();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!isEqual(this.props.images, nextProps.images)) {
|
||||
nextProps.change('images', nextProps.images);
|
||||
}
|
||||
}
|
||||
|
||||
onImageUploadHandler(event) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
this.props.onImageUpload({ id: `${file.name}_${Date.now()}`, file });
|
||||
}
|
||||
}
|
||||
|
||||
onSortEnd({ oldIndex, newIndex }) {
|
||||
const images = arrayMove(this.props.images, oldIndex, newIndex);
|
||||
this.props.onUpdateImageOrder(images.map(i => i.id));
|
||||
}
|
||||
|
||||
handleInitialize() {
|
||||
const { initData = {}, initialize } = this.props;
|
||||
initialize(initData);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
disabled,
|
||||
handleSubmit,
|
||||
images,
|
||||
intl,
|
||||
pristine,
|
||||
saveActionMsg = 'Save listing',
|
||||
submitting,
|
||||
selectedPlace,
|
||||
stripeConnected,
|
||||
} = this.props;
|
||||
const titleRequiredMessage = intl.formatMessage({ id: 'EditListingForm.titleRequired' });
|
||||
const maxLengthMessage = intl.formatMessage(
|
||||
{ id: 'EditListingForm.maxLength' },
|
||||
{
|
||||
maxLength: TITLE_MAX_LENGTH,
|
||||
}
|
||||
);
|
||||
const maxLength60Message = maxLength(maxLengthMessage, TITLE_MAX_LENGTH);
|
||||
const priceRequiredMessage = intl.formatMessage({ id: 'EditListingForm.priceRequired' });
|
||||
const imageRequiredMessage = intl.formatMessage({ id: 'EditListingForm.imageRequired' });
|
||||
const locationRequiredMessage = intl.formatMessage({
|
||||
id: 'EditListingForm.locationRequired',
|
||||
});
|
||||
const locationNotRecognizedMessage = intl.formatMessage({
|
||||
id: 'EditListingForm.locationNotRecognized',
|
||||
});
|
||||
const bankAccountNumberRequiredMessage = intl.formatMessage({
|
||||
id: 'EditListingForm.bankAccountNumberRequired',
|
||||
});
|
||||
const descriptionRequiredMessage = intl.formatMessage({
|
||||
id: 'EditListingForm.descriptionRequired',
|
||||
});
|
||||
const pricePlaceholderMessage = intl.formatMessage({ id: 'EditListingForm.pricePlaceholder' });
|
||||
|
||||
const country = selectedPlace ? selectedPlace.country : null;
|
||||
const showBankAccountField = !stripeConnected && country;
|
||||
const currency = config.currencyConfig.currency;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Field
|
||||
name="title"
|
||||
label="Title"
|
||||
placeholder="Title"
|
||||
component={this.EnhancedInput}
|
||||
type="text"
|
||||
validate={[required(titleRequiredMessage), maxLength60Message]}
|
||||
/>
|
||||
<Field
|
||||
name="price"
|
||||
label="Price"
|
||||
component={this.EnhancedCurrencyInput}
|
||||
currencyConfig={config.currencyConfig}
|
||||
validate={[required(priceRequiredMessage)]}
|
||||
placeholder={pricePlaceholderMessage}
|
||||
/>
|
||||
|
||||
<h3>Images</h3>
|
||||
<AddImages images={images} onSortEnd={this.onSortEnd}>
|
||||
<Field
|
||||
accept={ACCEPT_IMAGES}
|
||||
component={RenderAddImage}
|
||||
label="+ Add image"
|
||||
name="addImage"
|
||||
onChange={this.onImageUploadHandler}
|
||||
type="file"
|
||||
/>
|
||||
|
||||
<Field
|
||||
component={props => {
|
||||
const { input, type, meta: { error, touched } } = props;
|
||||
return (
|
||||
<div className={css.imageRequiredWrapper}>
|
||||
<Input {...input} type={type} />
|
||||
{touched && error
|
||||
? <span className={css.imageRequiredError}>{error}</span>
|
||||
: null}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
name="images"
|
||||
type="hidden"
|
||||
validate={[noEmptyArray(imageRequiredMessage)]}
|
||||
/>
|
||||
</AddImages>
|
||||
|
||||
<Field
|
||||
name="location"
|
||||
label="Location"
|
||||
format={null}
|
||||
component={this.EnhancedLocationAutocompleteInput}
|
||||
validate={[
|
||||
autocompleteSearchRequired(locationRequiredMessage),
|
||||
autocompletePlaceSelected(locationNotRecognizedMessage),
|
||||
]}
|
||||
/>
|
||||
|
||||
<Field
|
||||
name="description"
|
||||
label="Description"
|
||||
placeholder="Description"
|
||||
component={this.EnhancedTextArea}
|
||||
validate={[required(descriptionRequiredMessage)]}
|
||||
/>
|
||||
|
||||
{showBankAccountField
|
||||
? <Field
|
||||
name="bankAccountToken"
|
||||
component={StripeBankAccountToken}
|
||||
props={{ country, currency }}
|
||||
validate={required(bankAccountNumberRequiredMessage)}
|
||||
/>
|
||||
: null}
|
||||
|
||||
<Button
|
||||
className={css.submitButton}
|
||||
type="submit"
|
||||
disabled={pristine || submitting || disabled}
|
||||
>
|
||||
{saveActionMsg}
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EditListingFormComponent.defaultProps = { initData: {}, selectedPlace: null };
|
||||
|
||||
EditListingFormComponent.propTypes = {
|
||||
...formPropTypes,
|
||||
initData: shape({ title: string, description: string }),
|
||||
selectedPlace: propTypes.place,
|
||||
stripeConnected: bool.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
onImageUpload: func.isRequired,
|
||||
onUpdateImageOrder: func.isRequired,
|
||||
onSubmit: func.isRequired,
|
||||
};
|
||||
|
||||
const formName = 'EditListingForm';
|
||||
|
||||
// When a field depends on the value of another field, we must connect
|
||||
// to the store and select the required values to inject to the
|
||||
// component.
|
||||
//
|
||||
// See: http://redux-form.com/6.6.1/examples/selectingFormValues/
|
||||
const selector = formValueSelector(formName);
|
||||
const mapStateToProps = state => {
|
||||
const location = selector(state, 'location');
|
||||
return {
|
||||
selectedPlace: location && location.selectedPlace ? location.selectedPlace : null,
|
||||
};
|
||||
};
|
||||
|
||||
export default compose(connect(mapStateToProps), reduxForm({ form: formName }), injectIntl)(
|
||||
EditListingFormComponent
|
||||
);
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
// TODO: renderdeep doesn't work due to
|
||||
// "Invariant Violation: getNodeFromInstance: Invalid argument."
|
||||
// refs and findDOMNode are not supported by react-test-renderer
|
||||
// (react-sortable-hoc uses them)
|
||||
import React from 'react';
|
||||
import { renderShallow } from '../../util/test-helpers';
|
||||
import { fakeIntl, fakeFormProps } from '../../util/test-data';
|
||||
import { EditListingFormComponent } from './EditListingForm';
|
||||
|
||||
const noop = () => null;
|
||||
|
||||
describe('EditListingForm', () => {
|
||||
it('matches snapshot', () => {
|
||||
const tree = renderShallow(
|
||||
<EditListingFormComponent
|
||||
{...fakeFormProps}
|
||||
intl={fakeIntl}
|
||||
dispatch={noop}
|
||||
onImageUpload={v => v}
|
||||
onSubmit={v => v}
|
||||
onUpdateImageOrder={v => v}
|
||||
stripeConnected={false}
|
||||
/>
|
||||
);
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
exports[`EditListingForm matches snapshot 1`] = `
|
||||
<form
|
||||
onSubmit={[Function]}>
|
||||
<Field
|
||||
component={[Function]}
|
||||
label="Title"
|
||||
name="title"
|
||||
placeholder="Title"
|
||||
type="text"
|
||||
validate={
|
||||
Array [
|
||||
[Function],
|
||||
[Function],
|
||||
]
|
||||
} />
|
||||
<Field
|
||||
component={[Function]}
|
||||
currencyConfig={
|
||||
Object {
|
||||
"currency": "USD",
|
||||
"currencyDisplay": "symbol",
|
||||
"maximumFractionDigits": 2,
|
||||
"minimumFractionDigits": 2,
|
||||
"style": "currency",
|
||||
"subUnitDivisor": 100,
|
||||
"useGrouping": true,
|
||||
}
|
||||
}
|
||||
label="Price"
|
||||
name="price"
|
||||
placeholder="EditListingForm.pricePlaceholder"
|
||||
validate={
|
||||
Array [
|
||||
[Function],
|
||||
]
|
||||
} />
|
||||
<h3>
|
||||
Images
|
||||
</h3>
|
||||
<AddImages
|
||||
images={Array []}
|
||||
onSortEnd={[Function]}>
|
||||
<Field
|
||||
accept="image/*"
|
||||
component={[Function]}
|
||||
label="+ Add image"
|
||||
name="addImage"
|
||||
onChange={[Function]}
|
||||
type="file" />
|
||||
<Field
|
||||
component={[Function]}
|
||||
name="images"
|
||||
type="hidden"
|
||||
validate={
|
||||
Array [
|
||||
[Function],
|
||||
]
|
||||
} />
|
||||
</AddImages>
|
||||
<Field
|
||||
component={[Function]}
|
||||
format={null}
|
||||
label="Location"
|
||||
name="location"
|
||||
validate={
|
||||
Array [
|
||||
[Function],
|
||||
[Function],
|
||||
]
|
||||
} />
|
||||
<Field
|
||||
component={[Function]}
|
||||
label="Description"
|
||||
name="description"
|
||||
placeholder="Description"
|
||||
validate={
|
||||
Array [
|
||||
[Function],
|
||||
]
|
||||
} />
|
||||
<Button
|
||||
className={null}
|
||||
disabled={true}
|
||||
rootClassName=""
|
||||
type="submit">
|
||||
Save listing
|
||||
</Button>
|
||||
</form>
|
||||
`;
|
||||
|
|
@ -4,7 +4,6 @@ import ChangeAccountPasswordForm from './ChangeAccountPasswordForm/ChangeAccount
|
|||
import ChangePasswordForm from './ChangePasswordForm/ChangePasswordForm';
|
||||
import CheckoutPage from './CheckoutPage/CheckoutPage';
|
||||
import ContactDetailsPage from './ContactDetailsPage/ContactDetailsPage';
|
||||
import EditListingForm from './EditListingForm/EditListingForm';
|
||||
import EditListingPage from './EditListingPage/EditListingPage';
|
||||
import EditProfilePage from './EditProfilePage/EditProfilePage';
|
||||
import SearchForm from './SearchForm/SearchForm';
|
||||
|
|
@ -35,7 +34,6 @@ export {
|
|||
ChangePasswordForm,
|
||||
CheckoutPage,
|
||||
ContactDetailsPage,
|
||||
EditListingForm,
|
||||
EditListingPage,
|
||||
EditProfilePage,
|
||||
SearchForm,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import * as BookingDatesForm from './containers/BookingDatesForm/BookingDatesFor
|
|||
import * as ChangeAccountPasswordForm
|
||||
from './containers/ChangeAccountPasswordForm/ChangeAccountPasswordForm.example';
|
||||
import * as ChangePasswordForm from './containers/ChangePasswordForm/ChangePasswordForm.example';
|
||||
import * as EditListingForm from './containers/EditListingForm/EditListingForm.example';
|
||||
import * as SearchForm from './containers/SearchForm/SearchForm.example';
|
||||
import * as LoginForm from './containers/LoginForm/LoginForm.example';
|
||||
import * as PasswordForgottenForm
|
||||
|
|
@ -40,7 +39,6 @@ export {
|
|||
ChangePasswordForm,
|
||||
CurrencyInput,
|
||||
DateInput,
|
||||
EditListingForm,
|
||||
EditListingWizard,
|
||||
ListingCard,
|
||||
LocationAutocompleteInput,
|
||||
|
|
|
|||
|
|
@ -31,15 +31,6 @@
|
|||
"DateInput.closeDatePicker": "Close",
|
||||
"DateInput.defaultPlaceholder": "Date input",
|
||||
"DateInput.screenReaderInputMessage": "Date input",
|
||||
"EditListingForm.bankAccountNumberRequired": "You need to add a bank account number.",
|
||||
"EditListingForm.descriptionRequired": "You need to add a description.",
|
||||
"EditListingForm.imageRequired": "You need to add at least one image.",
|
||||
"EditListingForm.locationNotRecognized": "We didn't recognize this location. Please try another location.",
|
||||
"EditListingForm.locationRequired": "You need to provide a location",
|
||||
"EditListingForm.maxLength": "Must be {maxLength} characters or less",
|
||||
"EditListingForm.pricePlaceholder": "$0.00",
|
||||
"EditListingForm.priceRequired": "You need to add a valid price.",
|
||||
"EditListingForm.titleRequired": "You need to add a title.",
|
||||
"EditListingPage.titleCreateListing": "Create a listing",
|
||||
"EditListingPage.titleEditListing": "Edit listing",
|
||||
"HeroSection.subTitle": "The largest online community to rent music studios",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue