@qite/tide-booking-component 1.4.113 → 1.4.114

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.
@@ -10,12 +10,14 @@ import { SearchSeed } from '../../types';
10
10
  import { getTravelersText } from '../../../booking-wizard/features/sidebar/sidebar-util';
11
11
  import { RoomTraveler } from '../../../booking-wizard/types';
12
12
 
13
- import { BookingPackageFlightMetaData, BookingPriceDetail, PackagingEntryLine } from '@qite/tide-client';
13
+ import { BookingPackageFlightMetaData, BookingPriceDetail, PackagingAccommodationResponse, PackagingEntryLine, PortalQsmType } from '@qite/tide-client';
14
14
  import Spinner from '../spinner/spinner';
15
15
  import SharedSidebar from '../../../shared/booking/shared-sidebar';
16
+ import { getImageSrcFromHtml } from '../../../shared/utils/booking-summary';
16
17
 
17
18
  interface WLSidebarProps {
18
19
  activeSearchSeed: SearchSeed | null;
20
+ packagingAccoResult: PackagingAccommodationResponse | null;
19
21
  }
20
22
 
21
23
  const mapToSidebarFlightMetaData = (entryLine: PackagingEntryLine) => {
@@ -66,18 +68,12 @@ const selectSeparatePackagePriceDetails = (priceDetails: BookingPriceDetail[]) =
66
68
  return result;
67
69
  };
68
70
 
69
- const WLSidebar: React.FC<WLSidebarProps> = ({ activeSearchSeed }) => {
71
+ const WLSidebar: React.FC<WLSidebarProps> = ({ activeSearchSeed, packagingAccoResult }) => {
70
72
  const context = useContext(SearchResultsConfigurationContext);
71
- if (!context) {
72
- return null;
73
- }
74
- const translations = getTranslations(context.languageCode ?? 'en-GB');
73
+
75
74
  const { editablePackagingEntry, priceDetails } = useSelector((state: SearchResultsRootState) => state.searchResults);
76
75
 
77
- // Map editablePackagingEntry to sidebar props (example, adjust as needed)
78
- if (!editablePackagingEntry) {
79
- return null;
80
- }
76
+ const translations = getTranslations(context?.languageCode ?? 'en-GB');
81
77
 
82
78
  const sortedLines = useMemo(() => {
83
79
  return [...(editablePackagingEntry?.lines ?? [])].sort((a, b) => {
@@ -92,16 +88,31 @@ const WLSidebar: React.FC<WLSidebarProps> = ({ activeSearchSeed }) => {
92
88
  });
93
89
  }, [editablePackagingEntry]);
94
90
 
91
+ const accoImage = useMemo(() => {
92
+ return getImageSrcFromHtml(packagingAccoResult?.contents);
93
+ }, [packagingAccoResult?.contents]);
94
+
95
+ if (!context || !editablePackagingEntry) {
96
+ return null;
97
+ }
98
+
95
99
  const firstEntryLine = first(sortedLines);
96
100
  const accommodationLines = editablePackagingEntry.lines.filter((line) => line.serviceType === ACCOMMODATION_SERVICE_TYPE);
97
101
  const accommodationLine = first(accommodationLines) ?? firstEntryLine;
98
102
 
99
103
  const location =
100
- accommodationLine?.location?.name ??
101
- accommodationLine?.oord?.name ??
102
- accommodationLine?.region?.name ??
103
- accommodationLine?.country?.name ??
104
- firstEntryLine?.location?.name;
104
+ context.searchConfiguration.qsmType === PortalQsmType.Accommodation
105
+ ? packagingAccoResult?.name ??
106
+ accommodationLine?.location?.name ??
107
+ accommodationLine?.oord?.name ??
108
+ accommodationLine?.region?.name ??
109
+ accommodationLine?.country?.name ??
110
+ firstEntryLine?.location?.name
111
+ : accommodationLine?.location?.name ??
112
+ accommodationLine?.oord?.name ??
113
+ accommodationLine?.region?.name ??
114
+ accommodationLine?.country?.name ??
115
+ firstEntryLine?.location?.name;
105
116
 
106
117
  const rooms =
107
118
  activeSearchSeed?.rooms.map((room) => {
@@ -136,7 +147,7 @@ const WLSidebar: React.FC<WLSidebarProps> = ({ activeSearchSeed }) => {
136
147
  return (
137
148
  <SharedSidebar
138
149
  productName={location ?? ''}
139
- thumbnailUrl={context.destinationImage?.url}
150
+ thumbnailUrl={accoImage ?? context.destinationImage?.url}
140
151
  translations={translations}
141
152
  travelerRooms={travelerRooms}
142
153
  startDateText={first(sortedLines)?.from && formatDate(new Date(first(sortedLines)!.from))}
@@ -94,9 +94,12 @@ const IndependentFlightSelection: React.FC<IndependentFlightSelectionProps> = ({
94
94
  }, [searchResults, selectedReturnKey]);
95
95
 
96
96
  const firstResultDate = uniqueOutwardFlights.length > 0 ? uniqueOutwardFlights[0].outward.segments[0].departureDateTime : null;
97
+ const firstResultReturnDate = uniqueReturnFlights.length > 0 ? uniqueReturnFlights[0].return.segments[0].departureDateTime : null;
97
98
 
98
99
  const firstResultDay = firstResultDate ? format(firstResultDate, 'd') : null;
99
100
  const firstResultMonth = firstResultDate ? format(firstResultDate, 'MMM') : null;
101
+ const firstResultReturnDay = firstResultReturnDate ? format(firstResultReturnDate, 'd') : null;
102
+ const firstResultReturnMonth = firstResultReturnDate ? format(firstResultReturnDate, 'MMM') : null;
100
103
 
101
104
  return (
102
105
  <>
@@ -138,8 +141,8 @@ const IndependentFlightSelection: React.FC<IndependentFlightSelectionProps> = ({
138
141
 
139
142
  <div className="search__results__label search__results__label--secondary">
140
143
  <div className="search__results__label__date">
141
- {/* <p className="search__results__label__date-date">{format(day, 'd', { locale: getLocale(context?.languageCode ?? 'en-GB') })}</p>
142
- <p>{format(day, 'MMM', { locale: getLocale(context?.languageCode ?? 'en-GB') })}</p> */}
144
+ <p className="search__results__label__date-date">{firstResultReturnDay}</p>
145
+ <p>{firstResultReturnMonth}</p>
143
146
  </div>
144
147
  <div className="search__results__label__text">
145
148
  <Icon name="ui-flight" height={16} fill="white" />
@@ -175,12 +175,21 @@ const HotelAccommodationResults: React.FC<HotelAccommodationResultsProps> = ({ i
175
175
  const visibleResults = React.useMemo(() => {
176
176
  const shouldShowAll = context?.searchConfiguration.qsmType !== PortalQsmType.AccommodationAndFlight || isFlyIn;
177
177
 
178
+ let filteredMapperResults = mappedResults;
179
+
180
+ if (selectedPackagingAccoResult) {
181
+ filteredMapperResults = mappedResults.filter((result) => result.code !== selectedPackagingAccoResult.code);
182
+ }
183
+
178
184
  if (shouldShowAll) {
179
- return mappedResults;
185
+ if (isFlyIn) {
186
+ return mappedResults;
187
+ }
188
+ return filteredMapperResults;
180
189
  }
181
190
 
182
191
  if (selectedPackagingAccoResult) {
183
- return mappedResults.filter((result) => result.code !== selectedPackagingAccoResult.code).slice(0, 2);
192
+ return filteredMapperResults.filter((result) => result.code !== selectedPackagingAccoResult.code).slice(0, 2);
184
193
  }
185
194
 
186
195
  return mappedResults.slice(0, 3);
@@ -1489,7 +1489,11 @@ const SearchResultsContainer: React.FC<SearchResultsContainerProps> = ({ onBooki
1489
1489
  {context && (
1490
1490
  <div className="search">
1491
1491
  {bookPackagingEntry ? (
1492
- <BookPackagingEntry activeSearchSeed={activeSearchSeed} isConfirmationPage={isBookingConfirmation} />
1492
+ <BookPackagingEntry
1493
+ activeSearchSeed={activeSearchSeed}
1494
+ isLoading={itineraryIsLoading || pricesAreLoading}
1495
+ isConfirmationPage={isBookingConfirmation}
1496
+ />
1493
1497
  ) : (
1494
1498
  <div className="search__container">
1495
1499
  {context.searchConfiguration.qsmType === PortalQsmType.Flight && (
@@ -1,7 +1,6 @@
1
1
  import { compact, findIndex, isEmpty, isNil, uniqBy } from 'lodash';
2
2
  import React, { ReactNode, useEffect, useState } from 'react';
3
3
  import { SummaryCheckbox, TravelersFormValues } from '../../booking-wizard/types';
4
- import Loader from '../components/loader';
5
4
  import { buildClassName } from '../utils/class-util';
6
5
  import Icon from '../components/icon';
7
6
  import Spinner from '../../search-results/components/spinner/spinner';
@@ -4,6 +4,7 @@ import { useFlightSearch } from '../../../search-results/components/flight/fligh
4
4
  import { useDispatch, useSelector } from 'react-redux';
5
5
  import {
6
6
  resetFilters,
7
+ setBookPackagingEntry,
7
8
  setFilters,
8
9
  setFlyInType,
9
10
  setSelectedFlight,
@@ -125,6 +126,14 @@ const FlyIn: React.FC<FlyInProps> = ({
125
126
  }
126
127
  };
127
128
 
129
+ const onHandleConfirm = () => {
130
+ if (context?.packagingEntry) {
131
+ handleConfirm?.();
132
+ } else {
133
+ dispatch(setBookPackagingEntry(true));
134
+ }
135
+ };
136
+
128
137
  return (
129
138
  <div
130
139
  className={`flyin ${isOpen ? 'flyin--active' : ''} ${className} ${isPackageEditFlow || flyInType === 'acco-results' ? 'flyin--large' : ''} ${
@@ -211,7 +220,7 @@ const FlyIn: React.FC<FlyInProps> = ({
211
220
  )}
212
221
 
213
222
  {(srpType === PortalQsmType.Accommodation || srpType === PortalQsmType.AccommodationAndFlight) && flyInType === 'acco-details' && (
214
- <AccommodationFlyIn isLoading={detailsLoading} handleConfirm={handleConfirm!} />
223
+ <AccommodationFlyIn isLoading={detailsLoading} handleConfirm={onHandleConfirm} />
215
224
  )}
216
225
 
217
226
  {srpType === PortalQsmType.AccommodationAndFlight && (flyInType === 'flight-outward-results' || flyInType === 'flight-return-results') && (
@@ -44,3 +44,14 @@ export const renderEditablePackagingEntrySummaryOptions = (editablePackagingEntr
44
44
  );
45
45
  });
46
46
  };
47
+
48
+ export const getImageSrcFromHtml = (html?: string | null): string | undefined => {
49
+ if (!html || typeof window === 'undefined') {
50
+ return undefined;
51
+ }
52
+
53
+ const doc = new DOMParser().parseFromString(html, 'text/html');
54
+ const img = doc.querySelector('img');
55
+
56
+ return img?.getAttribute('src') ?? undefined;
57
+ };
@@ -13,6 +13,7 @@
13
13
  border-left: 2px solid var(--tide-booking-room-options-dropdown-select-icon-color);
14
14
  border-bottom: 2px solid var(--tide-booking-room-options-dropdown-select-icon-color);
15
15
  transform: rotate(-45deg);
16
+ pointer-events: none;
16
17
  }
17
18
  }
18
19
 
@@ -30,6 +31,10 @@
30
31
  border: --tide-booking-room-options-dropdown-select-border-focus;
31
32
  }
32
33
 
34
+ &:hover {
35
+ cursor: pointer;
36
+ }
37
+
33
38
  option {
34
39
  appearance: none;
35
40
  display: flex;