UNPKG

@qite/tide-booking-component

Version:

React Booking wizard & Booking product component for Tide

401 lines (333 loc) 16 kB
import { BookingPackageFlight, BookingPackageFlightMetaDataLine } from "@qite/tide-client/build/types"; import { differenceInMinutes, isEqual, parseISO } from "date-fns"; import { FlightDirectionFilter, FlightFilterOption, FlightFilterOptions, GroupedFlightDetails, GroupedFlights } from "../../types"; /*interface FlightGroup { code: string; startDate: Date, endDate: Date; options: BookingPackageFlight[]; }*/ export const buildGroupedFlights = (outwardFlights: BookingPackageFlight[] | undefined, returnFlights: BookingPackageFlight[] | undefined) => { if (!outwardFlights || !returnFlights) return [] as GroupedFlights[]; // let outwardGroups = groupFlights(outwardFlights); // let returnGroups = groupFlights(returnFlights); const pairs: { outward: BookingPackageFlight, return: BookingPackageFlight }[] = []; outwardFlights.forEach(outwardFlight => { if (outwardFlight.externalGuid) { const returnFlight = returnFlights.find(x => x.externalGuid === outwardFlight.externalGuid)!; pairs.push({ outward: outwardFlight, return: returnFlight }); } else { const outwardCode = outwardFlight.code.substring(0, 7); const returnCode = outwardCode.split(" ").reduce((a, b) => `${b} ${a}`); returnFlights.filter(x => x.code.startsWith(returnCode)).forEach(returnFlight => { pairs.push({ outward: outwardFlight, return: returnFlight }); }); } }); const results = pairs.map(x => { const outwardFlightDetails = getFlightDetails(x.outward); const returnFlightDetails = getFlightDetails(x.return); return { isSelected: x.outward.isSelected && x.return.isSelected, price: x.outward.price + x.return.price, outward: outwardFlightDetails, return: returnFlightDetails, selectedOutward: x.outward, selectedReturn: x.return } as GroupedFlights; }); return results; } export const buildFilterOptions = ( outwardFlights: BookingPackageFlight[] | undefined, returnFlights: BookingPackageFlight[] | undefined, translations: any ) => { if (!outwardFlights || !returnFlights) return undefined; const airports: FlightFilterOption[] = []; const airlines: FlightFilterOption[] = []; const numberOfStops: FlightFilterOption[] = []; const outwardDeparturePeriods: FlightFilterOption[] = []; const returnDeparturePeriods: FlightFilterOption[] = []; let lowestDepartureTravelDuration = 9999; let highestDepartureTravelDuration = 0 let lowestDepartureChangeDuration = 9999; let highestDepartureChangeDuration = 0; outwardFlights.forEach(flight => { const airlineCode = flight.code.split('/')[1]; if (flight.flightMetaData.flightLines?.length) { const firstLine = flight.flightMetaData.flightLines[0]; if (!airports.some(x => x.value === firstLine.departureAirport)) { airports.push({ value: firstLine?.departureAirport, label: firstLine.departureAirportDescription, count: 0, isSelected: false }); } } if (!airlines.some(x => x.value === airlineCode)) { airlines.push({ value: airlineCode, label: flight.airlineDescription, count: 0, isSelected: false }); } const stopCount = flight.flightMetaData.flightLines.length - 1; if (!numberOfStops.some(x => x.value === (stopCount + ''))) { numberOfStops.push({ value: (stopCount + ''), label: stopCount === 0 ? translations.FLIGHTS_FORM.DIRECT_FLIGHT : stopCount == 1 ? `${stopCount} ${translations.FLIGHTS_FORM.STOP}` : `${stopCount} ${translations.FLIGHTS_FORM.STOPS}`, count: 0, isSelected: false }); } const departureTime = flight.flightMetaData.flightLines[0].departureTime; const timeBracket = determineTimeBracket(departureTime); if (!outwardDeparturePeriods.some(x => x.value === timeBracket)) { outwardDeparturePeriods.push({ value: timeBracket, label: getBracketTranslation(timeBracket, translations), count: 0, isSelected: false }); } const travelDurationInMinutes = minutesFromTicks(flight.flightMetaData.durationInTicks); if (travelDurationInMinutes > highestDepartureTravelDuration) highestDepartureTravelDuration = travelDurationInMinutes; if (travelDurationInMinutes < lowestDepartureTravelDuration) lowestDepartureTravelDuration = travelDurationInMinutes; const changeDurationInMinutes = getTotalChangeDuration(flight); if (changeDurationInMinutes > highestDepartureChangeDuration) highestDepartureChangeDuration = changeDurationInMinutes; if (changeDurationInMinutes < lowestDepartureChangeDuration) lowestDepartureChangeDuration = changeDurationInMinutes; }); let lowestReturnTravelDuration = 9999; let highestReturnTravelDuration = 0 let lowestReturnChangeDuration = 9999; let highestReturnChangeDuration = 0; returnFlights.forEach(flight => { const durationInMinutes = minutesFromTicks(flight.flightMetaData.durationInTicks); if (durationInMinutes > highestReturnTravelDuration) highestReturnTravelDuration = durationInMinutes; if (durationInMinutes < lowestReturnTravelDuration) lowestReturnTravelDuration = durationInMinutes; const changeDurationInMinutes = getTotalChangeDuration(flight); if (changeDurationInMinutes > highestReturnChangeDuration) highestReturnChangeDuration = changeDurationInMinutes; if (changeDurationInMinutes < lowestReturnChangeDuration) lowestReturnChangeDuration = changeDurationInMinutes; const departureTime = flight.flightMetaData.flightLines[0].departureTime; const timeBracket = determineTimeBracket(departureTime); if (!returnDeparturePeriods.some(x => x.value === timeBracket)) { returnDeparturePeriods.push({ value: timeBracket, label: getBracketTranslation(timeBracket, translations), count: 0, isSelected: false }); } }) return { airports: airports, airlines: airlines, numberOfStops: numberOfStops, outward: { departurePeriod: outwardDeparturePeriods, travelDuration: { min: lowestDepartureTravelDuration, max: highestDepartureTravelDuration, selectedMin: lowestDepartureTravelDuration, selectedMax: highestDepartureTravelDuration }, changeDuration: { min: lowestDepartureChangeDuration, max: highestDepartureChangeDuration, selectedMin: lowestDepartureChangeDuration, selectedMax: highestDepartureChangeDuration } }, return: { departurePeriod: returnDeparturePeriods, travelDuration: { min: lowestReturnTravelDuration, max: highestReturnTravelDuration, selectedMin: lowestReturnTravelDuration, selectedMax: highestReturnTravelDuration }, changeDuration: { min: lowestReturnChangeDuration, max: highestReturnChangeDuration, selectedMin: lowestReturnChangeDuration, selectedMax: highestReturnChangeDuration } } } as FlightFilterOptions; } export const filterGroupedFlights = (groups: GroupedFlights[], filterOptions: FlightFilterOptions | undefined) => { if (!groups.length || !filterOptions) return []; let filteredGroups = groups; if (filterOptions.airlines.some(x => x.isSelected)) { const selectedAirlineCodes = filterOptions.airlines.filter(x => x.isSelected); filteredGroups = filteredGroups.filter(x => selectedAirlineCodes.some(y => y.value === x.outward.airlineCode)); } if (filterOptions.airports.some(x => x.isSelected)) { const selectedAirlineCodes = filterOptions.airports.filter(x => x.isSelected); filteredGroups = filteredGroups.filter(x => selectedAirlineCodes.some(y => y.value === x.outward.departureAirportCode)); } if (filterOptions.numberOfStops.some(x => x.isSelected)) { const selectedNumberOfStops = filterOptions.numberOfStops.filter(x => x.isSelected); filteredGroups = filteredGroups.filter(x => selectedNumberOfStops.some(y => parseInt(y.value) === (x.outward.flightLines.length - 1))); } filteredGroups = filterGroupedFlightByDirection(filteredGroups, true, filterOptions.outward); filteredGroups = filterGroupedFlightByDirection(filteredGroups, false, filterOptions.return); return filteredGroups; } const filterGroupedFlightByDirection = (groups: GroupedFlights[], isOutward: boolean, directionFilter: FlightDirectionFilter) => { let filteredGroups = groups; if (directionFilter.departurePeriod.some(x => x.isSelected)) { const selectedDeparturePeriods = directionFilter.departurePeriod.filter(x => x.isSelected); filteredGroups = filteredGroups.filter(x => selectedDeparturePeriods.some(y => y.value === determineTimeBracket((isOutward ? x.outward : x.return).departureTime))); } filteredGroups = filteredGroups.filter(x => directionFilter.travelDuration.selectedMin <= (isOutward ? x.outward : x.return).travelDurationMinutes && (isOutward ? x.outward : x.return).travelDurationMinutes <= directionFilter.travelDuration.selectedMax); return filteredGroups.filter(x => directionFilter.changeDuration.selectedMin <= (isOutward ? x.outward : x.return).changeDurationMinutes && (isOutward ? x.outward : x.return).changeDurationMinutes <= directionFilter.changeDuration.selectedMax); } export const formatMinutes = (minutes: number) => { var hh = Math.floor(minutes / 60); var mm = Math.floor(minutes % 60); return pad(hh, 2) + ":" + pad(mm, 2); } const getFlightDetails = (flight: BookingPackageFlight) => { const firstLine = flight.flightMetaData.flightLines[0]; const lastLine = flight.flightMetaData.flightLines[flight.flightMetaData.flightLines.length - 1]; const airlineCode = flight.code.split('/')[1]; const waitDurations = getWaitDurations(flight.flightMetaData.flightLines); return { airline: flight.airlineDescription, airlineCode: airlineCode, departureDate: firstLine.departureDate, departureTime: firstLine.departureTime, departureAirportCode: firstLine.departureAirport, departureAirport: firstLine.departureAirportDescription, arrivalDate: lastLine.arrivalDate, arrivalTime: lastLine.arrivalTime, arrivalAirport: lastLine.arrivalAirportDescription, travelDuration: formatDuration(flight.flightMetaData.durationInTicks), travelDurationMinutes: minutesFromTicks(flight.flightMetaData.durationInTicks), changeDurationMinutes: getTotalChangeDuration(flight), numberOfStops: flight.flightMetaData.flightLines.length - 1, isNextDay: isNextDay(firstLine.departureDate, lastLine.arrivalDate), travelClass: firstLine.travelClass, flightLines: flight.flightMetaData.flightLines.map((x, i) => ({ airline: x.operatingAirlineDescription, departureDate: x.departureDate, departureTime: x.departureTime, departureAirport: x.departureAirportDescription, arrivalDate: x.arrivalDate, arrivalTime: x.arrivalTime, arrivalAirport: x.arrivalAirportDescription, number: `${x.airlineCode} ${x.number}`, travelDuration: formatDuration(x.durationInTicks), waitDuration: waitDurations.length - 1 <= i ? waitDurations[i] : undefined, })) } as GroupedFlightDetails; } const isNextDay = (startDateString: string, endDateString: string) => { const startDate = parseISO(startDateString); const endDate = parseISO(endDateString); return !isEqual(startDate, endDate); } const getWaitDurations = (lines: BookingPackageFlightMetaDataLine[]) => { if (lines.length <= 1) return []; let arrivalDate = lines[0].arrivalDate; let arrivalTime = lines[0].arrivalTime; const waitDurations: string[] = []; for (var i = 1; i < lines.length; i++) { const line = lines[i]; const waitDuration = getWaitDuration(arrivalDate, arrivalTime, line.departureDate, line.departureTime); waitDurations.push(waitDuration); arrivalDate = line.arrivalDate; arrivalTime = line.arrivalTime; } return waitDurations; } const getWaitDuration = (arrivalDateString: string, arrivalTime: string, departureDateString: string, departureTime: string) => { const minutes = getWaitDurationInMinutes(arrivalDateString, arrivalTime, departureDateString, departureTime); var hh = Math.floor(minutes / 60); var mm = Math.floor(minutes % 60); return pad(hh, 2) + ":" + pad(mm, 2); } const getWaitDurationInMinutes = (arrivalDateString: string, arrivalTime: string, departureDateString: string, departureTime: string) => { const arrivalDate = parseISO(arrivalDateString); const arrivalTimeParts = arrivalTime.split(':'); arrivalDate.setHours(parseInt(arrivalTimeParts[0])); arrivalDate.setMinutes(parseInt(arrivalTimeParts[1])); const departureDate = parseISO(departureDateString); const departureTimeParts = departureTime.split(':'); departureDate.setHours(parseInt(departureTimeParts[0])); departureDate.setMinutes(parseInt(departureTimeParts[1])); return differenceInMinutes(departureDate, arrivalDate); } /*const groupFlights = (flights: BookingPackageFlight[]) => { let flightsPool = [...flights]; let groups = [] as FlightGroup[]; for (var i = 0; i < flightsPool.length; i++) { const flight = flightsPool[i]; const relatedFlights = flightsPool.filter(x => x != flight && x.code === flight.code && isDateEqual(x.startDateTime, flight.startDateTime) && isDateEqual(x.endDateTime, flight.endDateTime) ); flightsPool = flightsPool.filter(x => x != flight && relatedFlights.some(y => y != x)); groups.push({ code: flight.code, startDate: parseISO(flight.startDateTime), endDate: parseISO(flight.endDateTime), options: [flight, ...relatedFlights] }); } } const isDateEqual = (first: string, second: string) => { const firstDate = parseISO(first); const secondDate = parseISO(second); return isEqual(firstDate, secondDate); }*/ const minutesFromTicks = (ticks: number) => { const totalSeconds = ticks / 10_000_000; return Math.floor(totalSeconds / 60); } const formatDuration = (ticks: number) => { if (!ticks) return ''; const totalSeconds = ticks / 10_000_000; var hh = Math.floor(totalSeconds / 3600); var mm = Math.floor((totalSeconds % 3600) / 60); return pad(hh, 2) + ":" + pad(mm, 2); } const pad = (input: number, width: number) => { const n = input + ''; return n.length >= width ? n : new Array(width - n.length + 1).join('0') + n; } const determineTimeBracket = (input: string) => { const time = parseInt(input.replace(':', '')); if (time <= 500) return '0000-0500'; if (time > 500 && time <= 1200) return '0500-1200'; if (time > 1200 && time <= 1800) return '1201-1800'; return '1800-2400'; } const getBracketTranslation = (input: string, translations: any) => { if (input === '0000-0500') return translations.FLIGHTS_FORM.NIGHT_DEPARTURE; if (input === '0500-1200') return translations.FLIGHTS_FORM.MORNING_DEPARTURE; if (input === '1200-1800') return translations.FLIGHTS_FORM.AFTERNOON_DEPARTURE; return translations.FLIGHTS_FORM.EVENING_DEPARTURE; } const getTotalChangeDuration = (flight: BookingPackageFlight) => { const lines = flight.flightMetaData.flightLines; if (lines.length <= 1) return 0; let arrivalDate = lines[0].arrivalDate; let arrivalTime = lines[0].arrivalTime; let waitDuration = 0; for (var i = 1; i < lines.length; i++) { const line = lines[i]; waitDuration += getWaitDurationInMinutes(arrivalDate, arrivalTime, line.departureDate, line.departureTime); } return waitDuration; }