UNPKG

@kiwicom/smart-faq

Version:

290 lines (260 loc) 7.84 kB
// @flow import * as React from 'react'; import { graphql, createFragmentContainer } from 'react-relay'; import { withTheme } from 'styled-components'; import css from 'styled-jsx/css'; import Stack from '@kiwicom/orbit-components/lib/Stack'; import { ChevronDown, ChevronUp } from '@kiwicom/orbit-components/lib/icons'; import Button from '@kiwicom/nitro/lib/components/Button'; import ValueBind from '@kiwicom/nitro/lib/components/ValueBind'; import type { ThemeProps } from '@kiwicom/nitro/lib/records/Theme'; // TODO fix comment below // $FlowExpectedError: Flow types are broken in TextNode import TextNode from '@kiwicom/nitro/lib/components/TextNode'; import { updateFAQSection } from '../common/booking/utils'; import bookingTypes from '../common/booking/bookingTypes'; import { BookingState } from '../context/BookingState'; import OneWayBookingHeader from '../SingleBookingPage/bookingItem/BookingHeaders/OneWay'; import ReturnBookingHeader from '../SingleBookingPage/bookingItem/BookingHeaders/Return'; import MultiCityBookingHeader from '../SingleBookingPage/bookingItem/BookingHeaders/Multicity'; import formatBookingId from '../helpers/formatBookingId'; import { replaceWithCurrentDomain } from '../helpers/UrlHelpers'; import { Portrait, Landscape } from '../common/Responsive'; import SelectAnotherBookingLink from '../common/booking/SelectAnotherBookingLink'; import type { MobileBookingDetail_booking as MobileBookingDetailType } from './__generated__/MobileBookingDetail_booking.graphql'; type ContextProps = { onSetFAQSection: (isUrgent: boolean, isPastBooking: boolean) => void, }; type ComponentProps = { +booking: MobileBookingDetailType, onSetFAQSection: (isUrgent: boolean, isPastBooking: boolean) => void, ...ThemeProps, }; type MobileBookingControlsProps = {| +manageBookingURL: ?string, |}; type Props = ComponentProps; type TripIdProps = {| isPastBooking: ?boolean, databaseId: string, |}; const TripId = ({ isPastBooking, databaseId }: TripIdProps) => ( <div style={{ marginTop: '8px' }}> <TextNode type="secondary" dataTest="sfaq-booking-type" spaceAfter="smallest" t={ isPastBooking ? __('smartfaq.single_booking_page.header.booking_id.past') : __('smartfaq.single_booking_page.header.booking_id.upcoming') } values={{ booking_id: ( <span dir="ltr" key={databaseId ?? 0}> {formatBookingId(databaseId ?? 0)} </span> ), }} /> </div> ); type ManageMyBookingButtonProps = {| +manageBookingURL: ?string, |}; const onClickButton = manageBookingURL => { if (typeof window !== 'undefined') { window.open(manageBookingURL, '_blank', 'noopener'); } }; const ManageMyBookingButton = (props: ManageMyBookingButtonProps) => ( <ValueBind value={props.manageBookingURL ?? ''} onChange={onClickButton}> {({ onClick }) => ( <Button t="smartfaq.single_booking_page.booking_detail.manage_my_booking" block onClick={onClick} type="secondary" size="small" dataTest="mobileMMBButton" /> )} </ValueBind> ); const MobileBookingControls = (props: MobileBookingControlsProps) => ( <> <ManageMyBookingButton manageBookingURL={props.manageBookingURL} /> <div style={{ margin: '12px 0 8px', textAlign: 'center' }}> <SelectAnotherBookingLink /> </div> </> ); const MobileBookingSummaryStyle = css.global` .topRow { display: flex; } .topRow:focus { outline: 0; } .Chevron { display: flex; flex-direction: column; justify-content: space-around; cursor: pointer; } `; type State = { expanded: boolean, }; const renderByType = booking => { if (booking.type === bookingTypes.ONE_WAY) { return <OneWayBookingHeader booking={booking} isMobile />; } if (booking.type === bookingTypes.RETURN) { return <ReturnBookingHeader booking={booking} isMobile />; } if (booking.type === bookingTypes.MULTICITY) { return <MultiCityBookingHeader booking={booking} isMobile />; } return null; }; class MobileBookingDetail extends React.Component<Props, State> { state = { expanded: true, }; componentDidMount() { updateFAQSection(this.props); } componentDidUpdate() { updateFAQSection(this.props); } toggle = () => { this.setState(prevState => ({ expanded: !prevState.expanded })); }; renderPortrait() { const { booking, theme } = this.props; const { isPastBooking, databaseId } = booking; return ( <> <div className="topRow" onClick={this.toggle} onKeyDown={this.toggle} role="button" tabIndex="0" > <div style={{ flexGrow: 1 }} data-test="booking-sfaq-itinerary"> <TripId databaseId={databaseId} isPastBooking={isPastBooking} /> {renderByType(booking)} </div> <div className="Chevron"> {this.state.expanded ? ( <ChevronUp customColor={theme.orbit.colorIconTertiary} /> ) : ( <ChevronDown customColor={theme.orbit.colorIconTertiary} /> )} </div> </div> {this.state.expanded ? ( <MobileBookingControls manageBookingURL={ booking.directAccessURL && replaceWithCurrentDomain(booking.directAccessURL) } /> ) : null} <style jsx global> {MobileBookingSummaryStyle} </style> </> ); } renderLandscape() { const { booking, theme } = this.props; const { isPastBooking, databaseId } = booking; return ( <> <Stack justify="between" flex> <div> <TripId databaseId={databaseId} isPastBooking={isPastBooking} /> {renderByType(booking)} </div> <div> <SelectAnotherBookingLink /> </div> </Stack> {this.state.expanded && ( <ManageMyBookingButton manageBookingURL={ booking.directAccessURL && replaceWithCurrentDomain(booking.directAccessURL) } /> )} <Stack justify="center" flex> <div onClick={this.toggle} onKeyDown={this.toggle} role="button" tabIndex="0" style={{ cursor: 'pointer', outline: 'none' }} > {this.state.expanded ? ( <ChevronUp customColor={theme.orbit.colorIconTertiary} /> ) : ( <ChevronDown customColor={theme.orbit.colorIconTertiary} /> )} </div> </Stack> </> ); } render() { return ( <> <Portrait>{this.renderPortrait()}</Portrait> <Landscape>{this.renderLandscape()}</Landscape> </> ); } } const MobileBookingDetailWithFAQHandler = (props: ComponentProps) => ( <BookingState.Consumer> {({ onSetFAQSection }: ContextProps) => ( <MobileBookingDetail {...props} onSetFAQSection={onSetFAQSection} /> )} </BookingState.Consumer> ); export default createFragmentContainer( withTheme(MobileBookingDetailWithFAQHandler), graphql` fragment MobileBookingDetail_booking on BookingInterface { type: __typename databaseId: id(opaque: false) isPastBooking directAccessURL ... on BookingOneWay { ...OneWay_booking trip { departure { time } } } ... on BookingReturn { ...Return_booking outbound { departure { time } } } ... on BookingMulticity { ...Multicity_booking start { time } } } `, );