@qite/tide-booking-component
Version:
React Booking wizard & Booking product component for Tide
401 lines (333 loc) • 16 kB
text/typescript
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;
}