diff --git a/src/components/EditListingFeaturesPanel/EditListingFeaturesPanel.css b/src/components/EditListingFeaturesPanel/EditListingFeaturesPanel.css new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/components/EditListingFeaturesPanel/EditListingFeaturesPanel.css @@ -0,0 +1 @@ + diff --git a/src/components/EditListingFeaturesPanel/EditListingFeaturesPanel.js b/src/components/EditListingFeaturesPanel/EditListingFeaturesPanel.js new file mode 100644 index 00000000..9ee0f039 --- /dev/null +++ b/src/components/EditListingFeaturesPanel/EditListingFeaturesPanel.js @@ -0,0 +1,98 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { FormattedMessage } from 'react-intl'; +import { toPairs } from 'lodash'; + +import { ensureListing } from '../../util/data'; +import { createSlug } from '../../util/urlHelpers'; +import { EditListingFeaturesForm } from '../../containers'; +import { NamedLink } from '../../components'; + +const EditListingFeaturesPanel = props => { + const { + rootClassName, + className, + listing, + onSubmit, + onChange, + submitButtonText, + panelUpdated, + updateInProgress, + errors, + } = props; + + const classes = classNames(rootClassName || className); + const currentListing = ensureListing(listing); + const { title, publicData } = currentListing.attributes; + const listingTitle = title || ''; + const listingLink = currentListing.id ? ( + + {listingTitle} + + ) : ( + '' + ); + + const panelTitle = currentListing.id ? ( + + ) : ( + + ); + + const currentFeaturesArray = publicData && publicData.amenities; + const currentFeatures = + currentFeaturesArray && + currentFeaturesArray.reduce((map, key) => { + map[key] = true; + return map; + }, {}); + + return ( +
+

{panelTitle}

+ { + const entries = toPairs(values); + const amenities = entries.filter(entry => entry[1] === true).map(entry => entry[0]); + + const updatedValues = { + publicData: { amenities }, + }; + onSubmit(updatedValues); + }} + onChange={onChange} + saveActionMsg={submitButtonText} + updated={panelUpdated} + updateError={errors.updateListingError} + updateInProgress={updateInProgress} + /> +
+ ); +}; + +EditListingFeaturesPanel.defaultProps = { + rootClassName: null, + className: null, + listing: null, +}; + +const { bool, func, object, string } = PropTypes; + +EditListingFeaturesPanel.propTypes = { + rootClassName: string, + className: string, + + // We cannot use propTypes.listing since the listing might be a draft. + listing: object, + + onSubmit: func.isRequired, + onChange: func.isRequired, + submitButtonText: string.isRequired, + panelUpdated: bool.isRequired, + updateInProgress: bool.isRequired, + errors: object.isRequired, +}; + +export default EditListingFeaturesPanel; diff --git a/src/components/EditListingWizard/EditListingWizard.js b/src/components/EditListingWizard/EditListingWizard.js index 0206f3bb..cf78c783 100644 --- a/src/components/EditListingWizard/EditListingWizard.js +++ b/src/components/EditListingWizard/EditListingWizard.js @@ -9,6 +9,7 @@ import { NamedRedirect, Tabs } from '../../components'; import EditListingWizardTab, { DESCRIPTION, + FEATURES, POLICY, LOCATION, PRICING, @@ -18,7 +19,7 @@ import css from './EditListingWizard.css'; // 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]; +export const TABS = [DESCRIPTION, FEATURES, POLICY, LOCATION, PRICING, PHOTOS]; // Tabs are horizontal in small screens const MAX_HORIZONTAL_NAV_SCREEN_WIDTH = 1023; @@ -27,6 +28,8 @@ const tabLabel = (intl, tab) => { let key = null; if (tab === DESCRIPTION) { key = 'EditListingWizard.tabLabelDescription'; + } else if (tab === FEATURES) { + key = 'EditListingWizard.tabLabelFeatures'; } else if (tab === POLICY) { key = 'EditListingWizard.tabLabelPolicy'; } else if (tab === LOCATION) { @@ -55,6 +58,8 @@ const tabCompleted = (tab, listing) => { switch (tab) { case DESCRIPTION: return !!(description && title); + case FEATURES: + return !!(publicData && publicData.amenities); case POLICY: return !!(publicData && typeof publicData.rules !== 'undefined'); case LOCATION: diff --git a/src/components/EditListingWizard/EditListingWizardTab.js b/src/components/EditListingWizard/EditListingWizardTab.js index 750c3851..d218972d 100644 --- a/src/components/EditListingWizard/EditListingWizardTab.js +++ b/src/components/EditListingWizard/EditListingWizardTab.js @@ -7,6 +7,7 @@ import { ensureListing } from '../../util/data'; import { createResourceLocatorString } from '../../util/routes'; import { EditListingDescriptionPanel, + EditListingFeaturesPanel, EditListingLocationPanel, EditListingPhotosPanel, EditListingPoliciesPanel, @@ -16,13 +17,14 @@ import { import css from './EditListingWizard.css'; export const DESCRIPTION = 'description'; +export const FEATURES = 'features'; 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]; +export const SUPPORTED_TABS = [DESCRIPTION, FEATURES, POLICY, LOCATION, PRICING, PHOTOS]; const pathParamsToNextTab = (params, tab, marketplaceTabs) => { const nextTabIndex = marketplaceTabs.findIndex(s => s === tab) + 1; @@ -104,6 +106,20 @@ const EditListingWizardTab = props => { /> ); } + case FEATURES: { + const submitButtonTranslationKey = isNew + ? 'EditListingWizard.saveNewFeatures' + : 'EditListingWizard.saveEditFeatures'; + return ( + { + onCompleteEditListingWizardTab(tab, values); + }} + /> + ); + } case POLICY: { const submitButtonTranslationKey = isNew ? 'EditListingWizard.saveNewPolicies' diff --git a/src/components/index.js b/src/components/index.js index 9fa3a22e..1488e437 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -16,6 +16,9 @@ export { default as Discussion } from './Discussion/Discussion'; export { default as EditListingDescriptionPanel, } from './EditListingDescriptionPanel/EditListingDescriptionPanel'; +export { + default as EditListingFeaturesPanel, +} from './EditListingFeaturesPanel/EditListingFeaturesPanel'; export { default as EditListingLocationPanel, } from './EditListingLocationPanel/EditListingLocationPanel'; diff --git a/src/translations/en.json b/src/translations/en.json index aa562f0a..6cbdd521 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -120,6 +120,8 @@ "EditListingDescriptionPanel.createListingTitle": "Add your sauna", "EditListingDescriptionPanel.title": "Edit details of {listingTitle}", "EditListingFeaturesForm.updateFailed": "Failed to update listing. Please try again.", + "EditListingFeaturesPanel.createListingTitle": "What amenities does your sauna have?", + "EditListingFeaturesPanel.title": "Edit the amenities of {listingTitle}", "EditListingLocationForm.address": "Address", "EditListingLocationForm.addressNotRecognized": "We didn't recognize this location. Please try another location.", "EditListingLocationForm.addressPlaceholder": "123 Example Street", @@ -161,16 +163,19 @@ "EditListingPricingPanel.listingPriceCurrencyInvalid": "Listing currency is different from the marketplace currency. You cannot edit the price.", "EditListingPricingPanel.title": "Edit the pricing of {listingTitle}", "EditListingWizard.saveEditDescription": "Save description", + "EditListingWizard.saveEditFeatures": "Save amenities", "EditListingWizard.saveEditLocation": "Save location", "EditListingWizard.saveEditPhotos": "Save photos", "EditListingWizard.saveEditPolicies": "Save rules", "EditListingWizard.saveEditPricing": "Save pricing", - "EditListingWizard.saveNewDescription": "Next: Policies", + "EditListingWizard.saveNewDescription": "Next: Amenities", + "EditListingWizard.saveNewFeatures": "Next: Rules", "EditListingWizard.saveNewLocation": "Next: Pricing", "EditListingWizard.saveNewPhotos": "Publish listing", "EditListingWizard.saveNewPolicies": "Next: location", "EditListingWizard.saveNewPricing": "Next: Photos", "EditListingWizard.tabLabelDescription": "Description", + "EditListingWizard.tabLabelFeatures": "Amenities", "EditListingWizard.tabLabelLocation": "Location", "EditListingWizard.tabLabelPhotos": "Photos", "EditListingWizard.tabLabelPolicy": "Sauna rules",