@duffel/components 3.0.7-canary → 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +8 -0
- package/.github/CODEOWNERS +4 -0
- package/.github/renovate.json +1 -5
- package/.github/workflows/release.yml +3 -0
- package/.storybook/__snapshots__/Storyshots.test.js.snap +20384 -533
- package/README.md +16 -2
- package/config/esbuild.base.config.js +6 -2
- package/config/esbuild.cdn.config.js +2 -1
- package/config/esbuild.dev.config.js +2 -1
- package/config/esbuild.react.config.js +1 -1
- package/data/airports.csv +9084 -0
- package/data/cities.csv +256 -0
- package/package.json +11 -1
- package/react-dist/components/{Card.d.ts → DuffelAncillaries/Card.d.ts} +1 -1
- package/react-dist/components/{DuffelAncillaries.d.ts → DuffelAncillaries/DuffelAncillaries.d.ts} +1 -1
- package/react-dist/components/{DuffelAncillariesCustomElement.d.ts → DuffelAncillaries/DuffelAncillariesCustomElement.d.ts} +1 -1
- package/react-dist/components/{bags → DuffelAncillaries/bags}/BaggageSelectionCard.d.ts +2 -2
- package/react-dist/components/{bags → DuffelAncillaries/bags}/BaggageSelectionController.d.ts +2 -2
- package/react-dist/components/{bags → DuffelAncillaries/bags}/BaggageSelectionModal.d.ts +2 -2
- package/react-dist/components/{bags → DuffelAncillaries/bags}/BaggageSelectionModalBody.d.ts +2 -2
- package/react-dist/components/{bags → DuffelAncillaries/bags}/BaggageSelectionModalBodyPassenger.d.ts +2 -2
- package/react-dist/components/{bags → DuffelAncillaries/bags}/BaggageSelectionModalFooter.d.ts +1 -1
- package/react-dist/components/{bags → DuffelAncillaries/bags}/BaggageSelectionModalHeader.d.ts +1 -1
- package/react-dist/components/{bags → DuffelAncillaries/bags}/IncludedBaggageBanner.d.ts +1 -1
- package/react-dist/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionCard.d.ts +2 -2
- package/react-dist/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionModal.d.ts +2 -2
- package/react-dist/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionModalBody.d.ts +1 -1
- package/react-dist/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionModalFooter.d.ts +2 -2
- package/react-dist/components/{seats → DuffelAncillaries/seats}/Amenity.d.ts +1 -1
- package/react-dist/components/{seats → DuffelAncillaries/seats}/Element.d.ts +2 -2
- package/react-dist/components/{seats → DuffelAncillaries/seats}/Legend.d.ts +1 -1
- package/react-dist/components/{seats → DuffelAncillaries/seats}/Row.d.ts +2 -2
- package/react-dist/components/{seats → DuffelAncillaries/seats}/RowSection.d.ts +2 -2
- package/react-dist/components/{seats → DuffelAncillaries/seats}/SeatElement.d.ts +2 -2
- package/react-dist/components/{seats → DuffelAncillaries/seats}/SeatInfo.d.ts +1 -1
- package/react-dist/components/{seats → DuffelAncillaries/seats}/SeatMap.d.ts +2 -2
- package/react-dist/components/{seats → DuffelAncillaries/seats}/SeatSelectionCard.d.ts +3 -3
- package/react-dist/components/{seats → DuffelAncillaries/seats}/SeatSelectionModal.d.ts +3 -3
- package/react-dist/components/{seats → DuffelAncillaries/seats}/SeatSelectionModalFooter.d.ts +2 -2
- package/react-dist/components/{seats → DuffelAncillaries/seats}/SeatSelectionModalHeader.d.ts +1 -1
- package/react-dist/components/{seats → DuffelAncillaries/seats}/SeatUnavailable.d.ts +1 -1
- package/react-dist/components/DuffelPayments/DuffelPayments.d.ts +11 -0
- package/react-dist/components/DuffelPayments/DuffelPaymentsCustomElement.d.ts +14 -0
- package/react-dist/components/PlacesLookup/PlacesLookup.d.ts +20 -0
- package/react-dist/components/{Button.d.ts → shared/Button.d.ts} +2 -2
- package/react-dist/components/{ErrorBoundary.d.ts → shared/ErrorBoundary.d.ts} +1 -1
- package/react-dist/components/{Icon.d.ts → shared/Icon.d.ts} +2 -0
- package/react-dist/components/{IconButton.d.ts → shared/IconButton.d.ts} +1 -1
- package/react-dist/components/{NonIdealState.d.ts → shared/NonIdealState.d.ts} +1 -1
- package/react-dist/custom-elements.d.ts +2 -1
- package/react-dist/custom-elements.js +21 -20
- package/react-dist/custom-elements.js.map +4 -4
- package/react-dist/index.d.ts +3 -1
- package/react-dist/index.js +51 -21
- package/react-dist/index.js.map +4 -4
- package/react-dist/lib/captureErrorInSentry.d.ts +1 -1
- package/react-dist/lib/fetchFromDuffelAPI.d.ts +7 -0
- package/react-dist/lib/hasHighLuminance.d.ts +1 -0
- package/react-dist/lib/logging.d.ts +7 -14
- package/react-dist/lib/retrieveSeatMaps.d.ts +1 -1
- package/react-dist/types/DuffelAncillariesProps.d.ts +1 -1
- package/scripts/generate-fixture.ts +13 -8
- package/scripts/setup-suggestion-data.ts +100 -0
- package/scripts/upload-to-cdn.sh +1 -1
- package/src/components/{Card.tsx → DuffelAncillaries/Card.tsx} +1 -1
- package/src/components/{Counter.tsx → DuffelAncillaries/Counter.tsx} +1 -1
- package/src/components/{DuffelAncillaries.tsx → DuffelAncillaries/DuffelAncillaries.tsx} +68 -64
- package/src/components/{DuffelAncillariesCustomElement.tsx → DuffelAncillaries/DuffelAncillariesCustomElement.tsx} +2 -2
- package/src/components/{bags → DuffelAncillaries/bags}/BaggageSelectionCard.tsx +10 -5
- package/src/components/{bags → DuffelAncillaries/bags}/BaggageSelectionController.tsx +2 -2
- package/src/components/{bags → DuffelAncillaries/bags}/BaggageSelectionModal.tsx +4 -4
- package/src/components/{bags → DuffelAncillaries/bags}/BaggageSelectionModalBody.tsx +3 -3
- package/src/components/{bags → DuffelAncillaries/bags}/BaggageSelectionModalBodyPassenger.tsx +4 -4
- package/src/components/{bags → DuffelAncillaries/bags}/BaggageSelectionModalFooter.tsx +23 -16
- package/src/components/{bags → DuffelAncillaries/bags}/BaggageSelectionModalHeader.tsx +24 -18
- package/src/components/{bags → DuffelAncillaries/bags}/IncludedBaggageBanner.tsx +1 -1
- package/src/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionCard.tsx +4 -4
- package/src/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionModal.tsx +3 -3
- package/src/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionModalBody.tsx +3 -3
- package/src/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionModalBodyListItem.tsx +1 -1
- package/src/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionModalFooter.tsx +5 -5
- package/src/components/{seats → DuffelAncillaries/seats}/Amenity.tsx +2 -2
- package/src/components/{seats → DuffelAncillaries/seats}/DeckSelect.tsx +1 -1
- package/src/components/{seats → DuffelAncillaries/seats}/Element.tsx +2 -2
- package/src/components/{seats → DuffelAncillaries/seats}/ExitElement.tsx +1 -1
- package/src/components/{seats → DuffelAncillaries/seats}/Legend.tsx +2 -2
- package/src/components/{seats → DuffelAncillaries/seats}/Row.tsx +2 -2
- package/src/components/{seats → DuffelAncillaries/seats}/RowSection.tsx +5 -2
- package/src/components/{seats → DuffelAncillaries/seats}/SeatElement.tsx +3 -3
- package/src/components/{seats → DuffelAncillaries/seats}/SeatInfo.tsx +1 -1
- package/src/components/{seats → DuffelAncillaries/seats}/SeatMap.tsx +6 -2
- package/src/components/{seats → DuffelAncillaries/seats}/SeatMapUnavailable.tsx +1 -1
- package/src/components/{seats → DuffelAncillaries/seats}/SeatSelectionCard.tsx +5 -5
- package/src/components/{seats → DuffelAncillaries/seats}/SeatSelectionModal.tsx +5 -5
- package/src/components/{seats → DuffelAncillaries/seats}/SeatSelectionModalBody.tsx +1 -1
- package/src/components/{seats → DuffelAncillaries/seats}/SeatSelectionModalFooter.tsx +24 -17
- package/src/components/{seats → DuffelAncillaries/seats}/SeatSelectionModalHeader.tsx +30 -20
- package/src/components/{seats → DuffelAncillaries/seats}/SeatUnavailable.tsx +2 -2
- package/src/components/DuffelPayments/DuffelPayments.tsx +224 -0
- package/src/components/DuffelPayments/DuffelPaymentsCustomElement.tsx +130 -0
- package/src/components/PlacesLookup/PlacesLookup.tsx +123 -0
- package/src/components/{Button.tsx → shared/Button.tsx} +4 -3
- package/src/components/{ErrorBoundary.tsx → shared/ErrorBoundary.tsx} +2 -2
- package/src/components/{Icon.tsx → shared/Icon.tsx} +11 -11
- package/src/components/{IconButton.tsx → shared/IconButton.tsx} +1 -1
- package/src/components/{Modal.tsx → shared/Modal.tsx} +5 -1
- package/src/components/{NonIdealState.tsx → shared/NonIdealState.tsx} +1 -1
- package/src/custom-elements.ts +6 -1
- package/src/examples/client-side/index.html +1 -1
- package/src/examples/full-stack/index.html +1 -1
- package/src/examples/full-stack/server.mjs +1 -0
- package/src/examples/just-typescript/src/index.html +2 -2
- package/src/examples/just-typescript/src/index.ts +2 -1
- package/src/examples/payments-custom-element/README.md +17 -0
- package/src/examples/payments-custom-element/index.html +43 -0
- package/src/examples/payments-just-typescript/README.md +37 -0
- package/src/examples/payments-just-typescript/package.json +16 -0
- package/src/examples/payments-just-typescript/src/index.html +23 -0
- package/src/examples/payments-just-typescript/src/index.ts +18 -0
- package/src/examples/payments-just-typescript/yarn.lock +154 -0
- package/src/examples/react-app/src/index.tsx +11 -6
- package/src/fixtures/offers/off_1.json +1 -10
- package/src/index.ts +3 -1
- package/src/lib/captureErrorInSentry.ts +2 -20
- package/src/lib/fetchFromDuffelAPI.ts +36 -6
- package/src/lib/formatDate.ts +3 -4
- package/src/lib/getBaggageServiceDescription.ts +1 -6
- package/src/lib/getPassengerName.ts +4 -0
- package/src/lib/getTotalAmountForServices.ts +1 -1
- package/src/lib/hasHighLuminance.ts +9 -0
- package/src/lib/logging.ts +52 -32
- package/src/lib/retrieveOffer.ts +13 -6
- package/src/lib/retrieveSeatMaps.ts +13 -8
- package/src/stories/BaggageSelectionModalHeader.stories.tsx +1 -1
- package/src/stories/Button.stories.tsx +33 -2
- package/src/stories/DuffelAncillaries.stories.tsx +42 -2
- package/src/stories/DuffelPayments.stories.tsx +34 -0
- package/src/stories/Icon.stories.tsx +3 -2
- package/src/stories/IconButton.stories.tsx +1 -1
- package/src/stories/PlacesLookup.stories.tsx +22 -0
- package/src/styles/components/Button.css +11 -3
- package/src/styles/components/Card.css +3 -3
- package/src/styles/components/CfarSelectionModal.css +1 -1
- package/src/styles/components/DuffelPayments.css +42 -0
- package/src/styles/components/Legend.css +10 -6
- package/src/styles/components/LoadingState.css +8 -2
- package/src/styles/components/Modal.css +2 -1
- package/src/styles/components/PassengerSelect.css +8 -2
- package/src/styles/components/PlacesLookup.css +36 -0
- package/src/styles/components/Seat.css +9 -7
- package/src/styles/components/SeatInfo.css +1 -1
- package/src/styles/components/Tabs.css +5 -2
- package/src/styles/global.css +2 -0
- package/src/tests/components/DuffelAncillaries.test.tsx +1 -1
- package/src/tests/lib/createPriceFormatters.test.tsx +1 -1
- package/src/tests/lib/formatAvailableServices.test.tsx +1 -1
- package/src/tests/lib/formatSeatMaps.test.tsx +2 -2
- package/src/tests/lib/getCurrencyForServices.test.tsx +1 -1
- package/src/tests/lib/hasServiceOfSameMetadataTypeAlreadyBeenSelected.test.ts +1 -1
- package/src/tests/lib/logging.test.tsx +14 -14
- package/src/tests/lib/moneyStringFormatter.test.tsx +1 -1
- package/src/tests/lib/validateProps.test.tsx +1 -1
- package/src/types/DuffelAncillariesProps.ts +1 -1
- /package/react-dist/components/{Counter.d.ts → DuffelAncillaries/Counter.d.ts} +0 -0
- /package/react-dist/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionModalBodyListItem.d.ts +0 -0
- /package/react-dist/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionModalHeader.d.ts +0 -0
- /package/react-dist/components/{seats → DuffelAncillaries/seats}/DeckSelect.d.ts +0 -0
- /package/react-dist/components/{seats → DuffelAncillaries/seats}/EmptyElement.d.ts +0 -0
- /package/react-dist/components/{seats → DuffelAncillaries/seats}/ExitElement.d.ts +0 -0
- /package/react-dist/components/{seats → DuffelAncillaries/seats}/SeatMapUnavailable.d.ts +0 -0
- /package/react-dist/components/{seats → DuffelAncillaries/seats}/SeatSelectionModalBody.d.ts +0 -0
- /package/react-dist/components/{AnimatedLoaderEllipsis.d.ts → shared/AnimatedLoaderEllipsis.d.ts} +0 -0
- /package/react-dist/components/{FetchOfferErrorState.d.ts → shared/FetchOfferErrorState.d.ts} +0 -0
- /package/react-dist/components/{Modal.d.ts → shared/Modal.d.ts} +0 -0
- /package/react-dist/components/{Stamp.d.ts → shared/Stamp.d.ts} +0 -0
- /package/react-dist/components/{Tabs.d.ts → shared/Tabs.d.ts} +0 -0
- /package/src/components/{cancel_for_any_reason → DuffelAncillaries/cancel_for_any_reason}/CfarSelectionModalHeader.tsx +0 -0
- /package/src/components/{seats → DuffelAncillaries/seats}/EmptyElement.tsx +0 -0
- /package/src/components/{AnimatedLoaderEllipsis.tsx → shared/AnimatedLoaderEllipsis.tsx} +0 -0
- /package/src/components/{FetchOfferErrorState.tsx → shared/FetchOfferErrorState.tsx} +0 -0
- /package/src/components/{Stamp.tsx → shared/Stamp.tsx} +0 -0
- /package/src/components/{Tabs.tsx → shared/Tabs.tsx} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const captureErrorInSentry: (error: Error
|
|
1
|
+
export declare const captureErrorInSentry: (error: Error) => string;
|
|
@@ -1 +1,8 @@
|
|
|
1
|
+
export interface ErrorResponse extends Response {
|
|
2
|
+
data: {
|
|
3
|
+
meta: any;
|
|
4
|
+
errors: any[];
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
export declare const isErrorResponse: (response: any) => response is ErrorResponse;
|
|
1
8
|
export declare function fetchFromDuffelAPI(withClientKey: string, path: string, method?: string, body?: string): Promise<any>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const hasHighLuminance: (accentColor: string) => boolean;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
1
|
/**
|
|
3
2
|
* The functions in this file are used to enable logging.
|
|
4
3
|
*
|
|
@@ -24,10 +23,12 @@
|
|
|
24
23
|
* log('This is a log message')
|
|
25
24
|
* logGroup('These messages will be grouped together', ['This is a log message', 'This is another log message'])
|
|
26
25
|
*/
|
|
27
|
-
declare const initializeLogger: (debugMode: boolean) =>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
declare const initializeLogger: (debugMode: boolean) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Log a message to the console. Messages will be prefixed with "[Duffel Ancillaries]".
|
|
29
|
+
* @param message The message to print to the console.
|
|
30
|
+
*/
|
|
31
|
+
declare const log: (message: any) => void;
|
|
31
32
|
/**
|
|
32
33
|
* Log a series of messages to the console inside a collapsible group.
|
|
33
34
|
* @param groupName The name of the group of messages. This will be prefixed with "[Duffel Ancillaries]".
|
|
@@ -42,12 +43,4 @@ declare function logGroup(groupName: string, messages: any[]): void;
|
|
|
42
43
|
declare function logGroup(groupName: string, object: {
|
|
43
44
|
[key: string]: any;
|
|
44
45
|
}): void;
|
|
45
|
-
|
|
46
|
-
log: (message: any) => void;
|
|
47
|
-
logGroup: typeof logGroup;
|
|
48
|
-
}>;
|
|
49
|
-
declare const useLog: () => {
|
|
50
|
-
log: (message: any) => void;
|
|
51
|
-
logGroup: typeof logGroup;
|
|
52
|
-
};
|
|
53
|
-
export { LogContext, initializeLogger, useLog };
|
|
46
|
+
export { initializeLogger, logGroup, log };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { SeatMap } from "../types/SeatMap";
|
|
2
|
-
export declare function retrieveSeatMaps(offer_id: string, client_key: string | null, onError: (
|
|
2
|
+
export declare function retrieveSeatMaps(offer_id: string, client_key: string | null, onError: () => void, setIsLoading: (isLoading: boolean) => void, onSeatMapReady: (seatMaps: SeatMap[]) => void): Promise<void>;
|
|
@@ -45,7 +45,7 @@ export type DuffelAncillariesPriceFormatterForSeats = (amount: number, currency:
|
|
|
45
45
|
};
|
|
46
46
|
export type DuffelAncillariesPriceFormatterForCancelForAnyReason = (amount: number, currency: string, service: OfferAvailableServiceCancelForAnyReason) => {
|
|
47
47
|
amount: number;
|
|
48
|
-
currency
|
|
48
|
+
currency?: string;
|
|
49
49
|
};
|
|
50
50
|
export interface DuffelAncillariesPriceFormatters {
|
|
51
51
|
bags?: DuffelAncillariesPriceFormatterForBags;
|
|
@@ -10,6 +10,9 @@ const DUFFEL_API_TOKEN = process.env.DUFFEL_API_TOKEN || "";
|
|
|
10
10
|
const DUFFEL_API_URL = process.env.DUFFEL_API_URL || "";
|
|
11
11
|
const VERBOSE = process.env.VERBOSE === "true";
|
|
12
12
|
|
|
13
|
+
// eslint-disable-next-line
|
|
14
|
+
const log = console.log;
|
|
15
|
+
|
|
13
16
|
if (DUFFEL_API_URL.includes("localhost"))
|
|
14
17
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
15
18
|
|
|
@@ -89,7 +92,8 @@ const main = async () => {
|
|
|
89
92
|
const sliceInput = new Array<[string, string]>(sliceCount);
|
|
90
93
|
for (let i = 0; i < sliceCount; i++) {
|
|
91
94
|
let origin = sliceInput[i - 1]?.[0];
|
|
92
|
-
|
|
95
|
+
|
|
96
|
+
log(`\nSlice #${i + 1}`);
|
|
93
97
|
const { value } = await prompts({
|
|
94
98
|
type: "text",
|
|
95
99
|
name: "value",
|
|
@@ -108,7 +112,7 @@ const main = async () => {
|
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
// ask how many adults
|
|
111
|
-
|
|
115
|
+
log(`\n`);
|
|
112
116
|
const { adultCount } = await prompts({
|
|
113
117
|
type: "number",
|
|
114
118
|
name: "adultCount",
|
|
@@ -117,7 +121,7 @@ const main = async () => {
|
|
|
117
121
|
});
|
|
118
122
|
|
|
119
123
|
// ask for requested sources
|
|
120
|
-
|
|
124
|
+
log(`\n`);
|
|
121
125
|
const { requestedSources } = await prompts({
|
|
122
126
|
type: "text",
|
|
123
127
|
name: "requestedSources",
|
|
@@ -135,7 +139,7 @@ const main = async () => {
|
|
|
135
139
|
const airlines = new Set(
|
|
136
140
|
offerRequest.offers.map((offer) => offer.owner.iata_code)
|
|
137
141
|
);
|
|
138
|
-
|
|
142
|
+
log(
|
|
139
143
|
`Received ${withPlural(
|
|
140
144
|
offerRequest.offers.length,
|
|
141
145
|
"offer",
|
|
@@ -147,7 +151,7 @@ const main = async () => {
|
|
|
147
151
|
"airlines"
|
|
148
152
|
)}(${Array.from(airlines.values()).join(",")})`
|
|
149
153
|
);
|
|
150
|
-
|
|
154
|
+
log(
|
|
151
155
|
`Search completed, offer request ID: ${offerRequest.id}.\nUsing first offer to get services: ${offerRequest.offers[0].id}\n`
|
|
152
156
|
);
|
|
153
157
|
}
|
|
@@ -183,10 +187,11 @@ const main = async () => {
|
|
|
183
187
|
JSON.stringify(seatMaps, null, 2)
|
|
184
188
|
);
|
|
185
189
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
log(`\n🐄 Fixtures saved for ${firstOffer.id}`);
|
|
191
|
+
log(` ↳ /src/fixtures/offer/${firstOffer.id}.json`);
|
|
192
|
+
log(` ↳ /src/fixtures/seat-maps/${firstOffer.id}.json\n`);
|
|
189
193
|
} catch (err) {
|
|
194
|
+
// eslint-disable-next-line
|
|
190
195
|
console.error(err);
|
|
191
196
|
process.exit(1);
|
|
192
197
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import readline from "readline";
|
|
3
|
+
|
|
4
|
+
async function readCSVIntoMatrix(
|
|
5
|
+
filePath: string,
|
|
6
|
+
linePrefix: string,
|
|
7
|
+
keys: string[]
|
|
8
|
+
): Promise<string[]> {
|
|
9
|
+
const rl = readline.createInterface({
|
|
10
|
+
input: fs.createReadStream(filePath),
|
|
11
|
+
crlfDelay: Infinity,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// this will map a key into the index
|
|
15
|
+
let keyNameToIndexMap: Record<string, number> = {};
|
|
16
|
+
const matrix = new Array<string>();
|
|
17
|
+
|
|
18
|
+
rl.on("line", (line) => {
|
|
19
|
+
if (Object.keys(keyNameToIndexMap).length === 0) {
|
|
20
|
+
// it's the header line
|
|
21
|
+
keyNameToIndexMap = line
|
|
22
|
+
.split(",")
|
|
23
|
+
.reduce((acc, key, index) => ({ ...acc, [key]: index }), {});
|
|
24
|
+
} else {
|
|
25
|
+
// it's a data line
|
|
26
|
+
const row = line.split(",");
|
|
27
|
+
const rowObject =
|
|
28
|
+
linePrefix +
|
|
29
|
+
keys
|
|
30
|
+
.map((key) => {
|
|
31
|
+
const index = keyNameToIndexMap[key];
|
|
32
|
+
return row[index];
|
|
33
|
+
})
|
|
34
|
+
.join(`,`);
|
|
35
|
+
matrix.push(rowObject);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
await new Promise((res) => rl.once("close", res));
|
|
40
|
+
return matrix;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface CityCsvRow {
|
|
44
|
+
id: string;
|
|
45
|
+
iata_code: string;
|
|
46
|
+
iata_country_code: string;
|
|
47
|
+
name: string;
|
|
48
|
+
inserted_at: string;
|
|
49
|
+
updated_at: string;
|
|
50
|
+
metropolitan_area: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function loadCities() {
|
|
54
|
+
return await readCSVIntoMatrix("./data/cities.csv", "C,", [
|
|
55
|
+
"name",
|
|
56
|
+
"iata_code",
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface AirportCsvRow {
|
|
61
|
+
id: string;
|
|
62
|
+
iata_code: string;
|
|
63
|
+
iata_city_code: string;
|
|
64
|
+
iata_country_code: string;
|
|
65
|
+
name: string;
|
|
66
|
+
inserted_at: string;
|
|
67
|
+
updated_at: string;
|
|
68
|
+
source_type: string;
|
|
69
|
+
alternative_names: string;
|
|
70
|
+
icao_code: string;
|
|
71
|
+
disabled_at: string;
|
|
72
|
+
city_name: string;
|
|
73
|
+
latitude: string;
|
|
74
|
+
longitude: string;
|
|
75
|
+
time_zone: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function loadAirports() {
|
|
79
|
+
return await readCSVIntoMatrix("./data/airports.csv", "A,", [
|
|
80
|
+
"name",
|
|
81
|
+
"iata_code",
|
|
82
|
+
"latitude",
|
|
83
|
+
"longitude",
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function main() {
|
|
88
|
+
// load airports csv
|
|
89
|
+
const airports = await loadAirports();
|
|
90
|
+
|
|
91
|
+
// load cities csv
|
|
92
|
+
const cities = await loadCities();
|
|
93
|
+
|
|
94
|
+
fs.writeFileSync(
|
|
95
|
+
"./data/__generated__iata-lookup.json",
|
|
96
|
+
JSON.stringify([...cities, ...airports])
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export default main();
|
package/scripts/upload-to-cdn.sh
CHANGED
|
@@ -16,7 +16,7 @@ if [ -z "$VERSION" ]; then
|
|
|
16
16
|
fi
|
|
17
17
|
|
|
18
18
|
# Check if folder exists
|
|
19
|
-
if gsutil -q stat "$GCP_PREFIX/$VERSION/
|
|
19
|
+
if gsutil -q stat "$GCP_PREFIX/$VERSION/duffel-ancillaries.js"; then
|
|
20
20
|
# Confirm with user before overriding
|
|
21
21
|
read -p "Version \`$VERSION\` already exists. Do you want to override it? (\`Y\` to continue) " -n 1 -r
|
|
22
22
|
echo
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { ErrorBoundary } from "@components/shared/ErrorBoundary";
|
|
2
|
+
import { FetchOfferErrorState } from "@components/shared/FetchOfferErrorState";
|
|
1
3
|
import { compileCreateOrderPayload } from "@lib/compileCreateOrderPayload";
|
|
2
4
|
import { createPriceFormatters } from "@lib/createPriceFormatters";
|
|
3
5
|
import { formatAvailableServices } from "@lib/formatAvailableServices";
|
|
4
6
|
import { formatSeatMaps } from "@lib/formatSeatMaps";
|
|
7
|
+
import { hasHighLuminance } from "@lib/hasHighLuminance";
|
|
5
8
|
import { isPayloadComplete } from "@lib/isPayloadComplete";
|
|
6
|
-
import {
|
|
9
|
+
import { initializeLogger, logGroup } from "@lib/logging";
|
|
7
10
|
import { offerIsExpired } from "@lib/offerIsExpired";
|
|
8
11
|
import { retrieveOffer } from "@lib/retrieveOffer";
|
|
9
12
|
import { retrieveSeatMaps } from "@lib/retrieveSeatMaps";
|
|
@@ -19,12 +22,10 @@ import * as React from "react";
|
|
|
19
22
|
import {
|
|
20
23
|
CreateOrderPayloadPassengers,
|
|
21
24
|
CreateOrderPayloadService,
|
|
22
|
-
} from "
|
|
23
|
-
import { DuffelAncillariesProps } from "
|
|
24
|
-
import { Offer } from "
|
|
25
|
-
import { SeatMap } from "
|
|
26
|
-
import { ErrorBoundary } from "./ErrorBoundary";
|
|
27
|
-
import { FetchOfferErrorState } from "./FetchOfferErrorState";
|
|
25
|
+
} from "../../types/CreateOrderPayload";
|
|
26
|
+
import { DuffelAncillariesProps } from "../../types/DuffelAncillariesProps";
|
|
27
|
+
import { Offer } from "../../types/Offer";
|
|
28
|
+
import { SeatMap } from "../../types/SeatMap";
|
|
28
29
|
import { BaggageSelectionCard } from "./bags/BaggageSelectionCard";
|
|
29
30
|
import { CfarSelectionCard } from "./cancel_for_any_reason/CfarSelectionCard";
|
|
30
31
|
import { SeatSelectionCard } from "./seats/SeatSelectionCard";
|
|
@@ -33,9 +34,9 @@ const COMPONENT_CDN = process.env.COMPONENT_CDN || "";
|
|
|
33
34
|
const hrefToComponentStyles = `${COMPONENT_CDN}/global.css`;
|
|
34
35
|
|
|
35
36
|
export const DuffelAncillaries: React.FC<DuffelAncillariesProps> = (props) => {
|
|
36
|
-
|
|
37
|
+
initializeLogger(props.debug || false);
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
logGroup("Properties passed into the component:", props);
|
|
39
40
|
|
|
40
41
|
if (!areDuffelAncillariesPropsValid(props)) {
|
|
41
42
|
throw new Error(
|
|
@@ -115,7 +116,7 @@ export const DuffelAncillaries: React.FC<DuffelAncillariesProps> = (props) => {
|
|
|
115
116
|
setError(expiryErrorMessage);
|
|
116
117
|
return;
|
|
117
118
|
} else {
|
|
118
|
-
const msUntilExpiry = new Date(offer
|
|
119
|
+
const msUntilExpiry = new Date(offer?.expires_at)?.getTime() - Date.now();
|
|
119
120
|
|
|
120
121
|
// Only show the expiry error message if the offer expires in less than a day,
|
|
121
122
|
// to prevent buffer overflows when showing offers for fixtures, which expire in
|
|
@@ -186,7 +187,7 @@ export const DuffelAncillaries: React.FC<DuffelAncillariesProps> = (props) => {
|
|
|
186
187
|
? props.offer_id
|
|
187
188
|
: props.offer.id,
|
|
188
189
|
!isPropsWithOfferIdForFixture ? props.client_key : null,
|
|
189
|
-
|
|
190
|
+
() => updateSeatMaps([]),
|
|
190
191
|
setIsSeatMapLoading,
|
|
191
192
|
updateSeatMaps
|
|
192
193
|
);
|
|
@@ -235,7 +236,7 @@ export const DuffelAncillaries: React.FC<DuffelAncillariesProps> = (props) => {
|
|
|
235
236
|
cancel_for_any_reason_services: cfarSelectedServices,
|
|
236
237
|
};
|
|
237
238
|
|
|
238
|
-
|
|
239
|
+
logGroup("Payload ready", {
|
|
239
240
|
"Order creation payload": createOrderPayload,
|
|
240
241
|
"Services metadata": metadata,
|
|
241
242
|
});
|
|
@@ -263,6 +264,11 @@ export const DuffelAncillaries: React.FC<DuffelAncillariesProps> = (props) => {
|
|
|
263
264
|
...(props.styles?.accentColor && {
|
|
264
265
|
"--ACCENT": props.styles.accentColor,
|
|
265
266
|
}),
|
|
267
|
+
...(props.styles?.accentColor &&
|
|
268
|
+
hasHighLuminance(props.styles.accentColor) && {
|
|
269
|
+
"--SECONDARY": "var(--GREY-900)",
|
|
270
|
+
"--TERTIARY": "var(--GREY-400)",
|
|
271
|
+
}),
|
|
266
272
|
...(props.styles?.fontFamily && {
|
|
267
273
|
"--FONT-FAMILY": props.styles.fontFamily,
|
|
268
274
|
}),
|
|
@@ -284,63 +290,61 @@ export const DuffelAncillaries: React.FC<DuffelAncillariesProps> = (props) => {
|
|
|
284
290
|
error,
|
|
285
291
|
};
|
|
286
292
|
|
|
287
|
-
|
|
293
|
+
logGroup("Component's internal state:", state);
|
|
288
294
|
|
|
289
295
|
return (
|
|
290
296
|
<>
|
|
291
297
|
<link rel="stylesheet" href={hrefToComponentStyles}></link>
|
|
292
298
|
|
|
293
|
-
<
|
|
294
|
-
<
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
{
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
</div>
|
|
343
|
-
</LogContext.Provider>
|
|
299
|
+
<div className="duffel-components" style={duffelComponentsStyle}>
|
|
300
|
+
<ErrorBoundary>
|
|
301
|
+
{error && (
|
|
302
|
+
<FetchOfferErrorState
|
|
303
|
+
height={nonIdealStateHeight}
|
|
304
|
+
message={error}
|
|
305
|
+
/>
|
|
306
|
+
)}
|
|
307
|
+
|
|
308
|
+
{!error &&
|
|
309
|
+
props.services.map((ancillaryName) => {
|
|
310
|
+
if (ancillaryName === "bags")
|
|
311
|
+
return (
|
|
312
|
+
<BaggageSelectionCard
|
|
313
|
+
key="bags"
|
|
314
|
+
isLoading={isOfferLoading}
|
|
315
|
+
offer={offer}
|
|
316
|
+
passengers={passengers}
|
|
317
|
+
selectedServices={baggageSelectedServices}
|
|
318
|
+
setSelectedServices={setBaggageSelectedServices}
|
|
319
|
+
/>
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
if (ancillaryName === "seats")
|
|
323
|
+
return (
|
|
324
|
+
<SeatSelectionCard
|
|
325
|
+
key="seats"
|
|
326
|
+
isLoading={isOfferLoading || isSeatMapLoading}
|
|
327
|
+
seatMaps={seatMaps}
|
|
328
|
+
offer={offer}
|
|
329
|
+
passengers={passengers}
|
|
330
|
+
selectedServices={seatSelectedServices}
|
|
331
|
+
setSelectedServices={setSeatSelectedServices}
|
|
332
|
+
/>
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
if (ancillaryName === "cancel_for_any_reason")
|
|
336
|
+
return (
|
|
337
|
+
<CfarSelectionCard
|
|
338
|
+
key="cancel_for_any_reason"
|
|
339
|
+
isLoading={isOfferLoading}
|
|
340
|
+
offer={offer}
|
|
341
|
+
selectedServices={cfarSelectedServices}
|
|
342
|
+
setSelectedServices={setCfarSelectedServices}
|
|
343
|
+
/>
|
|
344
|
+
);
|
|
345
|
+
})}
|
|
346
|
+
</ErrorBoundary>
|
|
347
|
+
</div>
|
|
344
348
|
</>
|
|
345
349
|
);
|
|
346
350
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRoot, Root } from "react-dom/client";
|
|
2
|
-
import { CreateOrderPayload } from "
|
|
2
|
+
import { CreateOrderPayload } from "../../types/CreateOrderPayload";
|
|
3
3
|
import {
|
|
4
4
|
DuffelAncillariesPropsWithClientKeyAndOfferId,
|
|
5
5
|
DuffelAncillariesPropsWithOfferIdForFixture,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
DuffelAncillariesPropWithOfferAndClientKey,
|
|
8
8
|
OnPayloadReady,
|
|
9
9
|
OnPayloadReadyMetadata,
|
|
10
|
-
} from "
|
|
10
|
+
} from "../../types/DuffelAncillariesProps";
|
|
11
11
|
import { DuffelAncillaries } from "./DuffelAncillaries";
|
|
12
12
|
|
|
13
13
|
declare global {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { AnimatedLoaderEllipsis } from "@components/shared/AnimatedLoaderEllipsis";
|
|
2
|
+
import { Stamp } from "@components/shared/Stamp";
|
|
1
3
|
import { getCurrencyForServices } from "@lib/getCurrencyForServices";
|
|
2
4
|
import { getTotalAmountForServices } from "@lib/getTotalAmountForServices";
|
|
3
5
|
import { getTotalQuantity } from "@lib/getTotalQuantity";
|
|
@@ -8,11 +10,9 @@ import React from "react";
|
|
|
8
10
|
import {
|
|
9
11
|
CreateOrderPayload,
|
|
10
12
|
CreateOrderPayloadServices,
|
|
11
|
-
} from "
|
|
12
|
-
import { Offer } from "
|
|
13
|
-
import { AnimatedLoaderEllipsis } from "../AnimatedLoaderEllipsis";
|
|
13
|
+
} from "../../../types/CreateOrderPayload";
|
|
14
|
+
import { Offer } from "../../../types/Offer";
|
|
14
15
|
import { Card } from "../Card";
|
|
15
|
-
import { Stamp } from "../Stamp";
|
|
16
16
|
import { BaggageSelectionModal } from "./BaggageSelectionModal";
|
|
17
17
|
|
|
18
18
|
export interface BaggageSelectionCardProps {
|
|
@@ -86,7 +86,12 @@ export const BaggageSelectionCard: React.FC<BaggageSelectionCardProps> = ({
|
|
|
86
86
|
offer={offer}
|
|
87
87
|
passengers={passengers}
|
|
88
88
|
onClose={(newSelectedServices) => {
|
|
89
|
-
|
|
89
|
+
// We need to do a deep copy here because otherwise the modal changing the quantity
|
|
90
|
+
// will affect the selected services regardless of whether it's saved or not
|
|
91
|
+
const newSelectedServicesDeepCopy = JSON.parse(
|
|
92
|
+
JSON.stringify(newSelectedServices)
|
|
93
|
+
);
|
|
94
|
+
setSelectedServices(newSelectedServicesDeepCopy);
|
|
90
95
|
setIsOpen(false);
|
|
91
96
|
}}
|
|
92
97
|
selectedServices={selectedServices}
|
|
@@ -2,8 +2,8 @@ import { getBaggageServiceDescription } from "@lib/getBaggageServiceDescription"
|
|
|
2
2
|
import { hasServiceOfSameMetadataTypeAlreadyBeenSelected } from "@lib/hasServiceOfSameMetadataTypeAlreadyBeenSelected";
|
|
3
3
|
import { moneyStringFormatter } from "@lib/moneyStringFormatter";
|
|
4
4
|
import React from "react";
|
|
5
|
-
import { CreateOrderPayloadServices } from "
|
|
6
|
-
import { OfferAvailableServiceBaggage } from "
|
|
5
|
+
import { CreateOrderPayloadServices } from "../../../types/CreateOrderPayload";
|
|
6
|
+
import { OfferAvailableServiceBaggage } from "../../../types/Offer";
|
|
7
7
|
import { Counter } from "../Counter";
|
|
8
8
|
|
|
9
9
|
interface BaggageSelectionControllerProps {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Modal } from "@components/shared/Modal";
|
|
1
2
|
import { getCurrencyForServices } from "@lib/getCurrencyForServices";
|
|
2
3
|
import { getPassengerMapById } from "@lib/getPassengerMapById";
|
|
3
4
|
import { getSegmentList } from "@lib/getSegmentList";
|
|
@@ -7,9 +8,8 @@ import React, { useState } from "react";
|
|
|
7
8
|
import {
|
|
8
9
|
CreateOrderPayload,
|
|
9
10
|
CreateOrderPayloadServices,
|
|
10
|
-
} from "
|
|
11
|
-
import { Offer } from "
|
|
12
|
-
import { Modal } from "../Modal";
|
|
11
|
+
} from "../../../types/CreateOrderPayload";
|
|
12
|
+
import { Offer } from "../../../types/Offer";
|
|
13
13
|
import { BaggageSelectionModalBody } from "./BaggageSelectionModalBody";
|
|
14
14
|
import { BaggageSelectionModalFooter } from "./BaggageSelectionModalFooter";
|
|
15
15
|
import { BaggageSelectionModalHeader } from "./BaggageSelectionModalHeader";
|
|
@@ -48,7 +48,7 @@ export const BaggageSelectionModal: React.FC<BaggageSelectionModalProps> = ({
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
return (
|
|
51
|
-
<Modal isOpen={isOpen} onClose={() => onClose(
|
|
51
|
+
<Modal isOpen={isOpen} onClose={() => onClose(selectedServices)}>
|
|
52
52
|
<BaggageSelectionModalHeader
|
|
53
53
|
segmentCount={segments.length}
|
|
54
54
|
currentSegment={currentSegment}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { ModalBody } from "@components/Modal";
|
|
1
|
+
import { ModalBody } from "@components/shared/Modal";
|
|
2
2
|
import { getPassengerName } from "@lib/getPassengerName";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import {
|
|
5
5
|
CreateOrderPayloadPassenger,
|
|
6
6
|
CreateOrderPayloadServices,
|
|
7
|
-
} from "
|
|
7
|
+
} from "../../../types/CreateOrderPayload";
|
|
8
8
|
import {
|
|
9
9
|
Offer,
|
|
10
10
|
OfferAvailableServiceBaggage,
|
|
11
11
|
OfferSliceSegment,
|
|
12
|
-
} from "
|
|
12
|
+
} from "../../../types/Offer";
|
|
13
13
|
import { BaggageSelectionModalBodyPassenger } from "./BaggageSelectionModalBodyPassenger";
|
|
14
14
|
|
|
15
15
|
export interface BaggageSelectionModalBodyProps {
|
package/src/components/{bags → DuffelAncillaries/bags}/BaggageSelectionModalBodyPassenger.tsx
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { CreateOrderPayloadServices } from "
|
|
2
|
+
import { CreateOrderPayloadServices } from "../../../types/CreateOrderPayload";
|
|
3
3
|
import {
|
|
4
4
|
OfferAvailableServiceBaggage,
|
|
5
5
|
OfferSliceSegmentPassengerBaggage,
|
|
6
|
-
} from "
|
|
6
|
+
} from "../../../types/Offer";
|
|
7
7
|
import { BaggageSelectionController } from "./BaggageSelectionController";
|
|
8
8
|
import { IncludedBaggageBanner } from "./IncludedBaggageBanner";
|
|
9
9
|
|
|
@@ -38,9 +38,9 @@ export const BaggageSelectionModalBodyPassenger: React.FC<
|
|
|
38
38
|
<h3 style={{ margin: 0 }} className="p1--semibold">
|
|
39
39
|
{passengerName}
|
|
40
40
|
</h3>
|
|
41
|
-
{hasIncludedBaggage
|
|
41
|
+
{hasIncludedBaggage ? (
|
|
42
42
|
<IncludedBaggageBanner includedBaggage={includedBaggage} />
|
|
43
|
-
)}
|
|
43
|
+
) : null}
|
|
44
44
|
|
|
45
45
|
<div style={{ display: "flex", rowGap: "8px", flexDirection: "column" }}>
|
|
46
46
|
{passengerServicesForSegment.map((availableService) => (
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { Button } from "@components/shared/Button";
|
|
1
2
|
import { ServicePriceMapById } from "@lib/getServicePriceMapById";
|
|
2
3
|
import { getTotalAmountForServicesWithPriceMap } from "@lib/getTotalAmountForServices";
|
|
3
4
|
import { getTotalQuantity } from "@lib/getTotalQuantity";
|
|
4
5
|
import { moneyStringFormatter } from "@lib/moneyStringFormatter";
|
|
5
6
|
import { withPlural } from "@lib/withPlural";
|
|
6
7
|
import React from "react";
|
|
7
|
-
import { CreateOrderPayloadServices } from "
|
|
8
|
-
import { Button } from "../Button";
|
|
8
|
+
import { CreateOrderPayloadServices } from "../../../types/CreateOrderPayload";
|
|
9
9
|
|
|
10
10
|
export interface BaggageSelectionModalFooterProps {
|
|
11
11
|
currency: string;
|
|
@@ -38,6 +38,7 @@ export const BaggageSelectionModalFooter: React.FC<
|
|
|
38
38
|
selectedServices
|
|
39
39
|
);
|
|
40
40
|
const totalAmountLabel = moneyStringFormatter(currency)(totalAmount);
|
|
41
|
+
const isOneWay = isFirstSegment && isFirstSegment;
|
|
41
42
|
|
|
42
43
|
return (
|
|
43
44
|
<div style={{ padding: "16px 24px 24px" }}>
|
|
@@ -51,21 +52,27 @@ export const BaggageSelectionModalFooter: React.FC<
|
|
|
51
52
|
</div>
|
|
52
53
|
|
|
53
54
|
<div
|
|
54
|
-
style={
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
style={
|
|
56
|
+
isOneWay
|
|
57
|
+
? { marginTop: "16px", display: "grid" }
|
|
58
|
+
: {
|
|
59
|
+
marginTop: "16px",
|
|
60
|
+
display: "grid",
|
|
61
|
+
columnGap: "12px",
|
|
62
|
+
gridTemplateColumns: "repeat(2, 1fr)",
|
|
63
|
+
}
|
|
64
|
+
}
|
|
60
65
|
>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
{!isOneWay && (
|
|
67
|
+
<Button
|
|
68
|
+
size={48}
|
|
69
|
+
variant="outlined"
|
|
70
|
+
disabled={isFirstSegment}
|
|
71
|
+
onClick={() => onPreviousSegmentButtonClicked()}
|
|
72
|
+
>
|
|
73
|
+
Back
|
|
74
|
+
</Button>
|
|
75
|
+
)}
|
|
69
76
|
<Button
|
|
70
77
|
size={48}
|
|
71
78
|
data-testid="confirm-selection-for-baggage"
|