import React, { Component } from 'react';
import { array, bool, func, number, object, oneOf, shape, string } from 'prop-types';
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';
import EditListingWizardTab, {
DESCRIPTION,
FEATURES,
POLICY,
LOCATION,
PRICING,
PHOTOS,
} from './EditListingWizardTab';
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, FEATURES, POLICY, LOCATION, PRICING, PHOTOS];
// Tabs are horizontal in small screens
const MAX_HORIZONTAL_NAV_SCREEN_WIDTH = 1023;
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) {
key = 'EditListingWizard.tabLabelLocation';
} else if (tab === PRICING) {
key = 'EditListingWizard.tabLabelPricing';
} else if (tab === PHOTOS) {
key = 'EditListingWizard.tabLabelPhotos';
}
return intl.formatMessage({ id: key });
};
/**
* 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 FEATURES:
return !!(publicData && publicData.amenities);
case POLICY:
return !!(publicData && typeof publicData.rules !== '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. In edit mode all tabs are active.
*
* @param isNew flag if a new listing is being created or an old one being edited
* @param listing data to be checked
*
* @return object containing activity / editability of different tabs of this wizard
*/
const tabsActive = (isNew, listing) => {
return TABS.reduce((acc, tab) => {
const previousTabIndex = TABS.findIndex(t => t === tab) - 1;
const isActive =
previousTabIndex >= 0 ? !isNew || tabCompleted(TABS[previousTabIndex], listing) : true;
return { ...acc, [tab]: isActive };
}, {});
};
const scrollToTab = (tabPrefix, tabId) => {
const el = document.querySelector(`#${tabPrefix}_${tabId}`);
if (el) {
el.scrollIntoView({
block: 'start',
behavior: 'smooth',
});
}
};
// Create a new or edit listing through EditListingWizard
class EditListingWizard extends Component {
constructor(props) {
super(props);
// Having this info in state would trigger unnecessary rerendering
this.hasScrolledToTab = false;
this.state = {
draftId: null,
showPayoutDetails: false,
};
this.handleCreateFlowTabScrolling = this.handleCreateFlowTabScrolling.bind(this);
this.handlePublishListing = this.handlePublishListing.bind(this);
this.handlePayoutModalClose = this.handlePayoutModalClose.bind(this);
this.handlePayoutSubmit = this.handlePayoutSubmit.bind(this);
}
handleCreateFlowTabScrolling(shouldScroll) {
this.hasScrolledToTab = shouldScroll;
}
handlePublishListing(id) {
const { onPublishListingDraft, currentUser } = this.props;
const stripeConnected =
currentUser && currentUser.attributes && currentUser.attributes.stripeConnected;
if (stripeConnected) {
onPublishListingDraft(id);
} else {
this.setState({
draftId: id,
showPayoutDetails: true,
});
}
}
handlePayoutModalClose() {
this.setState({ showPayoutDetails: false });
}
handlePayoutSubmit(values) {
const { fname: firstName, lname: lastName, ...rest } = values;
this.props
.onPayoutDetailsSubmit({ firstName, lastName, ...rest })
.then(() => {
this.setState({ showPayoutDetails: false });
this.props.onManageDisableScrolling('EditListingWizard.payoutModal', false);
this.props.onPublishListingDraft(this.state.draftId);
})
.catch(() => {
// do nothing
});
}
render() {
const {
id,
className,
rootClassName,
params,
listing,
viewport,
intl,
errors,
fetchInProgress,
onManageDisableScrolling,
onPayoutDetailsFormChange,
...rest
} = this.props;
const selectedTab = params.tab;
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(isNewListingFlow, currentListing);
// If selectedTab is not active, redirect to the beginning of wizard
if (!tabsStatus[selectedTab]) {
const currentTabIndex = TABS.indexOf(selectedTab);
const nearestActiveTab = TABS.slice(0, currentTabIndex)
.reverse()
.find(t => tabsStatus[t]);
return