import { Route, Routes, useLocation, useNavigate } from 'react-router-dom'; import React, { useContext } from 'react'; import { useSelector } from 'react-redux'; import { getDateFromParams, getFlightsFromParams, getNumberFromParams, getNumbersFromParams, getRoomsFromParams, getStringFromParams } from '../../../shared/utils/query-string-util'; import { fetchPackage, setAccommodationViewId, setAgentAdressId, setBookingAttributes, setBookingNumber, setBookingOptions, setBookingType, setCalculateDeposit, setGeneratePaymentUrl, setIsRetry, setIsUnavailable, setLanguageCode, setOfficeId, setPackage, setProductAttributes, setShowCommission, setSkipPayment, setTagIds, setTranslations, setTravelersFirstStep } from './booking-slice'; import { isEqual, isNil } from 'lodash'; import { useEffect } from 'react'; import StepRoute from '../../components/step-route'; import SettingsContext from '../../settings-context'; import { useAppDispatch } from '../../store'; import { BookingAttributes } from '../../types'; import Confirmation from '../confirmation/confirmation'; import Error from '../error/error'; import FlightOptionsForm from '../flight-options'; import OptionsForm from '../product-options/options-form'; import RoomOptionsForm from '../room-options'; import Sidebar from '../sidebar'; import Summary from '../summary/summary'; import TravelersForm from '../travelers-form/travelers-form'; import { selectBookingAttributes, selectBookingNumber, selectBookingRooms, selectIsRetry, selectIsUnavailable, selectPackageDetails, selectProductAttributes, selectTranslations, selectTravelersFirstStep } from './selectors'; interface BookingProps { productCode: string; productName: string; thumbnailUrl?: string; } const Booking: React.FC = ({ productCode, productName, thumbnailUrl }) => { const { officeId, bookingOptions, basePath, roomOptions, flightOptions, options, travellers, summary, confirmation, error, showSidebarDeposit, showCommission, includeFlights, loaderComponent, skipPaymentWithAgent, generatePaymentUrl, tagIds, agentAdressId, language, translationFiles, accommodationViewId, isOffer, allowOption, skipBasePathInRouting } = useContext(SettingsContext); const dispatch = useAppDispatch(); const location = useLocation(); const navigate = useNavigate(); const productAttributes = useSelector(selectProductAttributes); const bookingAttributes = useSelector(selectBookingAttributes); const rooms = useSelector(selectBookingRooms); const bookingNumber = useSelector(selectBookingNumber); const isRetry = useSelector(selectIsRetry); const packageDetails = useSelector(selectPackageDetails); const isUnavailable = useSelector(selectIsUnavailable); const translations = useSelector(selectTranslations); const travelersFirstStep = useSelector(selectTravelersFirstStep); useEffect(() => { return () => { dispatch(setPackage(undefined)); dispatch(setBookingAttributes(undefined)); dispatch(setProductAttributes(undefined)); }; }, []); useEffect(() => { dispatch(setSkipPayment(skipPaymentWithAgent ?? false)); dispatch(setGeneratePaymentUrl(generatePaymentUrl ?? false)); }, [skipPaymentWithAgent, generatePaymentUrl]); useEffect(() => { const params = new URLSearchParams(location.search); const startDate = getDateFromParams(params, 'startDate'); const endDate = getDateFromParams(params, 'endDate'); const catalogueId = getNumberFromParams(params, 'catalogueId') ?? getNumberFromParams(params, 'catalog'); let rooms = getRoomsFromParams(params, 'rooms'); if (!rooms || !rooms.length) { dispatch(setTravelersFirstStep(true)); rooms = [{ adults: 2, children: 0, childAges: [] }]; } if (travellers.travelersFirstStep === true) { dispatch(setTravelersFirstStep(true)); } const flight = getFlightsFromParams(params, 'flight'); const flightRouteId = getStringFromParams(params, 'flightRouteId'); const vendorConfigurationId = getNumberFromParams(params, 'vendorConfigurationId'); const allotmentName = getStringFromParams(params, 'allotmentName'); const allotmentIds = getNumbersFromParams(params, 'allotmentId'); const tourCode = getStringFromParams(params, 'tourCode'); const productCode = getStringFromParams(params, 'productCode'); const productName = getStringFromParams(params, 'productName'); const bookingNumber = params.get('bookingNr') ?? undefined; if (typeof window !== 'undefined') { window.scrollTo(0, 0); } if (!isNil(bookingNumber)) { dispatch(setBookingNumber(bookingNumber)); navigate(`${!skipBasePathInRouting ? basePath : ''}${confirmation.pathSuffix}?bookingNr=${bookingNumber}`); } const nextBookingAttrs = { startDate, endDate, catalogueId, rooms, flight, includeFlights, allotmentName, allotmentIds, tourCode, flightRouteId, vendorConfigurationId, productCode, productName } as BookingAttributes; if (!isNil(startDate) && !isNil(endDate) && !isNil(catalogueId) && !isNil(rooms)) { if (!isEqual(bookingAttributes, nextBookingAttrs)) { dispatch(setBookingAttributes(nextBookingAttrs)); } } else { console.error('Failure when setting booking attributes', startDate, endDate, catalogueId, rooms); } }, [location.search, setBookingAttributes, setBookingNumber, includeFlights]); useEffect(() => { if (!productAttributes || !bookingAttributes || !isNil(bookingNumber) || !isRetry) { return; } // Retried dispatch(setIsRetry(false)); dispatch(setIsUnavailable(false)); // Fetch data const promise = dispatch(fetchPackage()); return () => { promise.abort(); }; }, [isRetry]); useEffect(() => { const params = new URLSearchParams(location.search); const foundproductCode = getStringFromParams(params, 'productCode') ?? productCode; const foundproductName = getStringFromParams(params, 'productName') ?? productName; const next = { productCode: foundproductCode, productName: foundproductName }; if (!isNil(foundproductCode) && !isNil(foundproductName)) { if (!isEqual(productAttributes, next)) { dispatch(setProductAttributes(next)); } } else { console.error('Failure when setting product attributes', productCode, productName); } }, [location.search, productCode, productName, setProductAttributes]); const getTranslations = async () => { const translations = translationFiles?.map((x) => fetch(x.path) .then((y) => y.json()) .then((z) => ({ language: x.language, value: z })) ); return translations && (await Promise.all(translations)); }; useEffect(() => { const loadTranslations = async () => { const translations = await getTranslations(); dispatch(setTranslations(translations)); // Now dispatch the resolved value }; loadTranslations(); dispatch(setOfficeId(officeId)); dispatch(setLanguageCode(language)); dispatch(setBookingOptions(bookingOptions)); dispatch(setCalculateDeposit(showSidebarDeposit)); dispatch(setShowCommission(showCommission)); if (tagIds && tagIds.length > 0) { dispatch(setTagIds(tagIds ?? undefined)); } dispatch(setAgentAdressId(agentAdressId ?? undefined)); if (agentAdressId && agentAdressId != 0) { dispatch(setBookingType('b2b')); } if (accommodationViewId && accommodationViewId != 0) { dispatch(setAccommodationViewId(accommodationViewId)); } }, [ officeId, language, bookingOptions, showSidebarDeposit, showCommission, setOfficeId, setLanguageCode, setCalculateDeposit, tagIds, agentAdressId, accommodationViewId ]); useEffect(() => { if (!productAttributes || !bookingAttributes || !rooms?.length || !isNil(bookingNumber) || !isNil(packageDetails)) { return; } // Fetch data const promise = dispatch(fetchPackage()); return () => { promise.abort(); }; }, [productAttributes]); let numberIndex = 1; return ( <> {((productAttributes && bookingAttributes && packageDetails) || bookingNumber) && (
{travelersFirstStep && ( } />} /> )} {!flightOptions.isHidden && flightOptions.pathSuffix && ( } />} /> )} {!roomOptions.isHidden && roomOptions.pathSuffix && ( } />} /> )} } />} /> {!travelersFirstStep && ( } />} /> )} } />} /> } />} /> } />} />
)} {!packageDetails && !bookingNumber && !isUnavailable && (
{loaderComponent}

{allowOption ? translations.MAIN.PREPARING_DOSSIER : isOffer ? translations.MAIN.PREPARING_OFFER : translations.MAIN.PREPARING_BOOKING}

)} {isUnavailable && !travelersFirstStep && (

{translations.MAIN.PRODUCT_UNAVAILABLE}

)} ); }; export default Booking;