mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-28 03:43:28 +10:00
EditListingWizard: tabs are configurable (except photos panel)
This commit is contained in:
parent
5bd7ae1249
commit
0718ebc663
3 changed files with 358 additions and 269 deletions
|
|
@ -40,15 +40,12 @@ const EditListingPoliciesPanel = props => {
|
|||
<FormattedMessage id="EditListingPoliciesPanel.createListingTitle" />
|
||||
);
|
||||
|
||||
const saunaRules = publicData && publicData.saunaRules ? publicData.saunaRules : '';
|
||||
const initialSearchFormValues = { saunaRules };
|
||||
|
||||
return (
|
||||
<div className={classes}>
|
||||
<h1 className={css.title}>{panelTitle}</h1>
|
||||
<EditListingPoliciesForm
|
||||
className={css.form}
|
||||
initialValues={initialSearchFormValues}
|
||||
initialValues={{ ...publicData }}
|
||||
onSubmit={onSubmit}
|
||||
onChange={onChange}
|
||||
saveActionMsg={submitButtonText}
|
||||
|
|
|
|||
|
|
@ -3,94 +3,85 @@ import PropTypes from 'prop-types';
|
|||
import { compose } from 'redux';
|
||||
import { injectIntl, intlShape } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import routeConfiguration from '../../routeConfiguration';
|
||||
import { propTypes } from '../../util/types';
|
||||
import { withViewport } from '../../util/contextHelpers';
|
||||
import { ensureListing } from '../../util/data';
|
||||
import { createResourceLocatorString } from '../../util/routes';
|
||||
import {
|
||||
EditListingDescriptionPanel,
|
||||
EditListingLocationPanel,
|
||||
EditListingPhotosPanel,
|
||||
EditListingPoliciesPanel,
|
||||
EditListingPricingPanel,
|
||||
NamedRedirect,
|
||||
Tabs,
|
||||
} from '../../components';
|
||||
import { NamedRedirect, Tabs } from '../../components';
|
||||
|
||||
import EditListingWizardTab, {
|
||||
DESCRIPTION,
|
||||
POLICY,
|
||||
LOCATION,
|
||||
PRICING,
|
||||
PHOTOS,
|
||||
} from './EditListingWizardTab';
|
||||
import css from './EditListingWizard.css';
|
||||
|
||||
const DESCRIPTION = 'description';
|
||||
const POLICY = 'policy';
|
||||
const LOCATION = 'location';
|
||||
const PRICING = 'pricing';
|
||||
const PHOTOS = 'photos';
|
||||
const STEPS = [DESCRIPTION, POLICY, LOCATION, PRICING, PHOTOS];
|
||||
// TODO: PHOTOS panel needs to be the last one since it currently contains PayoutDetailsForm modal
|
||||
// All the other panels can be reordered.
|
||||
export const TABS = [DESCRIPTION, POLICY, LOCATION, PRICING, PHOTOS];
|
||||
|
||||
// Tabs are horizontal in small screens
|
||||
const MAX_HORIZONTAL_NAV_SCREEN_WIDTH = 1023;
|
||||
|
||||
const submitText = (intl, isNew, step) => {
|
||||
const tabLabel = (intl, tab) => {
|
||||
let key = null;
|
||||
if (step === DESCRIPTION) {
|
||||
key = isNew ? 'EditListingWizard.saveNewDescription' : 'EditListingWizard.saveEditDescription';
|
||||
} else if (step === POLICY) {
|
||||
key = isNew ? 'EditListingWizard.saveNewPolicies' : 'EditListingWizard.saveEditPolicies';
|
||||
} else if (step === LOCATION) {
|
||||
key = isNew ? 'EditListingWizard.saveNewLocation' : 'EditListingWizard.saveEditLocation';
|
||||
} else if (step === PRICING) {
|
||||
key = isNew ? 'EditListingWizard.saveNewPricing' : 'EditListingWizard.saveEditPricing';
|
||||
} else if (step === PHOTOS) {
|
||||
key = isNew ? 'EditListingWizard.saveNewPhotos' : 'EditListingWizard.saveEditPhotos';
|
||||
}
|
||||
return intl.formatMessage({ id: key });
|
||||
};
|
||||
|
||||
const tabLabel = (intl, step) => {
|
||||
let key = null;
|
||||
if (step === DESCRIPTION) {
|
||||
if (tab === DESCRIPTION) {
|
||||
key = 'EditListingWizard.tabLabelDescription';
|
||||
} else if (step === POLICY) {
|
||||
} else if (tab === POLICY) {
|
||||
key = 'EditListingWizard.tabLabelPolicy';
|
||||
} else if (step === LOCATION) {
|
||||
} else if (tab === LOCATION) {
|
||||
key = 'EditListingWizard.tabLabelLocation';
|
||||
} else if (step === PRICING) {
|
||||
} else if (tab === PRICING) {
|
||||
key = 'EditListingWizard.tabLabelPricing';
|
||||
} else if (step === PHOTOS) {
|
||||
} else if (tab === PHOTOS) {
|
||||
key = 'EditListingWizard.tabLabelPhotos';
|
||||
}
|
||||
|
||||
return intl.formatMessage({ id: key });
|
||||
};
|
||||
|
||||
/**
|
||||
* Check which wizard steps are active and which are not yet available. Step is active is previous
|
||||
* step is completed.
|
||||
* Check if a wizard tab is completed.
|
||||
*
|
||||
* @param tab wizard's tab
|
||||
* @param listing is contains some specific data if tab is completed
|
||||
*
|
||||
* @return true if tab / step is completed.
|
||||
*/
|
||||
const tabCompleted = (tab, listing) => {
|
||||
const { description, geolocation, price, title, publicData } = listing.attributes;
|
||||
const images = listing.images;
|
||||
|
||||
switch (tab) {
|
||||
case DESCRIPTION:
|
||||
return !!(description && title);
|
||||
case POLICY:
|
||||
return !!(publicData && typeof publicData.saunaRules !== 'undefined');
|
||||
case LOCATION:
|
||||
return !!(geolocation && publicData && publicData.location && publicData.location.address);
|
||||
case PRICING:
|
||||
return !!price;
|
||||
case PHOTOS:
|
||||
return images && images.length > 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check which wizard tabs are active and which are not yet available. Tab is active if previous
|
||||
* tab is completed.
|
||||
*
|
||||
* @param listing data to be checked
|
||||
*
|
||||
* @return object containing activity / editability of different steps of this wizard
|
||||
* @return object containing activity / editability of different tabs of this wizard
|
||||
*/
|
||||
const stepsActive = listing => {
|
||||
const { description, geolocation, price, title, publicData } = listing.attributes;
|
||||
const descriptionStep = !!(title && description);
|
||||
const policyStep = !!(publicData && typeof publicData.saunaRules !== 'undefined');
|
||||
const locationStep = !!(
|
||||
geolocation &&
|
||||
publicData &&
|
||||
publicData.location &&
|
||||
publicData.location.address
|
||||
);
|
||||
const pricingStep = !!price;
|
||||
|
||||
// photosStep is about adding listing.images
|
||||
|
||||
return {
|
||||
[DESCRIPTION]: true,
|
||||
[POLICY]: descriptionStep,
|
||||
[LOCATION]: policyStep,
|
||||
[PRICING]: locationStep,
|
||||
[PHOTOS]: pricingStep,
|
||||
};
|
||||
const tabsActive = listing => {
|
||||
return TABS.reduce((acc, tab) => {
|
||||
const previousTabIndex = TABS.findIndex(t => t === tab) - 1;
|
||||
const isActive = previousTabIndex >= 0 ? tabCompleted(TABS[previousTabIndex], listing) : true;
|
||||
return { ...acc, [tab]: isActive };
|
||||
}, {});
|
||||
};
|
||||
|
||||
const scrollToTab = (tabPrefix, tabId) => {
|
||||
|
|
@ -113,59 +104,19 @@ class EditListingWizard extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
id,
|
||||
className,
|
||||
params,
|
||||
errors,
|
||||
fetchInProgress,
|
||||
newListingCreated,
|
||||
history,
|
||||
images,
|
||||
listing,
|
||||
onCreateListing,
|
||||
onUpdateListing,
|
||||
onCreateListingDraft,
|
||||
onImageUpload,
|
||||
onPayoutDetailsFormChange,
|
||||
onPayoutDetailsSubmit,
|
||||
onUpdateImageOrder,
|
||||
onRemoveImage,
|
||||
onUpdateListingDraft,
|
||||
onChange,
|
||||
rootClassName,
|
||||
currentUser,
|
||||
onManageDisableScrolling,
|
||||
updatedTab,
|
||||
updateInProgress,
|
||||
intl,
|
||||
viewport,
|
||||
} = this.props;
|
||||
const { id, className, rootClassName, params, listing, viewport, intl, ...rest } = this.props;
|
||||
|
||||
const isNew = params.type === 'new';
|
||||
const selectedTab = params.tab;
|
||||
const rootClasses = rootClassName || css.root;
|
||||
const classes = classNames(rootClasses, className);
|
||||
const currentListing = ensureListing(listing);
|
||||
const stepsStatus = stepsActive(currentListing);
|
||||
const tabsStatus = tabsActive(currentListing);
|
||||
|
||||
const tabParams = tab => {
|
||||
return { ...params, tab };
|
||||
};
|
||||
const tabLink = tab => {
|
||||
return { name: 'EditListingPage', params: tabParams(tab) };
|
||||
};
|
||||
|
||||
// If selectedStep is not active, redirect to the beginning of wizard
|
||||
if (!stepsStatus[selectedTab]) {
|
||||
return <NamedRedirect name="EditListingPage" params={tabParams(DESCRIPTION)} />;
|
||||
// If selectedTab is not active, redirect to the beginning of wizard
|
||||
if (!tabsStatus[selectedTab]) {
|
||||
return <NamedRedirect name="EditListingPage" params={{ ...params, tab: TABS[0] }} />;
|
||||
}
|
||||
|
||||
const onUpsertListingDraft = currentListing.id ? onUpdateListingDraft : onCreateListingDraft;
|
||||
const update = (tab, values) => {
|
||||
onUpdateListing(tab, { ...values, id: currentListing.id });
|
||||
};
|
||||
|
||||
const { width } = viewport;
|
||||
const hasViewport = width > 0;
|
||||
const hasHorizontalTabLayout = hasViewport && width <= MAX_HORIZONTAL_NAV_SCREEN_WIDTH;
|
||||
|
|
@ -182,132 +133,30 @@ class EditListingWizard extends Component {
|
|||
this.hasScrolledToTab = true;
|
||||
}
|
||||
|
||||
const panelProps = tab => {
|
||||
return {
|
||||
className: css.panel,
|
||||
disabled: !stepsStatus[tab],
|
||||
errors,
|
||||
listing,
|
||||
onChange,
|
||||
panelUpdated: updatedTab === tab,
|
||||
selected: selectedTab === tab,
|
||||
submitButtonText: submitText(intl, isNew, tab),
|
||||
tabId: `${id}_${tab}`,
|
||||
tabLabel: tabLabel(intl, tab),
|
||||
tabLinkProps: tabLink(tab),
|
||||
updateInProgress,
|
||||
};
|
||||
const tabLink = tab => {
|
||||
return { name: 'EditListingPage', params: { ...params, tab } };
|
||||
};
|
||||
|
||||
return (
|
||||
<Tabs rootClassName={classes} navRootClassName={css.nav} tabRootClassName={css.tab}>
|
||||
<EditListingDescriptionPanel
|
||||
{...panelProps(DESCRIPTION)}
|
||||
onSubmit={values => {
|
||||
const { title, description, category } = values;
|
||||
const updateValues = {
|
||||
title,
|
||||
description,
|
||||
customAttributes: { category },
|
||||
publicData: { category },
|
||||
};
|
||||
|
||||
if (isNew) {
|
||||
onUpsertListingDraft(updateValues);
|
||||
const pathParams = tabParams(POLICY);
|
||||
// Redirect to location tab
|
||||
history.push(
|
||||
createResourceLocatorString('EditListingPage', routeConfiguration(), pathParams, {})
|
||||
);
|
||||
} else {
|
||||
update(DESCRIPTION, updateValues);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<EditListingPoliciesPanel
|
||||
{...panelProps(POLICY)}
|
||||
onSubmit={values => {
|
||||
const { saunaRules = '' } = values;
|
||||
const updateValues = {
|
||||
publicData: {
|
||||
saunaRules,
|
||||
},
|
||||
};
|
||||
|
||||
if (isNew) {
|
||||
onUpdateListingDraft(updateValues);
|
||||
const pathParams = tabParams(LOCATION);
|
||||
// Redirect to pricing tab
|
||||
history.push(
|
||||
createResourceLocatorString('EditListingPage', routeConfiguration(), pathParams, {})
|
||||
);
|
||||
} else {
|
||||
update(POLICY, updateValues);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<EditListingLocationPanel
|
||||
{...panelProps(LOCATION)}
|
||||
onSubmit={values => {
|
||||
const { building = '', location } = values;
|
||||
const { selectedPlace: { address, origin } } = location;
|
||||
const updateValues = {
|
||||
geolocation: origin,
|
||||
publicData: {
|
||||
location: { address, building },
|
||||
},
|
||||
};
|
||||
|
||||
if (isNew) {
|
||||
onUpdateListingDraft(updateValues);
|
||||
const pathParams = tabParams(PRICING);
|
||||
// Redirect to pricing tab
|
||||
history.push(
|
||||
createResourceLocatorString('EditListingPage', routeConfiguration(), pathParams, {})
|
||||
);
|
||||
} else {
|
||||
update(LOCATION, updateValues);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<EditListingPricingPanel
|
||||
{...panelProps(PRICING)}
|
||||
onSubmit={values => {
|
||||
if (isNew) {
|
||||
onUpdateListingDraft(values);
|
||||
const pathParams = tabParams(PHOTOS);
|
||||
// Redirect to photos tab
|
||||
history.push(
|
||||
createResourceLocatorString('EditListingPage', routeConfiguration(), pathParams, {})
|
||||
);
|
||||
} else {
|
||||
update(PRICING, values);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<EditListingPhotosPanel
|
||||
{...panelProps(PHOTOS)}
|
||||
newListingCreated={newListingCreated}
|
||||
fetchInProgress={fetchInProgress}
|
||||
images={images}
|
||||
onImageUpload={onImageUpload}
|
||||
onRemoveImage={onRemoveImage}
|
||||
onPayoutDetailsFormChange={onPayoutDetailsFormChange}
|
||||
onPayoutDetailsSubmit={onPayoutDetailsSubmit}
|
||||
onSubmit={values => {
|
||||
const { country, images: updatedImages } = values;
|
||||
const updateValues = { ...listing.attributes, country, images: updatedImages };
|
||||
if (isNew) {
|
||||
onCreateListing(updateValues);
|
||||
} else {
|
||||
const imageIds = updatedImages.map(img => img.imageId || img.id);
|
||||
update(PHOTOS, { images: imageIds });
|
||||
}
|
||||
}}
|
||||
onUpdateImageOrder={onUpdateImageOrder}
|
||||
currentUser={currentUser}
|
||||
onManageDisableScrolling={onManageDisableScrolling}
|
||||
/>
|
||||
{TABS.map(tab => {
|
||||
return (
|
||||
<EditListingWizardTab
|
||||
{...rest}
|
||||
key={tab}
|
||||
tabId={`${id}_${tab}`}
|
||||
tabLabel={tabLabel(intl, tab)}
|
||||
tabLinkProps={tabLink(tab)}
|
||||
selected={selectedTab === tab}
|
||||
disabled={!tabsStatus[tab]}
|
||||
tab={tab}
|
||||
intl={intl}
|
||||
params={params}
|
||||
listing={listing}
|
||||
marketplaceTabs={TABS}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
|
@ -315,36 +164,22 @@ class EditListingWizard extends Component {
|
|||
|
||||
EditListingWizard.defaultProps = {
|
||||
className: null,
|
||||
errors: null,
|
||||
listing: null,
|
||||
rootClassName: null,
|
||||
currentUser: null,
|
||||
updatedTab: null,
|
||||
listing: null,
|
||||
};
|
||||
|
||||
const { array, bool, func, number, object, oneOf, shape, string } = PropTypes;
|
||||
const { array, number, object, oneOf, shape, string } = PropTypes;
|
||||
|
||||
EditListingWizard.propTypes = {
|
||||
id: string.isRequired,
|
||||
className: string,
|
||||
rootClassName: string,
|
||||
params: shape({
|
||||
id: string.isRequired,
|
||||
slug: string.isRequired,
|
||||
type: oneOf(['new', 'edit']).isRequired,
|
||||
tab: oneOf(STEPS).isRequired,
|
||||
tab: oneOf(TABS).isRequired,
|
||||
}).isRequired,
|
||||
errors: shape({
|
||||
createListingsError: object,
|
||||
updateListingError: object,
|
||||
showListingsError: object,
|
||||
uploadImageError: object,
|
||||
}).isRequired,
|
||||
fetchInProgress: bool.isRequired,
|
||||
newListingCreated: bool.isRequired,
|
||||
history: shape({
|
||||
push: func.isRequired,
|
||||
}).isRequired,
|
||||
images: array.isRequired,
|
||||
|
||||
// We cannot use propTypes.listing since the listing might be a draft.
|
||||
listing: shape({
|
||||
|
|
@ -359,22 +194,6 @@ EditListingWizard.propTypes = {
|
|||
images: array,
|
||||
}),
|
||||
|
||||
onCreateListing: func.isRequired,
|
||||
onUpdateListing: func.isRequired,
|
||||
onCreateListingDraft: func.isRequired,
|
||||
onImageUpload: func.isRequired,
|
||||
onPayoutDetailsFormChange: func.isRequired,
|
||||
onPayoutDetailsSubmit: func.isRequired,
|
||||
onUpdateImageOrder: func.isRequired,
|
||||
onRemoveImage: func.isRequired,
|
||||
onUpdateListingDraft: func.isRequired,
|
||||
onChange: func.isRequired,
|
||||
rootClassName: string,
|
||||
currentUser: propTypes.currentUser,
|
||||
onManageDisableScrolling: func.isRequired,
|
||||
updatedTab: string,
|
||||
updateInProgress: bool.isRequired,
|
||||
|
||||
// from withViewport
|
||||
viewport: shape({
|
||||
width: number.isRequired,
|
||||
|
|
|
|||
273
src/components/EditListingWizard/EditListingWizardTab.js
Normal file
273
src/components/EditListingWizard/EditListingWizardTab.js
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { intlShape } from 'react-intl';
|
||||
import routeConfiguration from '../../routeConfiguration';
|
||||
import { propTypes } from '../../util/types';
|
||||
import { ensureListing } from '../../util/data';
|
||||
import { createResourceLocatorString } from '../../util/routes';
|
||||
import {
|
||||
EditListingDescriptionPanel,
|
||||
EditListingLocationPanel,
|
||||
EditListingPhotosPanel,
|
||||
EditListingPoliciesPanel,
|
||||
EditListingPricingPanel,
|
||||
} from '../../components';
|
||||
|
||||
import css from './EditListingWizard.css';
|
||||
|
||||
export const DESCRIPTION = 'description';
|
||||
export const POLICY = 'policy';
|
||||
export const LOCATION = 'location';
|
||||
export const PRICING = 'pricing';
|
||||
export const PHOTOS = 'photos';
|
||||
|
||||
// EditListingWizardTab component supports these tabs
|
||||
export const SUPPORTED_TABS = [DESCRIPTION, POLICY, LOCATION, PRICING, PHOTOS];
|
||||
|
||||
const pathParamsToNextTab = (params, tab, marketplaceTabs) => {
|
||||
const nextTabIndex = marketplaceTabs.findIndex(s => s === tab) + 1;
|
||||
const nextTab =
|
||||
nextTabIndex < marketplaceTabs.length
|
||||
? marketplaceTabs[nextTabIndex]
|
||||
: marketplaceTabs[marketplaceTabs.length - 1];
|
||||
return { ...params, tab: nextTab };
|
||||
};
|
||||
|
||||
const EditListingWizardTab = props => {
|
||||
const {
|
||||
tab,
|
||||
marketplaceTabs,
|
||||
params,
|
||||
errors,
|
||||
fetchInProgress,
|
||||
newListingCreated,
|
||||
history,
|
||||
images,
|
||||
listing,
|
||||
onCreateListing,
|
||||
onUpdateListing,
|
||||
onCreateListingDraft,
|
||||
onImageUpload,
|
||||
onPayoutDetailsFormChange,
|
||||
onPayoutDetailsSubmit,
|
||||
onUpdateImageOrder,
|
||||
onRemoveImage,
|
||||
onUpdateListingDraft,
|
||||
onChange,
|
||||
currentUser,
|
||||
onManageDisableScrolling,
|
||||
updatedTab,
|
||||
updateInProgress,
|
||||
intl,
|
||||
} = props;
|
||||
|
||||
const isNew = params.type === 'new';
|
||||
const currentListing = ensureListing(listing);
|
||||
|
||||
const onUpsertListingDraft = currentListing.id ? onUpdateListingDraft : onCreateListingDraft;
|
||||
const update = (tab, values) => {
|
||||
onUpdateListing(tab, { ...values, id: currentListing.id });
|
||||
};
|
||||
const onCompleteEditListingWizardTab = (tab, updateValues) => {
|
||||
if (isNew) {
|
||||
onUpsertListingDraft(updateValues);
|
||||
// Redirect to next tab
|
||||
const pathParams = pathParamsToNextTab(params, tab, marketplaceTabs);
|
||||
history.push(
|
||||
createResourceLocatorString('EditListingPage', routeConfiguration(), pathParams, {})
|
||||
);
|
||||
} else {
|
||||
update(tab, updateValues);
|
||||
}
|
||||
};
|
||||
|
||||
const panelProps = tab => {
|
||||
return {
|
||||
className: css.panel,
|
||||
errors,
|
||||
listing,
|
||||
onChange,
|
||||
panelUpdated: updatedTab === tab,
|
||||
updateInProgress,
|
||||
};
|
||||
};
|
||||
|
||||
switch (tab) {
|
||||
case DESCRIPTION: {
|
||||
const submitButtonTranslationKey = isNew
|
||||
? 'EditListingWizard.saveNewDescription'
|
||||
: 'EditListingWizard.saveEditDescription';
|
||||
return (
|
||||
<EditListingDescriptionPanel
|
||||
{...panelProps(DESCRIPTION)}
|
||||
submitButtonText={intl.formatMessage({ id: submitButtonTranslationKey })}
|
||||
onSubmit={values => {
|
||||
const { title, description, category } = values;
|
||||
const updateValues = {
|
||||
title,
|
||||
description,
|
||||
customAttributes: { category },
|
||||
publicData: { category },
|
||||
};
|
||||
|
||||
onCompleteEditListingWizardTab(tab, updateValues);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case POLICY: {
|
||||
const submitButtonTranslationKey = isNew
|
||||
? 'EditListingWizard.saveNewPolicies'
|
||||
: 'EditListingWizard.saveEditPolicies';
|
||||
return (
|
||||
<EditListingPoliciesPanel
|
||||
{...panelProps(POLICY)}
|
||||
submitButtonText={intl.formatMessage({ id: submitButtonTranslationKey })}
|
||||
onSubmit={values => {
|
||||
const { saunaRules = '' } = values;
|
||||
const updateValues = {
|
||||
publicData: {
|
||||
saunaRules,
|
||||
},
|
||||
};
|
||||
|
||||
onCompleteEditListingWizardTab(tab, updateValues);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case LOCATION: {
|
||||
const submitButtonTranslationKey = isNew
|
||||
? 'EditListingWizard.saveNewLocation'
|
||||
: 'EditListingWizard.saveEditLocation';
|
||||
return (
|
||||
<EditListingLocationPanel
|
||||
{...panelProps(LOCATION)}
|
||||
submitButtonText={intl.formatMessage({ id: submitButtonTranslationKey })}
|
||||
onSubmit={values => {
|
||||
const { building = '', location } = values;
|
||||
const { selectedPlace: { address, origin } } = location;
|
||||
const updateValues = {
|
||||
geolocation: origin,
|
||||
publicData: {
|
||||
location: { address, building },
|
||||
},
|
||||
};
|
||||
|
||||
onCompleteEditListingWizardTab(tab, updateValues);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case PRICING: {
|
||||
const submitButtonTranslationKey = isNew
|
||||
? 'EditListingWizard.saveNewPricing'
|
||||
: 'EditListingWizard.saveEditPricing';
|
||||
return (
|
||||
<EditListingPricingPanel
|
||||
{...panelProps(PRICING)}
|
||||
submitButtonText={intl.formatMessage({ id: submitButtonTranslationKey })}
|
||||
onSubmit={values => {
|
||||
onCompleteEditListingWizardTab(tab, values);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case PHOTOS: {
|
||||
const submitButtonTranslationKey = isNew
|
||||
? 'EditListingWizard.saveNewPhotos'
|
||||
: 'EditListingWizard.saveEditPhotos';
|
||||
return (
|
||||
<EditListingPhotosPanel
|
||||
{...panelProps(PHOTOS)}
|
||||
submitButtonText={intl.formatMessage({ id: submitButtonTranslationKey })}
|
||||
newListingCreated={newListingCreated}
|
||||
fetchInProgress={fetchInProgress}
|
||||
images={images}
|
||||
onImageUpload={onImageUpload}
|
||||
onRemoveImage={onRemoveImage}
|
||||
onPayoutDetailsFormChange={onPayoutDetailsFormChange}
|
||||
onPayoutDetailsSubmit={onPayoutDetailsSubmit}
|
||||
onSubmit={values => {
|
||||
const { images: updatedImages } = values;
|
||||
const updateValues = { ...listing.attributes, images: updatedImages };
|
||||
|
||||
if (isNew) {
|
||||
onCreateListing(updateValues);
|
||||
} else {
|
||||
const imageIds = updatedImages.map(img => img.imageId || img.id);
|
||||
update(PHOTOS, { images: imageIds });
|
||||
}
|
||||
}}
|
||||
onUpdateImageOrder={onUpdateImageOrder}
|
||||
currentUser={currentUser}
|
||||
onManageDisableScrolling={onManageDisableScrolling}
|
||||
/>
|
||||
);
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
EditListingWizardTab.defaultProps = {
|
||||
errors: null,
|
||||
listing: null,
|
||||
currentUser: null,
|
||||
updatedTab: null,
|
||||
};
|
||||
|
||||
const { array, bool, func, object, oneOf, shape, string } = PropTypes;
|
||||
|
||||
EditListingWizardTab.propTypes = {
|
||||
params: shape({
|
||||
id: string.isRequired,
|
||||
slug: string.isRequired,
|
||||
type: oneOf(['new', 'edit']).isRequired,
|
||||
tab: oneOf(SUPPORTED_TABS).isRequired,
|
||||
}).isRequired,
|
||||
errors: shape({
|
||||
createListingsError: object,
|
||||
updateListingError: object,
|
||||
showListingsError: object,
|
||||
uploadImageError: object,
|
||||
}).isRequired,
|
||||
fetchInProgress: bool.isRequired,
|
||||
newListingCreated: bool.isRequired,
|
||||
history: shape({
|
||||
push: func.isRequired,
|
||||
}).isRequired,
|
||||
images: array.isRequired,
|
||||
|
||||
// We cannot use propTypes.listing since the listing might be a draft.
|
||||
listing: shape({
|
||||
attributes: shape({
|
||||
customAttributes: object, // structure (key: value) can be defined in management console
|
||||
publicData: object,
|
||||
description: string,
|
||||
geolocation: object,
|
||||
pricing: object,
|
||||
title: string,
|
||||
}),
|
||||
images: array,
|
||||
}),
|
||||
|
||||
onCreateListing: func.isRequired,
|
||||
onUpdateListing: func.isRequired,
|
||||
onCreateListingDraft: func.isRequired,
|
||||
onImageUpload: func.isRequired,
|
||||
onPayoutDetailsFormChange: func.isRequired,
|
||||
onPayoutDetailsSubmit: func.isRequired,
|
||||
onUpdateImageOrder: func.isRequired,
|
||||
onRemoveImage: func.isRequired,
|
||||
onUpdateListingDraft: func.isRequired,
|
||||
onChange: func.isRequired,
|
||||
currentUser: propTypes.currentUser,
|
||||
onManageDisableScrolling: func.isRequired,
|
||||
updatedTab: string,
|
||||
updateInProgress: bool.isRequired,
|
||||
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default EditListingWizardTab;
|
||||
Loading…
Add table
Reference in a new issue