diff --git a/src/components/EditListingWizard/EditListingWizard.js b/src/components/EditListingWizard/EditListingWizard.js
index d9f3771e..eb041819 100644
--- a/src/components/EditListingWizard/EditListingWizard.js
+++ b/src/components/EditListingWizard/EditListingWizard.js
@@ -4,6 +4,11 @@ import { compose } from 'redux';
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
import classNames from 'classnames';
import { withViewport } from '../../util/contextHelpers';
+import {
+ LISTING_PAGE_PARAM_TYPE_DRAFT,
+ LISTING_PAGE_PARAM_TYPE_NEW,
+ LISTING_PAGE_PARAM_TYPES,
+} from '../../util/urlHelpers';
import { ensureListing } from '../../util/data';
import { PayoutDetailsForm } from '../../forms';
import { Modal, NamedRedirect, Tabs } from '../../components';
@@ -111,11 +116,11 @@ class EditListingWizard extends Component {
this.hasScrolledToTab = false;
this.state = {
- submittedValues: null,
+ draftId: null,
showPayoutDetails: false,
};
this.handleCreateFlowTabScrolling = this.handleCreateFlowTabScrolling.bind(this);
- this.handleCreateListing = this.handleCreateListing.bind(this);
+ this.handlePublishListing = this.handlePublishListing.bind(this);
this.handlePayoutModalClose = this.handlePayoutModalClose.bind(this);
this.handlePayoutSubmit = this.handlePayoutSubmit.bind(this);
}
@@ -124,15 +129,15 @@ class EditListingWizard extends Component {
this.hasScrolledToTab = shouldScroll;
}
- handleCreateListing(values) {
- const { onCreateListing, currentUser } = this.props;
+ handlePublishListing(id) {
+ const { onPublishListingDraft, currentUser } = this.props;
const stripeConnected =
currentUser && currentUser.attributes && currentUser.attributes.stripeConnected;
if (stripeConnected) {
- onCreateListing(values);
+ onPublishListingDraft(id);
} else {
this.setState({
- submittedValues: values,
+ draftId: id,
showPayoutDetails: true,
});
}
@@ -149,7 +154,7 @@ class EditListingWizard extends Component {
.then(() => {
this.setState({ showPayoutDetails: false });
this.props.onManageDisableScrolling('EditListingWizard.payoutModal', false);
- this.props.onCreateListing(this.state.submittedValues);
+ this.props.onPublishListingDraft(this.state.draftId);
})
.catch(() => {
// do nothing
@@ -173,15 +178,22 @@ class EditListingWizard extends Component {
} = this.props;
const selectedTab = params.tab;
- const isNew = params.type === 'new';
+ const isNewListingFlow = [LISTING_PAGE_PARAM_TYPE_NEW, LISTING_PAGE_PARAM_TYPE_DRAFT].includes(
+ params.type
+ );
const rootClasses = rootClassName || css.root;
const classes = classNames(rootClasses, className);
const currentListing = ensureListing(listing);
- const tabsStatus = tabsActive(isNew, currentListing);
+ const tabsStatus = tabsActive(isNewListingFlow, currentListing);
// If selectedTab is not active, redirect to the beginning of wizard
if (!tabsStatus[selectedTab]) {
- return ;
+ const currentTabIndex = TABS.indexOf(selectedTab);
+ const nearestActiveTab = TABS.slice(0, currentTabIndex)
+ .reverse()
+ .find(t => tabsStatus[t]);
+
+ return ;
}
const { width } = viewport;
@@ -220,7 +232,7 @@ class EditListingWizard extends Component {
tabLabel={tabLabel(intl, tab)}
tabLinkProps={tabLink(tab)}
selected={selectedTab === tab}
- disabled={isNew && !tabsStatus[tab]}
+ disabled={isNewListingFlow && !tabsStatus[tab]}
tab={tab}
intl={intl}
params={params}
@@ -228,7 +240,7 @@ class EditListingWizard extends Component {
marketplaceTabs={TABS}
errors={errors}
handleCreateFlowTabScrolling={this.handleCreateFlowTabScrolling}
- handleCreateListing={this.handleCreateListing}
+ handlePublishListing={this.handlePublishListing}
fetchInProgress={fetchInProgress}
/>
);
@@ -276,7 +288,7 @@ EditListingWizard.propTypes = {
params: shape({
id: string.isRequired,
slug: string.isRequired,
- type: oneOf(['new', 'edit']).isRequired,
+ type: oneOf(LISTING_PAGE_PARAM_TYPES).isRequired,
tab: oneOf(TABS).isRequired,
}).isRequired,
@@ -293,14 +305,14 @@ EditListingWizard.propTypes = {
}),
errors: shape({
- createListingsError: object,
+ createListingDraftError: object,
updateListingError: object,
+ publishListingError: object,
showListingsError: object,
uploadImageError: object,
createStripeAccountError: object,
- }),
+ }).isRequired,
fetchInProgress: bool.isRequired,
- onCreateListing: func.isRequired,
onPayoutDetailsFormChange: func.isRequired,
onPayoutDetailsSubmit: func.isRequired,
onManageDisableScrolling: func.isRequired,
diff --git a/src/components/EditListingWizard/EditListingWizardTab.js b/src/components/EditListingWizard/EditListingWizardTab.js
index 5468d583..a73fe7d2 100644
--- a/src/components/EditListingWizard/EditListingWizardTab.js
+++ b/src/components/EditListingWizard/EditListingWizardTab.js
@@ -2,6 +2,11 @@ import React from 'react';
import PropTypes from 'prop-types';
import { intlShape } from 'react-intl';
import routeConfiguration from '../../routeConfiguration';
+import {
+ LISTING_PAGE_PARAM_TYPE_DRAFT,
+ LISTING_PAGE_PARAM_TYPE_NEW,
+ LISTING_PAGE_PARAM_TYPES,
+} from '../../util/urlHelpers';
import { ensureListing } from '../../util/data';
import { createResourceLocatorString } from '../../util/routes';
import {
@@ -34,6 +39,28 @@ const pathParamsToNextTab = (params, tab, marketplaceTabs) => {
return { ...params, tab: nextTab };
};
+// When user has update draft listing, he should be redirected to next EditListingWizardTab
+const redirectAfterDraftUpdate = (listingId, params, tab, marketplaceTabs, history) => {
+ const currentPathParams = {
+ ...params,
+ type: LISTING_PAGE_PARAM_TYPE_DRAFT,
+ id: listingId,
+ };
+ const routes = routeConfiguration();
+
+ // Replace current "new" path to "draft" path.
+ // Browser's back button should lead to editing current draft instead of creating a new one.
+ if (params.type === LISTING_PAGE_PARAM_TYPE_NEW) {
+ const draftURI = createResourceLocatorString('EditListingPage', routes, currentPathParams, {});
+ history.replace(draftURI);
+ }
+
+ // Redirect to next tab
+ const nextPathParams = pathParamsToNextTab(currentPathParams, tab, marketplaceTabs);
+ const to = createResourceLocatorString('EditListingPage', routes, nextPathParams, {});
+ history.push(to);
+};
+
const EditListingWizardTab = props => {
const {
tab,
@@ -41,55 +68,66 @@ const EditListingWizardTab = props => {
params,
errors,
fetchInProgress,
- newListingCreated,
+ newListingPublished,
history,
images,
listing,
handleCreateFlowTabScrolling,
- handleCreateListing,
+ handlePublishListing,
onUpdateListing,
onCreateListingDraft,
onImageUpload,
onUpdateImageOrder,
onRemoveImage,
- onUpdateListingDraft,
onChange,
updatedTab,
updateInProgress,
intl,
} = props;
- const isNew = params.type === 'new';
+ const { type } = params;
+ const isNewURI = type === LISTING_PAGE_PARAM_TYPE_NEW;
+ const isDraftURI = type === LISTING_PAGE_PARAM_TYPE_DRAFT;
+ const isNewListingFlow = isNewURI || isDraftURI;
+
const currentListing = ensureListing(listing);
const imageIds = images => {
return images ? images.map(img => img.imageId || img.id) : null;
};
const onCompleteEditListingWizardTab = (tab, updateValues) => {
- if (isNew) {
- const onUpsertListingDraft =
- tab !== marketplaceTabs[0] ? onUpdateListingDraft : onCreateListingDraft;
- onUpsertListingDraft(updateValues);
+ // Normalize images for API call
+ const { images: updatedImages, ...otherValues } = updateValues;
+ const imageProperty =
+ typeof updatedImages !== 'undefined' ? { images: imageIds(updatedImages) } : {};
+ const updateValuesWithImages = { ...otherValues, ...imageProperty };
- if (tab !== marketplaceTabs[marketplaceTabs.length - 1]) {
- // Create listing flow: smooth scrolling polyfill to scroll to correct tab
- handleCreateFlowTabScrolling(false);
- // Redirect to next tab
- const pathParams = pathParamsToNextTab(params, tab, marketplaceTabs);
- history.push(
- createResourceLocatorString('EditListingPage', routeConfiguration(), pathParams, {})
- );
- } else {
- // Normalize images for API call
- const imageIdArray = imageIds(updateValues.images);
- handleCreateListing({ ...listing.attributes, images: imageIdArray });
- }
+ if (isNewListingFlow) {
+ const onUpsertListingDraft = isNewURI
+ ? (tab, updateValues) => onCreateListingDraft(updateValues)
+ : onUpdateListing;
+
+ const upsertValues = isNewURI
+ ? updateValuesWithImages
+ : { ...updateValuesWithImages, id: currentListing.id };
+
+ onUpsertListingDraft(tab, upsertValues)
+ .then(r => {
+ if (tab !== marketplaceTabs[marketplaceTabs.length - 1]) {
+ // Create listing flow: smooth scrolling polyfill to scroll to correct tab
+ handleCreateFlowTabScrolling(false);
+
+ // After successful saving of draft data, user should be redirected to next tab
+ redirectAfterDraftUpdate(r.data.data.id.uuid, params, tab, marketplaceTabs, history);
+ } else {
+ handlePublishListing(currentListing.id);
+ }
+ })
+ .catch(e => {
+ // No need for extra actions
+ });
} else {
- const { images: updatedImages, ...rest } = updateValues;
- // Normalize images for API call
- const imageProperty =
- typeof updatedImages !== 'undefined' ? { images: imageIds(updatedImages) } : {};
- onUpdateListing(tab, { ...rest, id: currentListing.id, ...imageProperty });
+ onUpdateListing(tab, { ...updateValuesWithImages, id: currentListing.id });
}
};
@@ -106,7 +144,7 @@ const EditListingWizardTab = props => {
switch (tab) {
case DESCRIPTION: {
- const submitButtonTranslationKey = isNew
+ const submitButtonTranslationKey = isNewListingFlow
? 'EditListingWizard.saveNewDescription'
: 'EditListingWizard.saveEditDescription';
return (
@@ -120,7 +158,7 @@ const EditListingWizardTab = props => {
);
}
case FEATURES: {
- const submitButtonTranslationKey = isNew
+ const submitButtonTranslationKey = isNewListingFlow
? 'EditListingWizard.saveNewFeatures'
: 'EditListingWizard.saveEditFeatures';
return (
@@ -134,7 +172,7 @@ const EditListingWizardTab = props => {
);
}
case POLICY: {
- const submitButtonTranslationKey = isNew
+ const submitButtonTranslationKey = isNewListingFlow
? 'EditListingWizard.saveNewPolicies'
: 'EditListingWizard.saveEditPolicies';
return (
@@ -148,7 +186,7 @@ const EditListingWizardTab = props => {
);
}
case LOCATION: {
- const submitButtonTranslationKey = isNew
+ const submitButtonTranslationKey = isNewListingFlow
? 'EditListingWizard.saveNewLocation'
: 'EditListingWizard.saveEditLocation';
return (
@@ -162,7 +200,7 @@ const EditListingWizardTab = props => {
);
}
case PRICING: {
- const submitButtonTranslationKey = isNew
+ const submitButtonTranslationKey = isNewListingFlow
? 'EditListingWizard.saveNewPricing'
: 'EditListingWizard.saveEditPricing';
return (
@@ -176,16 +214,16 @@ const EditListingWizardTab = props => {
);
}
case PHOTOS: {
- const submitButtonTranslationKey = isNew
+ const submitButtonTranslationKey = isNewListingFlow
? 'EditListingWizard.saveNewPhotos'
: 'EditListingWizard.saveEditPhotos';
- // newListingCreated and fetchInProgress are flags for the last wizard tab
+ // newListingPublished and fetchInProgress are flags for the last wizard tab
return (
{
};
EditListingWizardTab.defaultProps = {
- errors: null,
listing: null,
updatedTab: null,
};
@@ -214,19 +251,21 @@ EditListingWizardTab.propTypes = {
params: shape({
id: string.isRequired,
slug: string.isRequired,
- type: oneOf(['new', 'edit']).isRequired,
+ type: oneOf(LISTING_PAGE_PARAM_TYPES).isRequired,
tab: oneOf(SUPPORTED_TABS).isRequired,
}).isRequired,
errors: shape({
- createListingsError: object,
+ createListingDraftError: object,
+ publishListingError: object,
updateListingError: object,
showListingsError: object,
uploadImageError: object,
}).isRequired,
fetchInProgress: bool.isRequired,
- newListingCreated: bool.isRequired,
+ newListingPublished: bool.isRequired,
history: shape({
push: func.isRequired,
+ replace: func.isRequired,
}).isRequired,
images: array.isRequired,
@@ -243,13 +282,12 @@ EditListingWizardTab.propTypes = {
}),
handleCreateFlowTabScrolling: func.isRequired,
- handleCreateListing: func.isRequired,
+ handlePublishListing: func.isRequired,
onUpdateListing: func.isRequired,
onCreateListingDraft: func.isRequired,
onImageUpload: func.isRequired,
onUpdateImageOrder: func.isRequired,
onRemoveImage: func.isRequired,
- onUpdateListingDraft: func.isRequired,
onChange: func.isRequired,
updatedTab: string,
updateInProgress: bool.isRequired,