UNPKG

@qite/tide-booking-component

Version:

React Booking wizard & Booking product component for Tide

419 lines (345 loc) 13.1 kB
import JsonURL from "@jsonurl/jsonurl"; import { Gender } from "@qite/tide-client"; import { BookingPackageAddress, BookingPackageBookRequest, BookingPackagePax, BookingPackageRequest, } from "@qite/tide-client/build/types"; import { createSelector } from "@reduxjs/toolkit"; import { format, parseISO } from "date-fns"; import { omit } from "lodash"; import { getTranslations } from "../../../shared/utils/localization-util"; import { RootState } from "../../store"; import { FlightInfo, Room, Traveler } from "../../types"; import { selectNotifications } from "../price-details/price-details-slice"; import { selectAgentId, selectTravelersFormValues, } from "../travelers-form/travelers-form-slice"; export const selectCurrentStep = (state: RootState) => state.booking.currentStep; export const selectGeneratePaymentUrl = (state: RootState) => state.booking.generatePaymentUrl; export const selectSkipPaymentWithAgent = (state: RootState) => state.booking.skipPaymentWithAgent; export const selectIsFetchingProductOptions = (state: RootState) => state.booking.isBusy; export const selectDepartureFlight = (state: RootState) => state.booking.package?.outwardFlights?.find((x) => x.isSelected); export const selectReturnFlight = (state: RootState) => state.booking.package?.returnFlights?.find((x) => x.isSelected); export const selectPackageRooms = (state: RootState) => state.booking.package?.options.find((x) => x.isSelected)?.rooms; export const selectAvailabilities = (state: RootState) => state.booking.package?.options.find((x) => x.isSelected)?.availabilities; export const selectPackageTags = (state: RootState) => state.booking.package?.tags; export const selectIsOnRequest = (state: RootState) => state.booking.package?.options.find((x) => x.isSelected)?.isOnRequest; export const selectPackageOptionUnits = (state: RootState) => state.booking.package?.options.find((x) => x.isSelected)?.optionUnits; export const selectPackageOptionPax = (state: RootState) => state.booking.package?.options.find((x) => x.isSelected)?.optionPax; export const selectPackageGroups = (state: RootState) => state.booking.package?.options.find((x) => x.isSelected)?.groups; export const selectPackageDetails = (state: RootState) => state.booking.package; export const selectPackageFlights = (state: RootState) => ({ outward: state.booking.package?.outwardFlights, return: state.booking.package?.returnFlights }); export const selectActiveOption = (state: RootState) => state.booking.package?.options.find((x) => x.isSelected); export const selectPackageAirlineGroups = createSelector( selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airlineGroups .filter(x => x.flightIds.includes(departureFlight?.entryLineGuid ?? "") || x.flightIds.includes(returnFlight?.entryLineGuid ?? ""))); export const selectPackageAirportGroups = createSelector( selectActiveOption, selectDepartureFlight, selectReturnFlight, (option, departureFlight, returnFlight) => option?.airportGroups .filter(x => x.flightIds.includes(departureFlight?.entryLineGuid ?? "") || x.flightIds.includes(returnFlight?.entryLineGuid ?? ""))); export const selectApiSettings = (state: RootState) => state.apiSettings; export const selectIsUnavailable = (state: RootState) => state.booking.isUnavailable; export const selectRequestRooms = (state: RootState) => state.booking.package?.options.find((x) => x.isSelected)?.requestRooms; export const selectOfficeId = (state: RootState) => state.booking.officeId; export const selectLanguageCode = (state: RootState) => state.booking.languageCode; export const selectTranslations = (state: RootState) => { const defaultStaticTranslations = getTranslations(state.booking.languageCode) as Record<string, any>; const dynamicTranslations = (state.booking.translations && state.booking.translations.find(x => x.language == state.booking.languageCode)?.value) ?? {}; const merged = {} as Record<string, any>; for (const key of Array.from(new Set([...Object.keys(defaultStaticTranslations), ...Object.keys(dynamicTranslations)]))) { merged[key] = { ...(defaultStaticTranslations[key] || {}), ...(dynamicTranslations[key] || {}) }; } return merged; } export const selectBookingOptions = (state: RootState) => state.booking.bookingOptions; export const selectBookingType = (state: RootState) => state.booking.bookingType; export const selectTagIds = (state: RootState) => state.booking.tagIds; export const selectAgentAdressId = (state: RootState) => state.booking.agentAdressId; export const selectProductAttributes = (state: RootState) => state.booking.productAttributes; export const selectBookingAttributes = (state: RootState) => state.booking.bookingAttributes; export const selectBookingNumber = (state: RootState) => state.booking.bookingNumber; export const selectBookingRooms = (state: RootState) => state.booking.bookingAttributes?.rooms; export const selectBookingRemarks = (state: RootState) => state.booking.remarks; export const selectVoucherCodes = (state: RootState) => state.booking.voucherCodes; export const selectCalculateDeposit = (state: RootState) => state.booking.calculateDeposit; export const selectIsRetry = (state: RootState) => state.booking.isRetry; export const selectStartDate = (state: RootState) => state.booking.package?.options.find((x) => x.isSelected)?.fromDate; export const selectAgents = (state: RootState) => state.booking.agents; export const selectProductCode = (state: RootState) => state.booking.productAttributes?.productCode; export const selectAccommodationCodes = (state: RootState) => { const accommodationCodes: string[] = []; state.booking.package?.options.forEach(o => { o.rooms.forEach(r => r.options.forEach(ro => { if (!accommodationCodes.some(y => y === ro.accommodationCode)) { accommodationCodes.push(ro.accommodationCode) } })) }); return accommodationCodes; } export const selectAccommodationViews = (state: RootState) => state.booking.accommodationViews; export const selectBookingQuery = (state: RootState) => { const bookingAttributes = state.booking.bookingAttributes; if (!bookingAttributes) { return undefined; } const params: Record<string, string> = {}; Object.entries(bookingAttributes).forEach(([key, value]) => { if (key === "startDate" || key === "endDate") { value = format(parseISO(value), "yyyy-MM-dd"); } if (key === "rooms") { value = JsonURL.stringify( (value as Room[]).map((room) => omit(room, ["children"])), { AQF: true, } ); } if (key === "allotmentIds" && !value.length) { value = undefined; } if (key === "flight" && value) { var flightInfo = value as FlightInfo; value = JsonURL.stringify(flightInfo, { AQF: true }); } if (value) { params[key] = value; } }); return params; }; export const selectBookingQueryString = createSelector( selectBookingQuery, (params) => { if (!params) { return undefined; } return Object.keys(params) .filter((key) => typeof params[key] !== "undefined") .map((key) => `${key}=${params[key]}`) .join("&"); } ); export const selectMainBookerId = createSelector( selectTravelersFormValues, (formValues) => formValues?.mainBookerId ); export const selectBookingPackagePax = createSelector( selectTravelersFormValues, (formValues) => { var pax: BookingPackagePax[] = []; formValues?.rooms.forEach((r) => r.adults.forEach((x) => { const adultPax = buildPax(x, formValues?.mainBookerId); if (adultPax.isMainBooker) { adultPax.mobilePhone = formValues?.phone; adultPax.email = formValues?.email; } pax.push(adultPax); }) ); formValues?.rooms.forEach((r) => r.children.forEach((x) => { pax.push(buildPax(x)); }) ); return pax; } ); export const selectBookingAddress = createSelector( selectTravelersFormValues, selectBookingPackagePax, selectBookingType, (formValues, pax, bookingType) => { const mainBooker = pax.find((x) => x.isMainBooker); if (!mainBooker || bookingType == "b2b") return undefined; return { name: `${mainBooker.firstName} ${mainBooker.lastName}`, street: formValues?.street, number: formValues?.houseNumber, box: formValues?.box, postalCode: formValues?.zipCode, location: formValues?.place, country: formValues?.country, mobilePhone: formValues?.phone, email: formValues?.email, } as BookingPackageAddress; } ); export const selectBookingPackageRequest = createSelector( selectOfficeId, selectAgentId, selectAgentAdressId, (officeId, agentId, agentAdressId) => { const agencyId = (agentId ?? agentAdressId ?? 0) > 0 ? agentId ?? agentAdressId : null; return { officeId: officeId, agentId: agencyId, payload: null, } as BookingPackageRequest<any>; } ); export const selectBookingPackageBookRequest = createSelector( selectBookingPackageRequest, selectBookingOptions, selectBookingType, selectBookingPackagePax, selectBookingAddress, selectPackageDetails, selectCalculateDeposit, selectAgentId, selectGeneratePaymentUrl, selectSkipPaymentWithAgent, selectNotifications, selectTagIds, selectBookingRemarks, selectVoucherCodes, ( bookingPackageRequest: BookingPackageRequest<BookingPackageBookRequest>, bookingOptions, bookingType, pax, address, packageDetails, calculateDeposit, agentId, generatePaymentUrl, skipPaymentWithAgent, notifications, tagIds, remarks, voucherCodes ) => { if (!packageDetails) return null; let returnPaymentUrl = false; if (generatePaymentUrl && (!skipPaymentWithAgent || (agentId ?? 0) == 0)) { returnPaymentUrl = true; } var entryStatus = 0; var customEntryStatusId = undefined; switch (bookingType) { case "b2b": if (bookingOptions.b2b.tagIds && bookingOptions.b2b.tagIds.length > 0) { tagIds = tagIds?.concat(bookingOptions.b2b.tagIds); } if (bookingOptions.b2b.entryStatus) { entryStatus = bookingOptions.b2b.entryStatus; } if (bookingOptions.b2b.customEntryStatusId) { customEntryStatusId = bookingOptions.b2b.customEntryStatusId; } break; case "b2b2c": if ( bookingOptions.b2b2c.tagIds && bookingOptions.b2b2c.tagIds.length > 0 ) { tagIds = tagIds?.concat(bookingOptions.b2b2c.tagIds); } if (bookingOptions.b2b2c.entryStatus) { entryStatus = bookingOptions.b2b2c.entryStatus; } if (bookingOptions.b2b2c.customEntryStatusId) { customEntryStatusId = bookingOptions.b2b2c.customEntryStatusId; } break; default: if (bookingOptions.b2c.tagIds && bookingOptions.b2c.tagIds.length > 0) { tagIds = tagIds?.concat(bookingOptions.b2c.tagIds); } if (bookingOptions.b2c.entryStatus) { entryStatus = bookingOptions.b2c.entryStatus; } if (bookingOptions.b2c.customEntryStatusId) { customEntryStatusId = bookingOptions.b2c.customEntryStatusId; } break; } bookingPackageRequest.payload = { package: packageDetails, status: entryStatus, customStatusId: customEntryStatusId, address: address, pax: pax?.length != 0 ? pax : packageDetails.options[0].requestRooms.flatMap((x) => x.pax), nonTravelPax: [], calculateDeposit: calculateDeposit, returnPaymentUrl: returnPaymentUrl, notifications: notifications, tagIds: tagIds, remarks: remarks, voucherCodes: voucherCodes, customerRequests: [], }; return bookingPackageRequest; } ); const buildPax = (traveler: Traveler, mainBookerId?: number) => { return { id: traveler.id, gender: parseGender(traveler.gender), firstName: traveler.firstName, lastName: traveler.lastName, dateOfBirth: traveler.birthDate, isMainBooker: traveler.id == mainBookerId, } as BookingPackagePax; }; const parseGender = (gender: string): number => { switch (gender) { case "m": return Gender.male; case "f": return Gender.female; case "x": default: return Gender.other; } };