import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { injectIntl, intlShape, FormattedMessage } from 'react-intl'; import classNames from 'classnames'; import { txIsEnquired, txIsRequested, propTypes } from '../../util/types'; import { ensureListing, ensureTransaction, ensureUser } from '../../util/data'; import { isMobileSafari } from '../../util/userAgent'; import { AvatarMedium, AvatarLarge, ResponsiveImage, ReviewModal } from '../../components'; import { SendMessageForm } from '../../containers'; // These are internal components that make this file more readable. import { BreakdownMaybe, FeedSection, OrderActionButtonMaybe, SaleActionButtonsMaybe, TransactionPageTitle, TransactionPageMessage, displayNames, } from './TransactionPanel.helpers'; import css from './TransactionPanel.css'; export class TransactionPanelComponent extends Component { constructor(props) { super(props); this.state = { sendMessageFormFocused: false, isReviewModalOpen: false, reviewSubmitted: false, }; this.isMobSaf = false; this.sendMessageFormName = 'TransactionPanel.SendMessageForm'; this.onOpenReviewModal = this.onOpenReviewModal.bind(this); this.onSubmitReview = this.onSubmitReview.bind(this); this.onSendMessageFormFocus = this.onSendMessageFormFocus.bind(this); this.onSendMessageFormBlur = this.onSendMessageFormBlur.bind(this); this.onMessageSubmit = this.onMessageSubmit.bind(this); this.scrollToMessage = this.scrollToMessage.bind(this); } componentWillMount() { this.isMobSaf = isMobileSafari(); } onOpenReviewModal() { this.setState({ isReviewModalOpen: true }); } onSubmitReview(values) { const { onSendReview, transaction, transactionRole } = this.props; const currentTransaction = ensureTransaction(transaction); const { reviewRating, reviewContent } = values; const rating = Number.parseInt(reviewRating, 10); onSendReview(transactionRole, currentTransaction, rating, reviewContent) .then(r => this.setState({ isReviewModalOpen: false, reviewSubmitted: true })) .catch(e => { // Do nothing. }); } onSendMessageFormFocus() { this.setState({ sendMessageFormFocused: true }); if (this.isMobSaf) { // Scroll to bottom window.scroll({ top: document.body.scrollHeight, left: 0, behavior: 'smooth' }); } } onSendMessageFormBlur() { this.setState({ sendMessageFormFocused: false }); } onMessageSubmit(values) { const message = values.message ? values.message.trim() : null; const { transaction, onResetForm, onSendMessage } = this.props; const ensuredTransaction = ensureTransaction(transaction); if (!message) { return; } onSendMessage(ensuredTransaction.id, message) .then(messageId => { onResetForm(this.sendMessageFormName); this.scrollToMessage(messageId); }) .catch(e => { // Ignore, Redux handles the error }); } scrollToMessage(messageId) { const selector = `#msg-${messageId.uuid}`; const el = document.querySelector(selector); if (el) { el.scrollIntoView({ block: 'start', behavior: 'smooth', }); } } render() { const { rootClassName, className, currentUser, transaction, totalMessagePages, oldestMessagePageFetched, messages, initialMessageFailed, fetchMessagesInProgress, fetchMessagesError, sendMessageInProgress, sendMessageError, sendReviewInProgress, sendReviewError, onManageDisableScrolling, onShowMoreMessages, transactionRole, intl, onAcceptSale, onDeclineSale, acceptInProgress, declineInProgress, acceptSaleError, declineSaleError, } = this.props; const currentTransaction = ensureTransaction(transaction); const currentListing = ensureListing(currentTransaction.listing); const currentProvider = ensureUser(currentTransaction.provider); const currentCustomer = ensureUser(currentTransaction.customer); const isCustomer = transactionRole === 'customer'; const isProvider = transactionRole === 'provider'; const listingLoaded = !!currentListing.id; const listingDeleted = listingLoaded && currentListing.attributes.deleted; const customerLoaded = !!currentCustomer.id; const isCustomerBanned = customerLoaded && currentCustomer.attributes.banned; const canShowSaleButtons = isProvider && txIsRequested(currentTransaction) && !isCustomerBanned; const isProviderLoaded = !!currentProvider.id; const isProviderBanned = isProviderLoaded && currentProvider.attributes.banned; const canShowBookButton = isCustomer && txIsEnquired(currentTransaction) && !isProviderBanned; const bannedUserDisplayName = intl.formatMessage({ id: 'TransactionPanel.bannedUserDisplayName', }); const deletedListingTitle = intl.formatMessage({ id: 'TransactionPanel.deletedListingTitle', }); const { authorDisplayName, customerDisplayName, otherUserDisplayName } = displayNames( currentUser, currentProvider, currentCustomer, bannedUserDisplayName ); const listingTitle = currentListing.attributes.deleted ? deletedListingTitle : currentListing.attributes.title; const firstImage = currentListing.images && currentListing.images.length > 0 ? currentListing.images[0] : null; const actionButtonClasses = classNames(css.actionButtons); const canShowActionButtons = canShowBookButton || canShowSaleButtons; let actionButtons = null; if (canShowSaleButtons) { actionButtons = ( ); } else if (canShowBookButton) { actionButtons = ( ); } const sendMessagePlaceholder = intl.formatMessage( { id: 'TransactionPanel.sendMessagePlaceholder' }, { name: otherUserDisplayName } ); const sendMessageFormClasses = classNames(css.sendMessageForm); const showInfoMessage = listingDeleted || (!listingDeleted && txIsRequested(transaction)); // !!orderInfoMessage; const feedContainerClasses = classNames(css.feedContainer, { [css.feedContainerWithInfoAbove]: showInfoMessage, }); const classes = classNames(rootClassName || css.root, className); return (
{isProvider ? (
) : null}
{canShowActionButtons ? (
{actionButtons}
) : null}
{isCustomer ? (
) : null} {isCustomer ? (

{listingTitle}

) : null} {canShowActionButtons ? (
{actionButtons}
) : null}
this.setState({ isReviewModalOpen: false })} onManageDisableScrolling={onManageDisableScrolling} onSubmitReview={this.onSubmitReview} revieweeName={authorDisplayName} reviewSent={this.state.reviewSubmitted} sendReviewInProgress={sendReviewInProgress} sendReviewError={sendReviewError} />
); } } TransactionPanelComponent.defaultProps = { rootClassName: null, className: null, currentUser: null, acceptSaleError: null, declineSaleError: null, fetchMessagesError: null, initialMessageFailed: null, sendMessageError: null, sendReviewError: null, }; const { arrayOf, bool, func, number, string } = PropTypes; TransactionPanelComponent.propTypes = { rootClassName: string, className: string, currentUser: propTypes.currentUser, transaction: propTypes.transaction.isRequired, totalMessagePages: number.isRequired, oldestMessagePageFetched: number.isRequired, messages: arrayOf(propTypes.message).isRequired, initialMessageFailed: bool, fetchMessagesInProgress: bool.isRequired, fetchMessagesError: propTypes.error, sendMessageInProgress: bool.isRequired, sendMessageError: propTypes.error, sendReviewInProgress: bool.isRequired, sendReviewError: propTypes.error, onManageDisableScrolling: func.isRequired, onShowMoreMessages: func.isRequired, onSendMessage: func.isRequired, onSendReview: func.isRequired, onResetForm: func.isRequired, // Sale related props onAcceptSale: func.isRequired, onDeclineSale: func.isRequired, acceptInProgress: bool.isRequired, declineInProgress: bool.isRequired, acceptSaleError: propTypes.error, declineSaleError: propTypes.error, // from injectIntl intl: intlShape, }; const TransactionPanel = injectIntl(TransactionPanelComponent); export default TransactionPanel;