@qite/tide-booking-component 1.1.3 → 1.2.0

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.
Files changed (63) hide show
  1. package/build/build-cjs/booking-product/components/multi-range-filter.d.ts +12 -0
  2. package/build/build-cjs/booking-wizard/features/booking/api.d.ts +4 -1
  3. package/build/build-cjs/booking-wizard/features/booking/booking-slice.d.ts +7 -3
  4. package/build/build-cjs/booking-wizard/features/booking/selectors.d.ts +23 -17
  5. package/build/build-cjs/booking-wizard/features/flight-options/flight-filter.d.ts +9 -0
  6. package/build/build-cjs/booking-wizard/features/flight-options/flight-option-flight.d.ts +8 -0
  7. package/build/build-cjs/booking-wizard/features/flight-options/flight-option-modal.d.ts +3 -0
  8. package/build/build-cjs/booking-wizard/features/flight-options/flight-option.d.ts +4 -9
  9. package/build/build-cjs/booking-wizard/features/flight-options/flight-utils.d.ts +6 -0
  10. package/build/build-cjs/booking-wizard/features/room-options/room-utils.d.ts +9 -0
  11. package/build/build-cjs/booking-wizard/features/room-options/room.d.ts +12 -0
  12. package/build/build-cjs/booking-wizard/features/room-options/traveler-rooms.d.ts +9 -0
  13. package/build/build-cjs/booking-wizard/types.d.ts +101 -0
  14. package/build/build-cjs/index.js +1563 -606
  15. package/build/build-cjs/shared/utils/localization-util.d.ts +30 -2
  16. package/build/build-esm/booking-product/components/multi-range-filter.d.ts +12 -0
  17. package/build/build-esm/booking-wizard/features/booking/api.d.ts +4 -1
  18. package/build/build-esm/booking-wizard/features/booking/booking-slice.d.ts +7 -3
  19. package/build/build-esm/booking-wizard/features/booking/selectors.d.ts +23 -17
  20. package/build/build-esm/booking-wizard/features/flight-options/flight-filter.d.ts +9 -0
  21. package/build/build-esm/booking-wizard/features/flight-options/flight-option-flight.d.ts +8 -0
  22. package/build/build-esm/booking-wizard/features/flight-options/flight-option-modal.d.ts +3 -0
  23. package/build/build-esm/booking-wizard/features/flight-options/flight-option.d.ts +4 -9
  24. package/build/build-esm/booking-wizard/features/flight-options/flight-utils.d.ts +6 -0
  25. package/build/build-esm/booking-wizard/features/room-options/room-utils.d.ts +9 -0
  26. package/build/build-esm/booking-wizard/features/room-options/room.d.ts +12 -0
  27. package/build/build-esm/booking-wizard/features/room-options/traveler-rooms.d.ts +9 -0
  28. package/build/build-esm/booking-wizard/types.d.ts +101 -0
  29. package/build/build-esm/index.js +1564 -607
  30. package/build/build-esm/shared/utils/localization-util.d.ts +30 -2
  31. package/package.json +3 -3
  32. package/rollup.config.js +23 -23
  33. package/src/booking-product/components/multi-range-filter.css +115 -0
  34. package/src/booking-product/components/multi-range-filter.tsx +114 -0
  35. package/src/booking-wizard/components/labeled-input.tsx +64 -64
  36. package/src/booking-wizard/components/labeled-select.tsx +69 -69
  37. package/src/booking-wizard/components/step-indicator.tsx +3 -3
  38. package/src/booking-wizard/features/booking/api.ts +12 -1
  39. package/src/booking-wizard/features/booking/booking-self-contained.tsx +50 -20
  40. package/src/booking-wizard/features/booking/booking-slice.ts +45 -9
  41. package/src/booking-wizard/features/booking/booking.tsx +67 -56
  42. package/src/booking-wizard/features/booking/selectors.ts +38 -11
  43. package/src/booking-wizard/features/flight-options/flight-filter.tsx +343 -0
  44. package/src/booking-wizard/features/flight-options/flight-option-flight.tsx +350 -0
  45. package/src/booking-wizard/features/flight-options/flight-option.tsx +30 -759
  46. package/src/booking-wizard/features/flight-options/flight-utils.ts +401 -0
  47. package/src/booking-wizard/features/flight-options/index.tsx +55 -368
  48. package/src/booking-wizard/features/price-details/util.ts +6 -6
  49. package/src/booking-wizard/features/product-options/option-room.tsx +3 -5
  50. package/src/booking-wizard/features/product-options/options-form.tsx +46 -54
  51. package/src/booking-wizard/features/room-options/index.tsx +48 -144
  52. package/src/booking-wizard/features/room-options/room-utils.ts +143 -0
  53. package/src/booking-wizard/features/room-options/room.tsx +124 -0
  54. package/src/booking-wizard/features/room-options/traveler-rooms.tsx +63 -0
  55. package/src/booking-wizard/features/sidebar/sidebar-util.ts +2 -2
  56. package/src/booking-wizard/features/summary/summary.tsx +2 -2
  57. package/src/booking-wizard/features/travelers-form/travelers-form.tsx +1 -1
  58. package/src/booking-wizard/types.ts +116 -0
  59. package/src/shared/components/rating.tsx +21 -21
  60. package/src/shared/translations/fr-BE.json +222 -192
  61. package/src/shared/translations/nl-BE.json +222 -192
  62. package/src/shared/utils/class-util.ts +9 -9
  63. package/tsconfig.json +24 -24
@@ -0,0 +1,124 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { useSelector } from "react-redux";
3
+ import { getPriceDifferenceText } from "../../../shared/utils/localization-util";
4
+ import { SelectableRoomAccommodation } from "../../types";
5
+ import { selectTranslations } from "../booking/selectors";
6
+ import { getDatePeriodText, getDateText } from "../sidebar/sidebar-util";
7
+ import { buildClassName } from "../../../shared/utils/class-util";
8
+
9
+ interface RoomOptionProps {
10
+ room: SelectableRoomAccommodation;
11
+ hasAlternatives?: boolean;
12
+ selectedRoomPrice?: number;
13
+ onAcommodationChange?: (accommodationCode: string, regimeCode: string) => void,
14
+ onRegimeChange?: (code: string) => void,
15
+ onToggleAlternatives?: () => void
16
+ }
17
+
18
+ const RoomOption: React.FC<RoomOptionProps> = ({
19
+ room,
20
+ hasAlternatives,
21
+ selectedRoomPrice,
22
+ onAcommodationChange,
23
+ onRegimeChange,
24
+ onToggleAlternatives
25
+ }) => {
26
+ const translations = useSelector(selectTranslations);
27
+
28
+ const [roomPrice, setRoomPrice] = useState<number>(0);
29
+ const [roomRegimeCode, setRoomRegimeCode] = useState<string>(room.regimeCode);
30
+
31
+ useEffect(() => {
32
+ setRoomPrice(room.price);
33
+ }, [room.code, room.regimeCode]);
34
+
35
+ const getPriceDifference = (selectedPrice: number, currentPrice: number) => {
36
+ const priceDifference = (selectedPrice ?? 0) - currentPrice;
37
+ if (priceDifference !== 0) {
38
+ return `(${getPriceDifferenceText(priceDifference)})`;
39
+ } else {
40
+ return "";
41
+ }
42
+ };
43
+
44
+ const selectAccommodation = () => {
45
+ if (onAcommodationChange) {
46
+ onAcommodationChange(room.code, roomRegimeCode);
47
+ }
48
+ }
49
+
50
+ const handleRegimeChange: React.FormEventHandler<HTMLSelectElement> = (
51
+ e
52
+ ) => {
53
+ let regimeCode = e.currentTarget.value;
54
+
55
+ const option = room.regimes.find(x => x.code === regimeCode || (x.code === null && regimeCode === ''))!;
56
+ setRoomRegimeCode(option.code);
57
+ setRoomPrice(option.price);
58
+
59
+ if (onRegimeChange) {
60
+ onRegimeChange(regimeCode);
61
+ }
62
+
63
+ e.preventDefault();
64
+ };
65
+
66
+ return (
67
+ <>
68
+ <div className="form__room">
69
+ {room.viewHtml && (
70
+ <div className="form__room__wrapper" dangerouslySetInnerHTML={{ __html: room.viewHtml }} />
71
+ )}
72
+ {!room.viewHtml && (
73
+ <div className="form__room__wrapper">
74
+ {room.image && (
75
+ <div className="form__room__image">
76
+ <img src={room.image} alt="" className="form__room__img" />
77
+ </div>
78
+ )}
79
+ <div className="form__room__body">
80
+ <div className="">
81
+ <h3 className="form__room__title">{room.title}</h3>
82
+ {room.description && (
83
+ <p className="form__room__text">{room.description}</p>
84
+ )}
85
+ <ul className="list--usps form__room__usps">
86
+ {room.usps.map((usp, uspIndex) => (
87
+ <li key={uspIndex} className="list__item">{usp}</li>
88
+ ))}
89
+ </ul>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ )}
94
+ <div className="form__room__footer">
95
+ <div className="form__room__footer__top">
96
+ <p className="form__room__dates">{getDateText(room.from)} - {getDateText(room.to)}</p>
97
+ <span className="form__room__days">{getDatePeriodText(room.from, room.to)}</span>
98
+ </div>
99
+ <div className="form__room__footer__bottom">
100
+ {selectedRoomPrice != undefined && (
101
+ <p className="form__room__price form__room__price--increase"><span>{getPriceDifference(roomPrice, selectedRoomPrice)}</span></p>
102
+ )}
103
+ {hasAlternatives && onToggleAlternatives && (<button type="button" onClick={onToggleAlternatives} className="form__room__alternatives__btn">{translations.ROOM_OPTIONS_FORM.SHOW_ALTERNATIVES}</button>)}
104
+ <div className="select-wrapper">
105
+ <div className="select-wrapper__select">
106
+ <select
107
+ defaultValue={roomRegimeCode}
108
+ onChange={handleRegimeChange}
109
+ >
110
+ {room.regimes.map(regime => (
111
+ <option key={regime.code} value={regime.code ?? ""}>{regime.title} {getPriceDifference(regime.price, roomPrice)}</option>
112
+ ))}
113
+ </select>
114
+ </div>
115
+ </div>
116
+ <button type="button" onClick={selectAccommodation} className={buildClassName(['cta', selectedRoomPrice ? 'cta--secondary' : 'cta--selected'])}>{selectedRoomPrice ? translations.SHARED.SELECT : translations.SHARED.SELECTED}</button>
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </>
121
+ );
122
+ }
123
+
124
+ export default RoomOption;
@@ -0,0 +1,63 @@
1
+ import React, { useState } from "react";
2
+ import { SelectableRoom } from "../../types";
3
+ import { useSelector } from "react-redux";
4
+ import { selectTranslations } from "../booking/selectors";
5
+ import RoomOption from "./room";
6
+ import { isEmpty } from "lodash";
7
+
8
+ interface TravelerRoomsProps {
9
+ index: number,
10
+ room: SelectableRoom;
11
+ onRoomChange: (index: number, accommodationCode: string, regimeCode: string | null) => void
12
+ }
13
+
14
+ const TravelerRooms: React.FC<TravelerRoomsProps> = ({
15
+ index,
16
+ room,
17
+ onRoomChange
18
+ }) => {
19
+ const translations = useSelector(selectTranslations);
20
+ const [showAlternatives, setShowAlternatives] = useState<boolean>(false);
21
+
22
+ const selectedAccommodationCode = room.selected.code;
23
+
24
+ return (
25
+ <div key={room.index}>
26
+ <div className="form__room__header">
27
+ <h5>{translations.ROOM_OPTIONS_FORM.TRAVELER_GROUP} {room.index + 1}</h5>
28
+ </div>
29
+
30
+ <RoomOption
31
+ room={room.selected}
32
+ hasAlternatives={!isEmpty(room.alternatives)}
33
+ onRegimeChange={(regimeCode) => onRoomChange(index, selectedAccommodationCode, regimeCode)}
34
+ onToggleAlternatives={() => setShowAlternatives(!showAlternatives)} />
35
+
36
+ {!isEmpty(room.alternatives) && showAlternatives && (
37
+ <div className="form__room__alternatives">
38
+ <div className="form__room__alternatives__header">
39
+ {translations.ROOM_OPTIONS_FORM.ALTERNATIVES_TRAVELER_GROUP} {room.index + 1}
40
+ </div>
41
+
42
+ {showAlternatives && (
43
+ <>
44
+ {room.alternatives.map((alternative, alternativeIndex) => (
45
+ <RoomOption
46
+ key={alternativeIndex}
47
+ room={alternative}
48
+ selectedRoomPrice={room.selected.price}
49
+ onAcommodationChange={(accommodationCode, regimeCode) => {
50
+ setShowAlternatives(false);
51
+ onRoomChange(index, accommodationCode, regimeCode);
52
+ }
53
+ } />
54
+ ))}
55
+ </>
56
+ )}
57
+ </div>
58
+ )}
59
+ </div>
60
+ )
61
+ }
62
+
63
+ export default TravelerRooms;
@@ -154,12 +154,12 @@ export const parseFlightLines = (
154
154
  };
155
155
 
156
156
  const parseFlightLineDateTime = (
157
- date: Date,
157
+ date: string,
158
158
  time: string
159
159
  ): string | undefined => {
160
160
  try {
161
161
  // Parse date
162
- const parsedDate = new Date(date);
162
+ const parsedDate = parseISO(date);
163
163
 
164
164
  // Parse time
165
165
  const parsedTimeHours = parseInt(time.substring(0, 2));
@@ -202,11 +202,11 @@ const Summary: React.FC<SummaryProps> = () => {
202
202
 
203
203
  const result = await validateVoucher(tideClientConfig, request);
204
204
 
205
- if (result?.payload) {
205
+ if (result) {
206
206
  setVoucher({
207
207
  ...voucher,
208
208
  isValidated: true,
209
- isValid: result.payload.isValid,
209
+ isValid: result.isValid,
210
210
  });
211
211
  }
212
212
  };
@@ -224,7 +224,7 @@ const TravelersForm: React.FC<TravelersFormProps> = () => {
224
224
 
225
225
  return (
226
226
  <form
227
- className="form"
227
+ className="form form__travelers"
228
228
  name="booking--travellers"
229
229
  id="booking--travellers"
230
230
  noValidate
@@ -1,3 +1,5 @@
1
+ import { BookingPackageFlight } from "@qite/tide-client/build/types";
2
+
1
3
  export interface Settings {
2
4
  officeId: number;
3
5
  bookingOptions: BookingOptions;
@@ -54,6 +56,9 @@ export interface Settings {
54
56
  language: string,
55
57
  path: string;
56
58
  }[];
59
+ accommodations?: AccommodationContent[];
60
+ regimes?: RegimeContent[];
61
+ accommodationViewId?: number;
57
62
  }
58
63
 
59
64
  export interface BookingOptions {
@@ -152,3 +157,114 @@ export interface FlightLine {
152
157
  airlineNumber?: string;
153
158
  travelClass?: string;
154
159
  }
160
+
161
+ export interface AccommodationContent {
162
+ code: string;
163
+ title: string;
164
+ imageUrl: string;
165
+ usps: string[];
166
+ description: string | undefined;
167
+ }
168
+
169
+ export interface RegimeContent {
170
+ code: string;
171
+ title: string;
172
+ }
173
+
174
+ export interface SelectableRoom {
175
+ index: number;
176
+ selected: SelectableRoomAccommodation,
177
+ alternatives: SelectableRoomAccommodation[];
178
+ }
179
+
180
+ export interface SelectableRoomAccommodation {
181
+ code: string;
182
+ regimeCode: string;
183
+ from: string;
184
+ to: string;
185
+ price: number;
186
+ regimes: SelectableRoomRegime[];
187
+ title: string;
188
+ image: string | undefined;
189
+ usps: string[];
190
+ description: string | undefined;
191
+ viewHtml: string | undefined
192
+ }
193
+
194
+ export interface SelectableRoomRegime {
195
+ code: string;
196
+ title: string;
197
+ price: number;
198
+ }
199
+
200
+ export interface GroupedFlights {
201
+ isSelected: boolean;
202
+ price: number;
203
+
204
+ outward: GroupedFlightDetails;
205
+ return: GroupedFlightDetails;
206
+
207
+ selectedOutward: BookingPackageFlight;
208
+ selectedReturn: BookingPackageFlight;
209
+ }
210
+
211
+ export interface GroupedFlightDetails {
212
+ airlineCode: string;
213
+ airline: string;
214
+ departureDate: string;
215
+ departureTime: string;
216
+ departureAirportCode: string;
217
+ departureAirport: string;
218
+ arrivalDate: string;
219
+ arrivalTime: string;
220
+ arrivalAirport: string;
221
+ changeDurationMinutes: number;
222
+ travelDurationMinutes: number;
223
+ travelDuration: string;
224
+ numberOfStops: number;
225
+ isNextDay: boolean;
226
+ travelClass: string;
227
+ flightLines: GroupedFlightLine[];
228
+ }
229
+
230
+ export interface GroupedFlightLine {
231
+ airline: string;
232
+ number: string;
233
+ departureDate: string;
234
+ departureTime: string;
235
+ departureAirport: string;
236
+ arrivalDate: string;
237
+ arrivalTime: string;
238
+ arrivalAirport: string;
239
+ travelDuration: string;
240
+ waitDuration: string | undefined;
241
+ }
242
+
243
+ export interface FlightFilterOptions {
244
+ airports: FlightFilterOption[];
245
+ airlines: FlightFilterOption[];
246
+ numberOfStops: FlightFilterOption[];
247
+ outward: FlightDirectionFilter;
248
+ return: FlightDirectionFilter;
249
+ }
250
+
251
+ export interface FlightFilterOption {
252
+ value: string;
253
+ label: string;
254
+ count: number;
255
+ isSelected: boolean;
256
+ }
257
+
258
+ export interface FlightDirectionFilter {
259
+ departurePeriod: FlightFilterOption[];
260
+ travelDuration: TimeRangeFilter;
261
+ changeDuration: TimeRangeFilter;
262
+ }
263
+
264
+ export interface TimeRangeFilter {
265
+ min: number;
266
+ max: number;
267
+
268
+ selectedMin: number;
269
+ selectedMax: number;
270
+ }
@@ -1,21 +1,21 @@
1
- import React from "react";
2
- import { clamp, range } from "lodash";
3
- import Icon from "../../booking-wizard/components/icon";
4
-
5
- interface RatingProps {
6
- rating: number;
7
- }
8
-
9
- const Rating: React.FC<RatingProps> = ({ rating }) => {
10
- const clampedRating = clamp(rating, 0, 5);
11
- return (
12
- <div className="rating">
13
- {range(0, Math.floor(clampedRating)).map((i) => (
14
- <Icon name="product-star" key={`rating-star-${i}`} />
15
- ))}
16
- {clampedRating % 1 > 0 && <Icon name="product-halfstar" />}
17
- </div>
18
- );
19
- };
20
-
21
- export default Rating;
1
+ import React from "react";
2
+ import { clamp, range } from "lodash";
3
+ import Icon from "../../booking-wizard/components/icon";
4
+
5
+ interface RatingProps {
6
+ rating: number;
7
+ }
8
+
9
+ const Rating: React.FC<RatingProps> = ({ rating }) => {
10
+ const clampedRating = clamp(rating, 0, 5);
11
+ return (
12
+ <div className="rating">
13
+ {range(0, Math.floor(clampedRating)).map((i) => (
14
+ <Icon name="product-star" key={`rating-star-${i}`} />
15
+ ))}
16
+ {clampedRating % 1 > 0 && <Icon name="product-halfstar" />}
17
+ </div>
18
+ );
19
+ };
20
+
21
+ export default Rating;