From 9e48a1fca7904c9dbbfef24dc82b6c83c113c2e1 Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Wed, 7 Nov 2018 12:24:40 +0200 Subject: [PATCH] EditListingWizard: use onCreateListingDraft and onPublishListingDraft instead of plain createListing. --- .../EditListingWizard/EditListingWizard.js | 44 ++++--- .../EditListingWizard/EditListingWizardTab.js | 118 ++++++++++++------ 2 files changed, 106 insertions(+), 56 deletions(-) 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,