EditListingWizard: use onCreateListingDraft and onPublishListingDraft

instead of plain createListing.
This commit is contained in:
Vesa Luusua 2018-11-07 12:24:40 +02:00
parent 98e279542d
commit 9e48a1fca7
2 changed files with 106 additions and 56 deletions

View file

@ -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 <NamedRedirect name="EditListingPage" params={{ ...params, tab: TABS[0] }} />;
const currentTabIndex = TABS.indexOf(selectedTab);
const nearestActiveTab = TABS.slice(0, currentTabIndex)
.reverse()
.find(t => tabsStatus[t]);
return <NamedRedirect name="EditListingPage" params={{ ...params, tab: nearestActiveTab }} />;
}
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,

View file

@ -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 (
<EditListingPhotosPanel
{...panelProps(PHOTOS)}
submitButtonText={intl.formatMessage({ id: submitButtonTranslationKey })}
newListingCreated={newListingCreated}
newListingPublished={newListingPublished}
fetchInProgress={fetchInProgress}
images={images}
onImageUpload={onImageUpload}
@ -203,7 +241,6 @@ const EditListingWizardTab = props => {
};
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,