@qite/tide-booking-component 1.4.97 → 1.4.99

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 (30) hide show
  1. package/build/build-cjs/index.js +1423 -975
  2. package/build/build-cjs/src/search-results/components/itinerary/index.d.ts +2 -0
  3. package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +9 -10
  4. package/build/build-cjs/src/search-results/types.d.ts +24 -1
  5. package/build/build-cjs/src/search-results/utils/packaging-utils.d.ts +7 -0
  6. package/build/build-cjs/src/search-results/utils/query-utils.d.ts +11 -0
  7. package/build/build-cjs/src/shared/components/flyin/accommodation-flyin.d.ts +1 -2
  8. package/build/build-cjs/src/shared/components/flyin/flyin.d.ts +4 -0
  9. package/build/build-cjs/src/shared/utils/localization-util.d.ts +1 -0
  10. package/build/build-esm/index.js +1419 -965
  11. package/build/build-esm/src/search-results/components/itinerary/index.d.ts +2 -0
  12. package/build/build-esm/src/search-results/store/search-results-slice.d.ts +9 -10
  13. package/build/build-esm/src/search-results/types.d.ts +24 -1
  14. package/build/build-esm/src/search-results/utils/packaging-utils.d.ts +7 -0
  15. package/build/build-esm/src/search-results/utils/query-utils.d.ts +11 -0
  16. package/build/build-esm/src/shared/components/flyin/accommodation-flyin.d.ts +1 -2
  17. package/build/build-esm/src/shared/components/flyin/flyin.d.ts +4 -0
  18. package/build/build-esm/src/shared/utils/localization-util.d.ts +1 -0
  19. package/package.json +2 -2
  20. package/src/qsm/components/search-input-group/index.tsx +0 -1
  21. package/src/search-results/components/itinerary/index.tsx +331 -234
  22. package/src/search-results/components/search-results-container/search-results-container.tsx +444 -383
  23. package/src/search-results/store/search-results-slice.ts +22 -10
  24. package/src/search-results/types.ts +26 -1
  25. package/src/search-results/utils/packaging-utils.ts +75 -0
  26. package/src/search-results/utils/query-utils.ts +152 -0
  27. package/src/shared/components/flyin/accommodation-flyin.tsx +10 -11
  28. package/src/shared/components/flyin/flyin.tsx +52 -4
  29. package/styles/components/_flyin.scss +25 -0
  30. package/styles/components/_search.scss +28 -1
@@ -1,6 +1,6 @@
1
1
  import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2
- import { ExtendedFlightSearchResponseItem, Filter, SortByType } from '../types';
3
- import { BookingPackage, BookingPackageItem, EntryLight, PackagingAccommodationResponse } from '@qite/tide-client/build/types';
2
+ import { AccommodationFlyInStep, ExtendedFlightSearchResponseItem, Filter, SortByType } from '../types';
3
+ import { BookingPackage, BookingPackageItem, PackagingAccommodationResponse, PackagingEntry } from '@qite/tide-client/build/types';
4
4
 
5
5
  export interface SearchResultsState {
6
6
  results: BookingPackageItem[];
@@ -13,13 +13,15 @@ export interface SearchResultsState {
13
13
  selectedFlight: ExtendedFlightSearchResponseItem | null;
14
14
  selectedFlightDetails: ExtendedFlightSearchResponseItem | null;
15
15
  bookingPackageDetails: BookingPackage | null;
16
- entry: EntryLight | null;
17
16
  isLoading: boolean;
18
17
  filters: Filter[];
19
18
  selectedSortType: SortByType | null;
20
19
  activeTab: string | null;
21
20
  currentPage: number;
22
21
  flyInIsOpen: boolean;
22
+ editablePackagingEntry: PackagingEntry | null;
23
+ transactionId: string | null;
24
+ accommodationFlyInStep: AccommodationFlyInStep;
23
25
  }
24
26
 
25
27
  const initialState: SearchResultsState = {
@@ -33,13 +35,15 @@ const initialState: SearchResultsState = {
33
35
  selectedFlight: null,
34
36
  selectedFlightDetails: null,
35
37
  bookingPackageDetails: null,
36
- entry: null,
37
38
  isLoading: false,
38
39
  filters: [],
39
40
  selectedSortType: null,
40
41
  activeTab: 'compact',
41
42
  currentPage: 1,
42
- flyInIsOpen: false
43
+ flyInIsOpen: false,
44
+ editablePackagingEntry: null,
45
+ transactionId: null,
46
+ accommodationFlyInStep: 'details'
43
47
  };
44
48
 
45
49
  const searchResultsSlice = createSlice({
@@ -76,9 +80,6 @@ const searchResultsSlice = createSlice({
76
80
  setBookingPackageDetails(state, action: PayloadAction<{ details: BookingPackage }>) {
77
81
  state.bookingPackageDetails = action.payload.details;
78
82
  },
79
- setEntry(state, action: PayloadAction<{ entry: EntryLight }>) {
80
- state.entry = action.payload.entry;
81
- },
82
83
  selectFlight(state, action: PayloadAction<{ flightOptionId: string; isDeparture: boolean }>) {
83
84
  if (!state.bookingPackageDetails) return;
84
85
 
@@ -128,6 +129,15 @@ const searchResultsSlice = createSlice({
128
129
  },
129
130
  setFlyInIsOpen(state, action: PayloadAction<boolean>) {
130
131
  state.flyInIsOpen = action.payload;
132
+ },
133
+ setEditablePackagingEntry(state, action: PayloadAction<PackagingEntry | null>) {
134
+ state.editablePackagingEntry = action.payload;
135
+ },
136
+ setTransactionId(state, action: PayloadAction<string | null>) {
137
+ state.transactionId = action.payload;
138
+ },
139
+ setAccommodationFlyInStep(state, action: PayloadAction<AccommodationFlyInStep>) {
140
+ state.accommodationFlyInStep = action.payload;
131
141
  }
132
142
  }
133
143
  });
@@ -143,7 +153,6 @@ export const {
143
153
  setSelectedFlight,
144
154
  setSelectedFlightDetails,
145
155
  setBookingPackageDetails,
146
- setEntry,
147
156
  selectFlight,
148
157
  setIsLoading,
149
158
  setFilters,
@@ -152,7 +161,10 @@ export const {
152
161
  setActiveTab,
153
162
  setCurrentPage,
154
163
  resetSearchState,
155
- setFlyInIsOpen
164
+ setFlyInIsOpen,
165
+ setEditablePackagingEntry,
166
+ setTransactionId,
167
+ setAccommodationFlyInStep
156
168
  } = searchResultsSlice.actions;
157
169
 
158
170
  export default searchResultsSlice.reducer;
@@ -1,4 +1,10 @@
1
- import { BookingPackage, FlightSearchResponseItem, WebsiteConfigurationSearchConfiguration } from '@qite/tide-client';
1
+ import {
2
+ BookingPackage,
3
+ BookingPackageRequestRoom,
4
+ FlightSearchResponseItem,
5
+ PackagingEntry,
6
+ WebsiteConfigurationSearchConfiguration
7
+ } from '@qite/tide-client';
2
8
  import { ReactNode } from 'react';
3
9
 
4
10
  export type FlightSelectionMode = 'paired' | 'independent';
@@ -53,6 +59,7 @@ export interface SearchResultsConfiguration {
53
59
 
54
60
  destinationImage?: { url: string; alt: string };
55
61
  onBook?: (result: BookingPackage) => void;
62
+ packagingEntry?: PackagingEntry;
56
63
  }
57
64
 
58
65
  export type FilterType = 'checkbox' | 'toggle' | 'slider' | 'star-rating';
@@ -179,3 +186,21 @@ export interface TideTag {
179
186
  id: number;
180
187
  name: string;
181
188
  }
189
+
190
+ export type SearchSeed = {
191
+ fromDate: string;
192
+ toDate: string;
193
+ country?: number | null;
194
+ region?: number | null;
195
+ oord?: number | null;
196
+ location?: number | null;
197
+ hotel?: number | null;
198
+ hotelCode?: string | null;
199
+ tagId?: number | null;
200
+ departureAirport?: string | null;
201
+ returnAirport?: string | null;
202
+ destinationAirport?: string | null;
203
+ rooms: BookingPackageRequestRoom[];
204
+ };
205
+
206
+ export type AccommodationFlyInStep = 'results' | 'details';
@@ -0,0 +1,75 @@
1
+ import { BookingPackagePax, BookingPackageRequestRoom, PackagingAccommodationResponse, PackagingEntry, PackagingEntryLine } from '@qite/tide-client';
2
+ import { ACCOMMODATION_SERVICE_TYPE } from './query-utils';
3
+
4
+ export const getSelectedOptionsPerRoom = (details: PackagingAccommodationResponse[]) => {
5
+ const firstResult = details[0];
6
+ if (!firstResult?.rooms?.length) return [];
7
+
8
+ return firstResult.rooms.map((room, roomIndex) => {
9
+ const selectedOption = room.options.find((option) => option.isSelected) ?? room.options[0];
10
+
11
+ return {
12
+ roomIndex,
13
+ option: selectedOption ?? null
14
+ };
15
+ });
16
+ };
17
+
18
+ export const getRoomIndexFromLine = (line: PackagingEntryLine): number => {
19
+ if (!line.pax?.length) return 0;
20
+
21
+ const firstPax = [...line.pax].sort((a, b) => a.order - b.order)[0];
22
+ return firstPax?.room ?? 0;
23
+ };
24
+
25
+ export const getRequestRoomsFromPackagingSegments = (entry: PackagingEntry, segments: PackagingEntryLine[]): BookingPackageRequestRoom[] => {
26
+ const accommodationLines = [...(segments ?? [])]
27
+ .filter((line) => line.serviceType === ACCOMMODATION_SERVICE_TYPE && line.pax?.length > 0)
28
+ .sort((a, b) => a.order - b.order);
29
+
30
+ const paxById = new Map((entry.pax ?? []).map((p) => [p.id, p]));
31
+
32
+ if (!accommodationLines.length) {
33
+ return [];
34
+ }
35
+
36
+ const roomGroups: BookingPackagePax[][] = [];
37
+
38
+ accommodationLines.forEach((line) => {
39
+ const groupedByRoom = new Map<number, BookingPackagePax[]>();
40
+
41
+ line.pax.forEach((linePax) => {
42
+ const roomIndexWithinLine = Number(linePax.room ?? 0);
43
+ const paxId = Number(linePax.paxId);
44
+ const paxSource = paxById.get(paxId);
45
+
46
+ const pax: BookingPackagePax = {
47
+ id: paxSource?.id ?? paxId,
48
+ guid: paxSource?.id?.toString() ?? paxId.toString(),
49
+ firstName: paxSource?.firstName ?? '',
50
+ lastName: paxSource?.lastName ?? '',
51
+ dateOfBirth: paxSource?.dateOfBirth ?? undefined,
52
+ age: paxSource?.dateOfBirth ? undefined : 30,
53
+ isMainBooker: paxSource?.isMainBooker,
54
+ email: ''
55
+ };
56
+
57
+ if (!groupedByRoom.has(roomIndexWithinLine)) {
58
+ groupedByRoom.set(roomIndexWithinLine, []);
59
+ }
60
+
61
+ groupedByRoom.get(roomIndexWithinLine)!.push(pax);
62
+ });
63
+
64
+ const sortedGroups = Array.from(groupedByRoom.entries())
65
+ .sort(([a], [b]) => a - b)
66
+ .map(([, pax]) => pax);
67
+
68
+ roomGroups.push(...sortedGroups);
69
+ });
70
+
71
+ return roomGroups.map((pax, index) => ({
72
+ index,
73
+ pax
74
+ }));
75
+ };
@@ -0,0 +1,152 @@
1
+ import {
2
+ PackagingEntryLine,
3
+ PackagingEntryPax,
4
+ BookingPackagePax,
5
+ PackagingEntry,
6
+ BookingPackageRequestRoom,
7
+ PackagingRoom,
8
+ PackagingTraveller
9
+ } from '@qite/tide-client';
10
+ import { range } from 'lodash';
11
+
12
+ export const GROUP_TOUR_SERVICE_TYPE = 1;
13
+ export const ACCOMMODATION_SERVICE_TYPE = 3;
14
+ export const FLIGHT_SERVICE_TYPE = 7;
15
+
16
+ export const toDateOnlyString = (value: string | Date): string => {
17
+ const date = value instanceof Date ? value : new Date(value);
18
+ return date.toISOString().split('T')[0];
19
+ };
20
+
21
+ const getAgeAtReferenceDate = (dateOfBirth: string | Date, referenceDate: string | Date): number => {
22
+ const dob = dateOfBirth instanceof Date ? dateOfBirth : new Date(dateOfBirth);
23
+ const ref = referenceDate instanceof Date ? referenceDate : new Date(referenceDate);
24
+
25
+ let age = ref.getFullYear() - dob.getFullYear();
26
+ const monthDiff = ref.getMonth() - dob.getMonth();
27
+
28
+ if (monthDiff < 0 || (monthDiff === 0 && ref.getDate() < dob.getDate())) {
29
+ age--;
30
+ }
31
+
32
+ return age;
33
+ };
34
+
35
+ export const getPrimaryAccommodationLine = (lines: PackagingEntryLine[]): PackagingEntryLine | undefined => {
36
+ return [...lines]
37
+ .filter((line) => line.serviceType === ACCOMMODATION_SERVICE_TYPE)
38
+ .sort((a, b) => new Date(a.from).getTime() - new Date(b.from).getTime())[0];
39
+ };
40
+
41
+ const getFlightLines = (lines: PackagingEntryLine[]): PackagingEntryLine[] => {
42
+ return [...lines].filter((line) => line.serviceType === FLIGHT_SERVICE_TYPE).sort((a, b) => new Date(a.from).getTime() - new Date(b.from).getTime());
43
+ };
44
+
45
+ export const getDepartureAirportFromEntry = (lines: PackagingEntryLine[]): string | null => {
46
+ const firstFlight = getFlightLines(lines)[0];
47
+ const firstSegment = firstFlight?.flightInformation?.flightLines?.[0];
48
+ return firstSegment?.departureAirportCode ?? null;
49
+ };
50
+
51
+ export const getDestinationAirportFromEntry = (lines: PackagingEntryLine[]): string | null => {
52
+ const outboundFlight = getFlightLines(lines)[0];
53
+ const flightSegments = outboundFlight?.flightInformation?.flightLines;
54
+
55
+ if (!flightSegments?.length) return null;
56
+
57
+ return flightSegments[flightSegments.length - 1]?.arrivalAirportCode ?? null;
58
+ };
59
+
60
+ const mapPackagingPaxToBookingPax = (pax: PackagingEntryPax | undefined, fallbackId: number, referenceDate: string): BookingPackagePax => ({
61
+ id: pax?.id ?? fallbackId,
62
+ guid: pax?.id?.toString() ?? fallbackId.toString(),
63
+ firstName: pax?.firstName ?? '',
64
+ lastName: pax?.lastName ?? '',
65
+ dateOfBirth: pax?.dateOfBirth ?? undefined,
66
+ age: pax?.dateOfBirth ? getAgeAtReferenceDate(pax.dateOfBirth, referenceDate) : undefined,
67
+ isMainBooker: pax?.isMainBooker,
68
+ email: ''
69
+ });
70
+
71
+ export const getRequestRoomsFromPackagingEntry = (entry: PackagingEntry): BookingPackageRequestRoom[] => {
72
+ const accommodationLines = (entry.lines ?? []).filter((line) => line.serviceType === ACCOMMODATION_SERVICE_TYPE && line.pax?.length > 0);
73
+
74
+ const paxById = new Map((entry.pax ?? []).map((p) => [p.id, p]));
75
+
76
+ if (!accommodationLines.length) {
77
+ return [
78
+ {
79
+ index: 0,
80
+ pax: (entry.pax ?? []).map((p) => mapPackagingPaxToBookingPax(p, p.id, new Date().toISOString()))
81
+ }
82
+ ];
83
+ }
84
+
85
+ const roomGroups: BookingPackagePax[][] = [];
86
+
87
+ accommodationLines.forEach((line) => {
88
+ const groupedByRoom = new Map<number, BookingPackagePax[]>();
89
+
90
+ line.pax.forEach((linePax) => {
91
+ const roomIndexWithinLine = Number(linePax.room ?? 0);
92
+ const paxId = Number(linePax.paxId);
93
+ const pax = mapPackagingPaxToBookingPax(paxById.get(paxId), paxId, line.from);
94
+
95
+ if (!groupedByRoom.has(roomIndexWithinLine)) {
96
+ groupedByRoom.set(roomIndexWithinLine, []);
97
+ }
98
+
99
+ groupedByRoom.get(roomIndexWithinLine)!.push(pax);
100
+ });
101
+
102
+ const sortedGroups = Array.from(groupedByRoom.entries())
103
+ .sort(([a], [b]) => a - b)
104
+ .map(([, pax]) => pax);
105
+
106
+ roomGroups.push(...sortedGroups);
107
+ });
108
+
109
+ if (!roomGroups.length) {
110
+ return [
111
+ {
112
+ index: 0,
113
+ pax: (entry.pax ?? []).map((p) => mapPackagingPaxToBookingPax(p, p.id, accommodationLines[0].from))
114
+ }
115
+ ];
116
+ }
117
+
118
+ return roomGroups.map((pax, index) => ({
119
+ index,
120
+ pax
121
+ }));
122
+ };
123
+
124
+ export const parseHotelId = (line?: PackagingEntryLine): number | null => {
125
+ if (!line?.productCode) return null;
126
+ const parsed = Number(line.productCode);
127
+ return Number.isNaN(parsed) ? null : parsed;
128
+ };
129
+
130
+ export const getPackagingRequestRoomsFromBookingRooms = (rooms: BookingPackageRequestRoom[] | null) => {
131
+ if (!rooms?.length) {
132
+ const room = { index: 0, travellers: [] } as PackagingRoom;
133
+ range(0, 2).forEach(() => {
134
+ room.travellers.push({
135
+ age: 30
136
+ } as PackagingTraveller);
137
+ });
138
+ return [room];
139
+ }
140
+
141
+ return rooms.map((x, i) => {
142
+ const room = { index: x.index ?? i, travellers: [] } as PackagingRoom;
143
+
144
+ x.pax.forEach((p) => {
145
+ room.travellers.push({
146
+ age: p.age ?? 30
147
+ } as PackagingTraveller);
148
+ });
149
+
150
+ return room;
151
+ });
152
+ };
@@ -5,14 +5,14 @@ import { SearchResultsRootState } from '../../../search-results/store/search-res
5
5
  import SearchResultsConfigurationContext from '../../../search-results/search-results-configuration-context';
6
6
  import { getTranslations } from '../../utils/localization-util';
7
7
  import { setPackagingAccoSearchDetails } from '../../../search-results/store/search-results-slice';
8
- import { PackageMainRoom } from '@qite/tide-client';
8
+ import { PackageMainRoom, PortalQsmType } from '@qite/tide-client';
9
9
  import { PickerItem } from '../../types';
10
10
  import { first } from 'lodash';
11
+ import Spinner from '../../../search-results/components/spinner/spinner';
11
12
 
12
13
  type AccommodationFlyInProps = {
13
14
  isLoading: boolean;
14
- isOpen: boolean;
15
- setIsOpen: (open: boolean) => void;
15
+ handleConfirm: () => void;
16
16
  };
17
17
 
18
18
  type PackagingAccommodationResponse = {
@@ -38,9 +38,14 @@ const formatPrice = (price?: number, currencyCode = 'EUR') => {
38
38
  }).format(price);
39
39
  };
40
40
 
41
- const AccommodationFlyIn: React.FC<AccommodationFlyInProps> = ({ isLoading, isOpen, setIsOpen }) => {
41
+ const AccommodationFlyIn: React.FC<AccommodationFlyInProps> = ({ isLoading, handleConfirm }) => {
42
42
  const dispatch = useDispatch();
43
43
  const context = useContext(SearchResultsConfigurationContext);
44
+
45
+ if (isLoading) {
46
+ return <>{context?.customSpinner ?? <Spinner />}</>;
47
+ }
48
+
44
49
  const language = context?.languageCode ?? 'en-GB';
45
50
  const translations = getTranslations(language);
46
51
 
@@ -118,12 +123,6 @@ const AccommodationFlyIn: React.FC<AccommodationFlyInProps> = ({ isLoading, isOp
118
123
  dispatch(setPackagingAccoSearchDetails(updatedPackagingAccoSearchDetails));
119
124
  };
120
125
 
121
- const handleConfirm = () => {
122
- if (isOpen) {
123
- setIsOpen(false);
124
- }
125
- };
126
-
127
126
  if (!selectedPackagingAccoSearchDetails) {
128
127
  return null;
129
128
  }
@@ -248,7 +247,7 @@ const AccommodationFlyIn: React.FC<AccommodationFlyInProps> = ({ isLoading, isOp
248
247
 
249
248
  <div className="flyin__button-wrapper">
250
249
  <button className="cta cta--select" onClick={handleConfirm}>
251
- {translations.PRODUCT.BOOK_NOW}
250
+ {context?.searchConfiguration.qsmType == PortalQsmType.AccommodationAndFlight ? translations.QSM.CONFIRM : translations.PRODUCT.BOOK_NOW}
252
251
  </button>
253
252
  </div>
254
253
  </div>
@@ -2,11 +2,19 @@ import React, { useEffect, useRef } from 'react';
2
2
  import Icon from '../icon';
3
3
  import { useFlightSearch } from '../../../search-results/components/flight/flight-search-context';
4
4
  import { useDispatch } from 'react-redux';
5
- import { setSelectedFlight, setSelectedFlightDetails } from '../../../search-results/store/search-results-slice';
5
+ import {
6
+ setAccommodationFlyInStep,
7
+ setSelectedFlight,
8
+ setSelectedFlightDetails,
9
+ setSelectedPackagingAccoResult,
10
+ setSelectedSearchResult
11
+ } from '../../../search-results/store/search-results-slice';
6
12
  import FlightsFlyIn from './flights-flyin';
7
13
  import AccommodationFlyIn from './accommodation-flyin';
8
14
  import { PortalQsmType } from '@qite/tide-client';
9
15
  import GroupTourFlyIn from './group-tour-flyin';
16
+ import { AccommodationFlyInStep } from '../../../search-results/types';
17
+ import HotelAccommodationResults from '../../../search-results/components/hotel/hotel-accommodation-results';
10
18
 
11
19
  type FlyInProps = {
12
20
  title: string;
@@ -16,9 +24,23 @@ type FlyInProps = {
16
24
  className?: string;
17
25
  onPanelRef?: (el: HTMLDivElement | null) => void;
18
26
  detailsLoading: boolean;
27
+ handleConfirm?: () => void;
28
+ accommodationStep?: AccommodationFlyInStep;
29
+ isPackageEditFlow?: boolean;
19
30
  };
20
31
 
21
- const FlyIn: React.FC<FlyInProps> = ({ title, srpType, isOpen, setIsOpen, className = '', onPanelRef, detailsLoading }) => {
32
+ const FlyIn: React.FC<FlyInProps> = ({
33
+ title,
34
+ srpType,
35
+ isOpen,
36
+ setIsOpen,
37
+ className = '',
38
+ onPanelRef,
39
+ detailsLoading,
40
+ accommodationStep,
41
+ isPackageEditFlow,
42
+ handleConfirm
43
+ }) => {
22
44
  const dispatch = useDispatch();
23
45
  const { onCancelSearch } = useFlightSearch();
24
46
  const panelRef = useRef<HTMLDivElement>(null);
@@ -55,13 +77,21 @@ const FlyIn: React.FC<FlyInProps> = ({ title, srpType, isOpen, setIsOpen, classN
55
77
  dispatch(setSelectedFlight(null));
56
78
  dispatch(setSelectedFlightDetails(null));
57
79
  onCancelSearch();
80
+ } else {
81
+ dispatch(setSelectedSearchResult(null));
82
+ dispatch(setSelectedPackagingAccoResult(null));
58
83
  }
84
+ dispatch(setAccommodationFlyInStep('details'));
59
85
  setIsOpen(false);
60
86
  }
61
87
  };
62
88
 
89
+ const handleGoBack = () => {
90
+ dispatch(setAccommodationFlyInStep('results'));
91
+ };
92
+
63
93
  return (
64
- <div className={`flyin ${isOpen ? 'flyin--active' : ''} ${className}`}>
94
+ <div className={`flyin ${isOpen ? 'flyin--active' : ''} ${className} ${isPackageEditFlow ? 'flyin--large' : ''}`}>
65
95
  <div className={`flyin__panel ${isOpen ? 'flyin__panel--active' : ''}`} ref={panelRef}>
66
96
  <div className="flyin__content">
67
97
  <div className="flyin__content-title-row">
@@ -70,9 +100,27 @@ const FlyIn: React.FC<FlyInProps> = ({ title, srpType, isOpen, setIsOpen, classN
70
100
  <Icon name="ui-close" width={30} height={30} aria-hidden="true" />
71
101
  </span>
72
102
  </div>
103
+ {isPackageEditFlow && accommodationStep === 'details' && (
104
+ <div className="flyin__content-title-row">
105
+ <div onClick={handleGoBack} className="flyin__content-title__back">
106
+ <Icon name="ui-chevron" width={14} height={14} aria-hidden="true" />
107
+ Go Back
108
+ </div>
109
+ </div>
110
+ )}
73
111
  </div>
74
112
  {srpType === PortalQsmType.Flight && <FlightsFlyIn isOpen={isOpen} setIsOpen={setIsOpen} />}
75
- {srpType === PortalQsmType.Accommodation && <AccommodationFlyIn isLoading={true} isOpen={isOpen} setIsOpen={setIsOpen} />}
113
+
114
+ {(srpType === PortalQsmType.Accommodation || srpType === PortalQsmType.AccommodationAndFlight) && accommodationStep === 'results' && (
115
+ <div className="flyin__content">
116
+ <HotelAccommodationResults isLoading={detailsLoading} />
117
+ </div>
118
+ )}
119
+
120
+ {(srpType === PortalQsmType.Accommodation || srpType === PortalQsmType.AccommodationAndFlight) && accommodationStep === 'details' && (
121
+ <AccommodationFlyIn isLoading={detailsLoading} handleConfirm={handleConfirm!} />
122
+ )}
123
+
76
124
  {srpType === PortalQsmType.GroupTour && <GroupTourFlyIn isLoading={detailsLoading} isOpen={isOpen} setIsOpen={setIsOpen} />}
77
125
  </div>
78
126
  </div>
@@ -19,6 +19,20 @@
19
19
  pointer-events: auto;
20
20
  }
21
21
 
22
+ &--large {
23
+ .flyin__panel {
24
+ @include mixins.media-sm {
25
+ width: 80%;
26
+ }
27
+ }
28
+
29
+ .flyin__acco__cards {
30
+ @include mixins.media-lg {
31
+ grid-template-columns: repeat(3, 1fr);
32
+ }
33
+ }
34
+ }
35
+
22
36
  &__panel {
23
37
  background: var(--tide-booking-gray-xlight);
24
38
  height: 100%;
@@ -89,6 +103,17 @@
89
103
  align-items: center;
90
104
  padding-bottom: 15px;
91
105
  }
106
+
107
+ &__back {
108
+ display: flex;
109
+ align-items: center;
110
+ gap: 3px;
111
+ cursor: pointer;
112
+
113
+ svg {
114
+ transform: rotate(180deg);
115
+ }
116
+ }
92
117
  }
93
118
 
94
119
  &-arrow {
@@ -370,6 +370,7 @@
370
370
  display: flex;
371
371
  flex-direction: column;
372
372
  align-items: center;
373
+
373
374
  p {
374
375
  margin: 0px;
375
376
  line-height: 1.5;
@@ -493,6 +494,8 @@
493
494
  }
494
495
 
495
496
  &-date {
497
+ min-width: 26px;
498
+
496
499
  p {
497
500
  margin: 0px;
498
501
  color: var(--tide-booking-search-itinerary-filter-transport-date-month-color);
@@ -626,6 +629,14 @@
626
629
  &--start {
627
630
  align-items: flex-start;
628
631
  }
632
+
633
+ &--editable {
634
+ cursor: pointer;
635
+
636
+ &:hover {
637
+ background-color: rgba(0, 0, 0, 0.05);
638
+ }
639
+ }
629
640
  }
630
641
 
631
642
  &-badge {
@@ -670,6 +681,7 @@
670
681
  display: flex;
671
682
  align-items: center;
672
683
  flex-flow: row nowrap;
684
+ min-width: 26px;
673
685
  max-width: 26px;
674
686
 
675
687
  svg {
@@ -690,11 +702,18 @@
690
702
  color: var(--tide-booking-search-itinerary-filter-segment-title-color);
691
703
  }
692
704
 
693
- p {
705
+ &__room {
706
+ display: flex;
707
+ align-items: center;
708
+ gap: 5px;
694
709
  margin: 0px;
695
710
  line-height: 1.2;
696
711
  font-weight: var(--tide-booking-search-itinerary-filter-segment-text-font-weight);
697
712
  color: var(--tide-booking-search-itinerary-filter-segment-text-color);
713
+
714
+ svg {
715
+ flex: 12px 0 0;
716
+ }
698
717
  }
699
718
 
700
719
  .rating {
@@ -1001,6 +1020,7 @@
1001
1020
 
1002
1021
  &--custom {
1003
1022
  gap: 20px;
1023
+
1004
1024
  .search__result-card__footer {
1005
1025
  padding: 20px;
1006
1026
  padding-top: 0px;
@@ -1667,6 +1687,7 @@
1667
1687
 
1668
1688
  &__allotment {
1669
1689
  padding: 0px;
1690
+
1670
1691
  @include mixins.media-sm {
1671
1692
  flex-direction: column;
1672
1693
  }
@@ -1689,9 +1710,11 @@
1689
1710
  @include mixins.media-md {
1690
1711
  padding: 20px 0px;
1691
1712
  }
1713
+
1692
1714
  @include mixins.media-lg {
1693
1715
  padding: 0px 20px;
1694
1716
  }
1717
+
1695
1718
  @include mixins.media-xl {
1696
1719
  padding: 20px 0px;
1697
1720
  }
@@ -1700,6 +1723,7 @@
1700
1723
  &__footer {
1701
1724
  padding: 0px 20px;
1702
1725
  padding-bottom: 20px;
1726
+
1703
1727
  @include mixins.media-sm {
1704
1728
  flex-direction: row;
1705
1729
  align-items: flex-start;
@@ -1732,12 +1756,15 @@
1732
1756
  @include mixins.media-sm {
1733
1757
  align-items: flex-start;
1734
1758
  }
1759
+
1735
1760
  @include mixins.media-md {
1736
1761
  align-items: flex-end;
1737
1762
  }
1763
+
1738
1764
  @include mixins.media-lg {
1739
1765
  align-items: flex-start;
1740
1766
  }
1767
+
1741
1768
  @include mixins.media-xl {
1742
1769
  align-items: flex-end;
1743
1770
  }