@kiwicom/smart-faq
Version:
240 lines (216 loc) • 7.3 kB
JavaScript
// @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 HolidayTrip from './bookingTypes/HolidayTrip/HolidayTrip';
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 OwnProps = {|
+booking: BookingDetailType,
history: RouterHistory,
|};
type Props = {|
...OwnProps,
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} />;
}
if (booking.type === bookingTypes.HOLIDAY) {
return <HolidayTrip 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: OwnProps) => {
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
}
}
... on BookingHoliday {
...HolidayTrip_booking
}
...Contact_booking
}
`,
);