UNPKG

@kiwicom/smart-faq

Version:

227 lines (206 loc) 7.01 kB
// @flow import * as React from 'react'; import { withRouter } from 'react-router-dom'; import type { RouterHistory } from 'react-router-dom'; import { graphql, createFragmentContainer } from 'react-relay'; import differenceInHours from 'date-fns/difference_in_hours'; import { Stack, ButtonLink, TextLink } from '@kiwicom/orbit-components'; import { BaggageChecked, Ticket, Insurance, } from '@kiwicom/orbit-components/lib/icons'; import Translate from '@kiwicom/nitro/lib/components/Translate'; import LogContext from '@kiwicom/nitro/lib/services/log/context'; import { isUrgentBooking, updateFAQSection, getDepartureTimeByType, } from '../common/booking/utils'; import OneWayTrip from './bookingTypes/OneWayTrip/OneWayTrip'; import ReturnTrip from './bookingTypes/ReturnTrip/ReturnTrip'; import MulticityOverlayTrip from './bookingTypes/MulticityTrip/OverlayWrap'; import Contact from './bookingItem/Contact'; import Notification from './bookingItem/Notification'; import Header from './bookingItem/Header'; import MMBButton from './bookingItem/MMBButton'; import ScrollableContent from '../common/ScrollableContent'; import bookingTypes from '../common/booking/bookingTypes'; import { URGENCY_THRESHOLD } from '../helpers/dateUtils'; import { replaceWithCurrentDomain, addDeepLink } from '../helpers/UrlHelpers'; import type { BookingDetail_booking as BookingDetailType } from './__generated__/BookingDetail_booking.graphql'; import FAQExtraInfoButton from '../../shared/StaticFAQ/FAQExtraInfo/FAQExtraInfoButton'; import { BookingState } from '../context/BookingState'; import features from '../../feature-toggles.json'; import { events } from '../../const/events'; import type { log } from '../../const/events'; type Props = {| +booking: BookingDetailType, history: RouterHistory, log: log, onSetFAQSection: (isUrgent: boolean, isPastBooking: boolean) => void, |}; class BookingDetail extends React.Component<Props> { componentDidMount() { updateFAQSection(this.props); } componentDidUpdate() { updateFAQSection(this.props); } decideIfIsFutureAndUrgent = (time: ?Date) => { const timeDelta = time ? differenceInHours(time, new Date()) : null; const isUrgent = timeDelta !== null && URGENCY_THRESHOLD > timeDelta && timeDelta >= 0; return { timeDelta, isFuture: timeDelta !== null && timeDelta > 0, isUrgent, }; }; handleInsuranceClick = () => { const { log } = this.props; log(events.BOOKING_INSURANCE_ADD, {}); }; handleEtickedClick = () => { const { log } = this.props; log(events.BOOKING_ETICKET_CLICKED, {}); }; renderByType = (booking: BookingDetailType) => { if (booking.type === bookingTypes.ONE_WAY) { return <OneWayTrip booking={booking} />; } if (booking.type === bookingTypes.RETURN) { return <ReturnTrip booking={booking} />; } if (booking.type === bookingTypes.MULTICITY) { return <MulticityOverlayTrip booking={booking} />; } return null; }; render() { const { booking } = this.props; const eTicketLink = booking.assets?.ticketUrl; const departureTime = getDepartureTimeByType(booking); const departureInfo = this.decideIfIsFutureAndUrgent(departureTime); const { timeDelta, isFuture } = departureInfo; const isUrgent = isUrgentBooking(booking.isPastBooking, departureTime); const isInsuranceAvailable = Boolean( (booking.availableServices?.insurance?.passengers ?? []).length, ); const mmbUrl = booking.directAccessURL; return ( <ScrollableContent dataCy="nearestBooking" styles="width: 100%; padding:40px; background-color: #ffffff; box-shadow: inset -1px 0 0 0 #e8edf1;" > <div data-test={booking.isPastBooking ? 'past' : 'upcoming'}> <Header booking={booking} isFuture={!booking.isPastBooking} /> </div> {features.notification && (isFuture && booking.status === 'CONFIRMED' && timeDelta && ( <Notification hoursLeft={timeDelta} isUrgent={isUrgent} /> ))} <Stack direction="row" wrap spaceAfter="normal" dataTest="booking-sfaq-buttons" > {features.baggage_info && ( <FAQExtraInfoButton category="baggage" icon={<BaggageChecked />}> <Translate t="smartfaq.single_booking_page.booking_detail.baggage" /> </FAQExtraInfoButton> )} <FAQExtraInfoButton category="boarding-passes" icon={<Ticket />} dataTest="btn-boarding-passes" > <Translate t="smartfaq.single_booking_page.booking_detail.boarding_passes" /> </FAQExtraInfoButton> {isInsuranceAvailable && mmbUrl && ( <ButtonLink onClick={this.handleInsuranceClick} external iconLeft={<Insurance />} href={replaceWithCurrentDomain(addDeepLink(mmbUrl, 'insurance'))} > <Translate t="smartfaq.single_booking_page.booking_detail.insurance" /> </ButtonLink> )} </Stack> <div data-test="booking-sfaq-itinerary"> {this.renderByType(booking)} </div> <Stack direction="column"> {mmbUrl && <MMBButton url={mmbUrl} />} {eTicketLink && ( <TextLink href={eTicketLink} type="secondary" external onClick={this.handleEtickedClick} size="normal" > <Translate t="smartfaq.single_booking_page.booking_detail.download_e_ticket" /> </TextLink> )} </Stack> {isUrgent && <Contact booking={booking} dataTest="contact" />} </ScrollableContent> ); } } export const RawBookingDetail = BookingDetail; const BookingDetailWithFAQHandler = (props: Props) => { const { onSetFAQSection } = React.useContext(BookingState); const { log } = React.useContext(LogContext); return ( <BookingDetail {...props} onSetFAQSection={onSetFAQSection} log={log} /> ); }; export default createFragmentContainer( withRouter(BookingDetailWithFAQHandler), graphql` fragment BookingDetail_booking on BookingInterface { type: __typename status assets { ticketUrl } availableServices { insurance { passengers { databaseId } } } directAccessURL isPastBooking ...Header_booking ... on BookingOneWay { ...OneWayTrip_booking trip { departure { time } } } ... on BookingReturn { ...ReturnTrip_booking outbound { departure { time } } } ... on BookingMulticity { ...OverlayWrap_booking start { time } } ...Contact_booking } `, );