import { book, validateVoucher, EntryStatus } from '@qite/tide-client'; import { BookingPackageRequest, BookingPackageVoucherRequest, ServiceType } from '@qite/tide-client'; import { Link, useNavigate, useLocation } from 'react-router-dom'; import { compact, findIndex, isEmpty, isNil, uniqBy } from 'lodash'; import React, { useContext, useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { buildClassName } from '../../../shared/utils/class-util'; import { buildTideClientConfig } from '../../../shared/utils/tide-api-utils'; import Icon from '../../../shared/components/icon'; import SettingsContext from '../../settings-context'; import { useAppDispatch } from '../../store'; import { SummaryCheckbox } from '../../types'; import { setBookingNumber, setBookingRemarks, setCurrentStep, setIsOption, setVoucherCodes } from '../booking/booking-slice'; import { CONFIRMATION_STEP, ERROR_STEP, TRAVELERS_FORM_STEP } from '../booking/constants'; import { selectActiveOption, selectAgentAdressId, selectApiSettings, selectBookingPackageBookRequest, selectBookingQueryString, selectDepartureFlight, selectLanguageCode, selectOfficeId, selectPackageDetails, selectReturnFlight, selectRoomOptionDepartureFlightsMetaData, selectRoomOptionReturnFlightsMetaData, selectTranslations } from '../booking/selectors'; import { fetchPriceDetails, selectNotifications, setNotifications } from '../price-details/price-details-slice'; import { getDateText } from '../sidebar/sidebar-util'; import { selectRooms, selectTravelersFormValues } from '../travelers-form/travelers-form-slice'; import SummaryBookingOptionPax from './summary-booking-option-pax'; import SummaryBookingOptionUnit from './summary-booking-option-unit'; import SummaryFlight from './summary-flight'; import SummaryBookingOption from './summary-per-booking-option-group'; import { selectUserValidated, setUserValidated } from './summary-slice'; import Loader from '../../../shared/components/loader'; interface VoucherProps { code?: string; isValidated?: boolean; isValid?: boolean; } interface SummaryProps {} const Summary: React.FC = () => { const dispatch = useAppDispatch(); const settings = useContext(SettingsContext); const navigate = settings.skipRouter ? () => {} : useNavigate(); const [isSubmitting, setIsSubmitting] = useState(false); const [checkboxes, setCheckboxes] = useState(settings.summary?.checkboxes); const [remarks, setRemarks] = useState(''); const [voucher, setVoucher] = useState({}); const bookingQueryString = useSelector(selectBookingQueryString); const travelerFormValues = useSelector(selectTravelersFormValues); const packageDetails = useSelector(selectPackageDetails); const activeOption = useSelector(selectActiveOption); const apiSettings = useSelector(selectApiSettings); const languageCode = useSelector(selectLanguageCode); const officeId = useSelector(selectOfficeId); const agentId = useSelector(selectAgentAdressId); const departureFlight = useSelector(selectDepartureFlight); const departureFlightMetaData = departureFlight?.flightMetaData ?? useSelector(selectRoomOptionDepartureFlightsMetaData)?.[0]; const returnFlight = useSelector(selectReturnFlight); const returnFlightMetaData = returnFlight?.flightMetaData ?? useSelector(selectRoomOptionReturnFlightsMetaData)?.[0]; if (!travelerFormValues) { if (settings.skipRouter) { dispatch(setCurrentStep(TRAVELERS_FORM_STEP)); } else { navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}?${bookingQueryString}`); } } const rooms = useSelector(selectRooms); const userValidated = useSelector(selectUserValidated); const notifications = useSelector(selectNotifications); const bookRequest = useSelector(selectBookingPackageBookRequest); useEffect(() => { // Every checkbox should be checked, or no checkboxes const checkboxesValidated = !isNil(checkboxes) ? checkboxes.every((checkbox) => checkbox.isSelected) : true; const notificationsValidated = !isNil(notifications) ? notifications.filter((x) => x.hasToBeConfirmed).every((checkbox) => checkbox.isConfirmed) : true; dispatch(setUserValidated(checkboxesValidated && notificationsValidated)); }, [checkboxes, notifications]); const handleSubmit: React.FormEventHandler = async (e) => { e.preventDefault(); const submitter = (e.nativeEvent as any).submitter?.name; setIsSubmitting(true); if (typeof window !== 'undefined') { window.scrollTo(0, 0); } const tideClientConfig = buildTideClientConfig(apiSettings); if (!bookRequest || !tideClientConfig) { return; } if (bookRequest.payload.returnPaymentUrl) { if (typeof window !== 'undefined') { const location = window.location; window.scrollTo(0, 0); bookRequest.payload.redirectUrl = `${location.protocol}//${location.host}${settings.basePath}?${bookingQueryString}`; } } try { if (submitter === 'option') { bookRequest.payload.status = EntryStatus.option; bookRequest.payload.customStatusId = settings.customOptionStatus; dispatch(setIsOption(true)); } const bookingResponse = await book(tideClientConfig, bookRequest, undefined, languageCode); // Booking successfull dispatch(setBookingNumber(bookingResponse.number)); if (bookingResponse.paymentUrl) { window.location.href = bookingResponse.paymentUrl; } else { if (settings.skipRouter) { dispatch(setCurrentStep(CONFIRMATION_STEP)); } else { navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.confirmation.pathSuffix}?${bookingQueryString}`); } } } catch (error) { if (settings.skipRouter) { dispatch(setCurrentStep(ERROR_STEP)); } else { navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.error.pathSuffix}?${bookingQueryString}`); } } finally { setIsSubmitting(false); } }; const handleNotificationChange = (id: number, checked: boolean) => { const updatedNotifications = notifications.map((notification) => (notification.id === id ? { ...notification, isConfirmed: checked } : notification)); dispatch(setNotifications(updatedNotifications)); }; const handleCheckboxChange = (id: string, checked: boolean) => { if (isNil(checkboxes)) { return; } const newCheckboxes = [...checkboxes]; const index = findIndex(checkboxes, (checkbox) => checkbox.id === id); newCheckboxes[index].isSelected = !newCheckboxes[index].isSelected; setCheckboxes(newCheckboxes); }; const handleRemarksChange = (text: string) => { dispatch(setBookingRemarks(text)); setRemarks(text); }; const handleValidateVoucher = async () => { if (!voucher?.code) return; const request = { officeId: officeId, agentId: agentId, payload: { code: voucher.code, otherCodes: bookRequest?.payload.voucherCodes ?? [] } } as BookingPackageRequest; const tideClientConfig = buildTideClientConfig(apiSettings); if (!tideClientConfig) return; const result = await validateVoucher(tideClientConfig, request); if (result) { setVoucher({ ...voucher, isValidated: true, isValid: result.isValid }); } }; const handleAddVoucher: React.MouseEventHandler = (event) => { if (!voucher.isValid) return; dispatch(setVoucherCodes([...(bookRequest?.payload.voucherCodes ?? []), voucher.code ?? ''].filter((x) => x !== ''))); dispatch(fetchPriceDetails()); setVoucher({}); }; const handleRemoveVoucher = (code: string) => { dispatch(setVoucherCodes(bookRequest?.payload.voucherCodes?.filter((x) => x !== code) ?? [])); dispatch(fetchPriceDetails()); }; const goPrevious = () => { dispatch(setCurrentStep(TRAVELERS_FORM_STEP)); }; const translations = useSelector(selectTranslations); return ( <> {isSubmitting && (settings.loaderComponent || )} {!isSubmitting && (
{translations.SUMMARY.PERSONAL_DETAILS}
{rooms.map((r, rIndex) => (
{rooms.length > 1 ? `${translations.SHARED.ROOM} ${rIndex + 1}` : translations.ROOM_OPTIONS_FORM.TRAVELER_GROUP}

{`${r.adults.length + r.children.length} ${ r.adults.length + r.children.length === 1 ? translations.SUMMARY.TRAVELER : translations.SUMMARY.TRAVELERS }: ${compact([ r.adults.length, r.adults.length === 1 && ` ${translations.SUMMARY.ADULT}`, r.adults.length > 1 && ` ${translations.SUMMARY.ADULTS}`, r.adults && r.adults.length && r.children && r.children.length && ', ', r.children.length, r.children.length === 1 && ` ${translations.SUMMARY.CHILD}`, r.children.length > 1 && ` ${translations.SUMMARY.CHILDREN}` ]).join('')}`}

{[...r.adults, ...r.children].map((traveler) => { const isMainBooker = traveler.id === travelerFormValues?.mainBookerId; return (
  • {traveler.firstName} {traveler.lastName} {' '} {isMainBooker && ({translations.SUMMARY.MAIN_BOOKER})}
  • {traveler.birthDate.split('-').reverse().join('/')}
  • {isMainBooker && ( <> {travelerFormValues?.street && ( <>
  • {`${travelerFormValues?.street} ${compact([ travelerFormValues?.houseNumber, travelerFormValues?.box ]).join(' ')}, ${travelerFormValues?.zipCode} ${travelerFormValues?.place}`}
  • )} {travelerFormValues?.phone &&
  • {travelerFormValues?.phone}
  • } {travelerFormValues?.email &&
  • {travelerFormValues?.email}
  • } )}
); })}
))}
{translations.SUMMARY.OPTIONS}
    {activeOption?.serviceType == ServiceType.flight ? ( <> {departureFlightMetaData && } {returnFlightMetaData && } ) : ( <> {activeOption?.rooms .flatMap((r) => r.options) .filter((x) => x.isSelected) .map((roomOption, roomOptionIndex) => (
  • {roomOption?.productName}
    • {roomOption?.accommodationName} {!isNil(roomOption?.regimeName) && ', '} {roomOption?.regimeName}

    ( {roomOption?.from === roomOption?.to ? ( getDateText(roomOption?.from) ) : ( <> {getDateText(roomOption?.from)} > {getDateText(roomOption?.to)} )} )

  • {!isEmpty(activeOption?.groups) && activeOption?.groups.map((x, i) => { if (!x.options.some((y) => y.isSelected)) return; return ; })} {!isEmpty(activeOption?.optionUnits) && activeOption?.optionUnits.map((x, i) => )} {!isEmpty(activeOption?.optionPax) && activeOption?.optionPax.map((x, i) => )} {packageDetails?.outwardFlights && packageDetails.outwardFlights .filter((x) => x.isSelected) .map((flight, i) => ( ))} {packageDetails?.returnFlights && packageDetails.returnFlights .filter((x) => x.isSelected) .map((flight, i) => ( ))}
    ))} )}
{settings.enableVoucher && (
{translations.SUMMARY.VOUCHERS}
setVoucher({ code: e.target.value })} />
{voucher.isValid && voucher.isValidated && (
{translations.SUMMARY.VOUCHER_VALID}
)} {!voucher.isValid && voucher.isValidated &&
{translations.SUMMARY.VOUCHER_INVALID}
}
    {!isEmpty(bookRequest?.payload.voucherCodes) && bookRequest?.payload.voucherCodes?.map((y, i) => (
  • {y}{' '}
  • ))}
)} {!isEmpty(notifications) && (
{translations.SUMMARY.NOTIFICATIONS_TITLE}
<> {uniqBy( notifications.filter((x) => !x.hasToBeConfirmed), 'id' ).map((notification) => ( {notification.title} {notification.description} ))} {uniqBy( notifications.filter((x) => x.hasToBeConfirmed), 'id' ).map((notification) => (
))}
)}
{translations.SUMMARY.REMARKS}
{translations.SUMMARY.VALIDATE_TITLE}
{settings.customValidateText ? (
) : ( <>

{settings.isOffer ? translations.SUMMARY.VALIDATE_TEXT_OFFER : translations.SUMMARY.VALIDATE_TEXT_BOOKING}

{settings.allowOption &&

{translations.SUMMARY.VALIDATE_TEXT_OPTION}

} )} {checkboxes && checkboxes.map((checkbox) => (
))}
{settings.skipRouter ? ( ) : ( {translations.STEPS.PREVIOUS} )} {settings.allowOption && ( )}
)} ); }; export default Summary;