import React from 'react'; import PropTypes from 'prop-types'; import { compose } from 'redux'; import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; import classNames from 'classnames'; import { FormattedMessage, intlShape, injectIntl } from 'react-intl'; import { createResourceLocatorString, findRouteByRouteName } from '../../util/routes'; import routeConfiguration from '../../routeConfiguration'; import { propTypes } from '../../util/types'; import { ensureListing, ensureTransaction } from '../../util/data'; import { dateFromAPIToLocalNoon } from '../../util/dates'; import { createSlug } from '../../util/urlHelpers'; import { txIsPaymentPending } from '../../util/transaction'; import { getMarketplaceEntities } from '../../ducks/marketplaceData.duck'; import { isScrollingDisabled, manageDisableScrolling } from '../../ducks/UI.duck'; import { initializeCardPaymentData } from '../../ducks/stripe.duck.js'; import { NamedRedirect, TransactionPanel, Page, LayoutSingleColumn, LayoutWrapperTopbar, LayoutWrapperMain, LayoutWrapperFooter, Footer, } from '../../components'; import { TopbarContainer } from '../../containers'; import { acceptSale, declineSale, loadData, setInitialValues, sendMessage, sendReview, fetchMoreMessages, } from './TransactionPage.duck'; import css from './TransactionPage.css'; const PROVIDER = 'provider'; const CUSTOMER = 'customer'; // TransactionPage handles data loading for Sale and Order views to transaction pages in Inbox. export const TransactionPageComponent = props => { const { currentUser, initialMessageFailedToTransaction, fetchMessagesError, fetchMessagesInProgress, totalMessagePages, oldestMessagePageFetched, fetchTransactionError, history, intl, messages, onManageDisableScrolling, onSendMessage, onSendReview, onShowMoreMessages, params, scrollingDisabled, sendMessageError, sendMessageInProgress, sendReviewError, sendReviewInProgress, transaction, transactionRole, acceptInProgress, acceptSaleError, declineInProgress, declineSaleError, onAcceptSale, onDeclineSale, timeSlots, fetchTimeSlotsError, callSetInitialValues, onInitializeCardPaymentData, } = props; const currentTransaction = ensureTransaction(transaction); const currentListing = ensureListing(currentTransaction.listing); const isProviderRole = transactionRole === PROVIDER; const isCustomerRole = transactionRole === CUSTOMER; const redirectToCheckoutPageWithInitialValues = (initialValues, listing) => { const routes = routeConfiguration(); // Customize checkout page state with current listing and selected bookingDates const { setInitialValues } = findRouteByRouteName('CheckoutPage', routes); callSetInitialValues(setInitialValues, initialValues); // Clear previous Stripe errors from store if there is any onInitializeCardPaymentData(); // Redirect to CheckoutPage history.push( createResourceLocatorString( 'CheckoutPage', routes, { id: currentListing.id.uuid, slug: createSlug(currentListing.attributes.title) }, {} ) ); }; // If payment is pending, redirect to CheckoutPage if (txIsPaymentPending(currentTransaction) && isCustomerRole) { const currentBooking = ensureListing(currentTransaction.booking); const initialValues = { listing: currentListing, // Transaction with payment pending should be passed to CheckoutPage transaction: currentTransaction, // Original bookingData content is not available, // but it is already used since booking is created. // (E.g. quantity is used when booking is created.) bookingData: {}, bookingDates: { bookingStart: dateFromAPIToLocalNoon(currentBooking.attributes.start), bookingEnd: dateFromAPIToLocalNoon(currentBooking.attributes.end), }, }; redirectToCheckoutPageWithInitialValues(initialValues, currentListing); } // Customer can create a booking, if the tx is in "enquiry" state. const handleSubmitBookingRequest = values => { const { bookingDates, ...bookingData } = values; const initialValues = { listing: currentListing, // enquired transaction should be passed to CheckoutPage transaction: currentTransaction, bookingData, bookingDates: { bookingStart: bookingDates.startDate, bookingEnd: bookingDates.endDate, }, confirmPaymentError: null, }; redirectToCheckoutPageWithInitialValues(initialValues, currentListing); }; const deletedListingTitle = intl.formatMessage({ id: 'TransactionPage.deletedListing', }); const listingTitle = currentListing.attributes.deleted ? deletedListingTitle : currentListing.attributes.title; // Redirect users with someone else's direct link to their own inbox/sales or inbox/orders page. const isDataAvailable = currentUser && currentTransaction.id && currentTransaction.id.uuid === params.id && currentTransaction.attributes.lineItems && currentTransaction.customer && currentTransaction.provider && !fetchTransactionError; const isOwnSale = isDataAvailable && isProviderRole && currentUser.id.uuid === currentTransaction.provider.id.uuid; const isOwnOrder = isDataAvailable && isCustomerRole && currentUser.id.uuid === currentTransaction.customer.id.uuid; if (isDataAvailable && isProviderRole && !isOwnSale) { // eslint-disable-next-line no-console console.error('Tried to access a sale that was not owned by the current user'); return ; } else if (isDataAvailable && isCustomerRole && !isOwnOrder) { // eslint-disable-next-line no-console console.error('Tried to access an order that was not owned by the current user'); return ; } const detailsClassName = classNames(css.tabContent, css.tabContentVisible); const fetchErrorMessage = isCustomerRole ? 'TransactionPage.fetchOrderFailed' : 'TransactionPage.fetchSaleFailed'; const loadingMessage = isCustomerRole ? 'TransactionPage.loadingOrderData' : 'TransactionPage.loadingSaleData'; const loadingOrFailedFetching = fetchTransactionError ? (

) : (

); const initialMessageFailed = !!( initialMessageFailedToTransaction && currentTransaction.id && initialMessageFailedToTransaction.uuid === currentTransaction.id.uuid ); // TransactionPanel is presentational component // that currently handles showing everything inside layout's main view area. const panel = isDataAvailable ? ( ) : ( loadingOrFailedFetching ); return (
{panel}