@qite/tide-booking-component 1.4.103 → 1.4.105

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 (70) hide show
  1. package/build/build-cjs/index.js +2782 -1052
  2. package/build/build-cjs/src/search-results/components/excursions/day-by-day-excursions.d.ts +4 -0
  3. package/build/build-cjs/src/search-results/components/excursions/excursion-details.d.ts +3 -0
  4. package/build/build-cjs/src/search-results/components/excursions/excursion-results.d.ts +8 -0
  5. package/build/build-cjs/src/search-results/components/filters/filters.d.ts +2 -0
  6. package/build/build-cjs/src/search-results/components/hotel/hotel-accommodation-results.d.ts +1 -0
  7. package/build/build-cjs/src/search-results/store/search-results-selectors.d.ts +546 -0
  8. package/build/build-cjs/src/search-results/store/search-results-slice.d.ts +55 -8
  9. package/build/build-cjs/src/search-results/types.d.ts +40 -2
  10. package/build/build-cjs/src/search-results/utils/query-utils.d.ts +1 -0
  11. package/build/build-cjs/src/search-results/utils/search-results-utils.d.ts +8 -6
  12. package/build/build-cjs/src/shared/components/flyin/flyin.d.ts +4 -3
  13. package/build/build-cjs/src/shared/components/flyin/packaging-flights-flyin.d.ts +7 -0
  14. package/build/build-cjs/src/shared/utils/localization-util.d.ts +3 -0
  15. package/build/build-cjs/src/shared/utils/tide-api-utils.d.ts +6 -0
  16. package/build/build-esm/index.js +2735 -1023
  17. package/build/build-esm/src/search-results/components/excursions/day-by-day-excursions.d.ts +4 -0
  18. package/build/build-esm/src/search-results/components/excursions/excursion-details.d.ts +3 -0
  19. package/build/build-esm/src/search-results/components/excursions/excursion-results.d.ts +8 -0
  20. package/build/build-esm/src/search-results/components/filters/filters.d.ts +2 -0
  21. package/build/build-esm/src/search-results/components/hotel/hotel-accommodation-results.d.ts +1 -0
  22. package/build/build-esm/src/search-results/store/search-results-selectors.d.ts +546 -0
  23. package/build/build-esm/src/search-results/store/search-results-slice.d.ts +55 -8
  24. package/build/build-esm/src/search-results/types.d.ts +40 -2
  25. package/build/build-esm/src/search-results/utils/query-utils.d.ts +1 -0
  26. package/build/build-esm/src/search-results/utils/search-results-utils.d.ts +8 -6
  27. package/build/build-esm/src/shared/components/flyin/flyin.d.ts +4 -3
  28. package/build/build-esm/src/shared/components/flyin/packaging-flights-flyin.d.ts +7 -0
  29. package/build/build-esm/src/shared/utils/localization-util.d.ts +3 -0
  30. package/build/build-esm/src/shared/utils/tide-api-utils.d.ts +6 -0
  31. package/package.json +2 -2
  32. package/src/booking-wizard/features/flight-options/index.tsx +6 -2
  33. package/src/search-results/components/excursions/day-by-day-excursions.tsx +169 -0
  34. package/src/search-results/components/excursions/excursion-details.tsx +340 -0
  35. package/src/search-results/components/excursions/excursion-results.tsx +186 -0
  36. package/src/search-results/components/filters/filters.tsx +8 -9
  37. package/src/search-results/components/hotel/hotel-accommodation-results.tsx +81 -24
  38. package/src/search-results/components/hotel/hotel-card.tsx +0 -3
  39. package/src/search-results/components/icon.tsx +1 -4
  40. package/src/search-results/components/search-results-container/search-results-container.tsx +208 -130
  41. package/src/search-results/store/search-results-selectors.ts +84 -0
  42. package/src/search-results/store/search-results-slice.ts +138 -15
  43. package/src/search-results/types.ts +55 -2
  44. package/src/search-results/utils/query-utils.ts +1 -0
  45. package/src/search-results/utils/search-results-utils.ts +310 -58
  46. package/src/shared/components/flyin/accommodation-flyin.tsx +4 -2
  47. package/src/shared/components/flyin/flights-flyin.tsx +3 -1
  48. package/src/shared/components/flyin/flyin.tsx +116 -21
  49. package/src/shared/components/flyin/group-tour-flyin.tsx +3 -1
  50. package/src/shared/components/flyin/packaging-flights-flyin.tsx +164 -0
  51. package/src/shared/translations/ar-SA.json +4 -2
  52. package/src/shared/translations/da-DK.json +4 -2
  53. package/src/shared/translations/de-DE.json +4 -2
  54. package/src/shared/translations/en-GB.json +4 -2
  55. package/src/shared/translations/es-ES.json +4 -2
  56. package/src/shared/translations/fr-BE.json +4 -2
  57. package/src/shared/translations/fr-FR.json +4 -2
  58. package/src/shared/translations/is-IS.json +4 -2
  59. package/src/shared/translations/it-IT.json +4 -2
  60. package/src/shared/translations/ja-JP.json +4 -2
  61. package/src/shared/translations/nl-BE.json +4 -2
  62. package/src/shared/translations/nl-NL.json +4 -2
  63. package/src/shared/translations/no-NO.json +4 -2
  64. package/src/shared/translations/pl-PL.json +4 -2
  65. package/src/shared/translations/pt-PT.json +4 -2
  66. package/src/shared/translations/sv-SE.json +4 -2
  67. package/src/shared/utils/localization-util.ts +14 -0
  68. package/src/shared/utils/tide-api-utils.ts +8 -0
  69. package/styles/components/_flyin.scss +16 -0
  70. package/styles/components/_search.scss +15 -2
@@ -0,0 +1,84 @@
1
+ import { createSelector } from '@reduxjs/toolkit';
2
+ import { SearchResultsRootState } from './search-results-store';
3
+ import { getFlightKey } from '../utils/flight-utils';
4
+ import { PackagingFlightResponse } from '@qite/tide-client';
5
+
6
+ const selectSearchResultsState = (state: SearchResultsRootState) => state.searchResults;
7
+
8
+ export const selectPackagingAccoResults = createSelector([selectSearchResultsState], (state) => state.packagingAccoResults);
9
+ export const selectSelectedPackagingAccoResultCode = createSelector([selectSearchResultsState], (state) => state.selectedPackagingAccoResultCode);
10
+ export const selectSelectedPackagingAccoResult = createSelector(
11
+ [selectPackagingAccoResults, selectSelectedPackagingAccoResultCode],
12
+ (packagingAccoResults, selectedPackagingAccoResultCode) => {
13
+ if (!selectedPackagingAccoResultCode) return null;
14
+
15
+ return packagingAccoResults.find((accoResult) => accoResult.code === selectedPackagingAccoResultCode) ?? null;
16
+ }
17
+ );
18
+
19
+ export const selectPackagingFlightResults = createSelector([selectSearchResultsState], (state) => state.packagingFlightResults);
20
+ export const selectFilteredPackagingFlightResults = createSelector([selectSearchResultsState], (state) => state.filteredPackagingFlightResults);
21
+
22
+ export const selectSelectedOutwardKey = createSelector([selectSearchResultsState], (state) => state.selectedOutwardKey);
23
+
24
+ export const selectSelectedReturnKey = createSelector([selectSearchResultsState], (state) => state.selectedReturnKey);
25
+
26
+ export const selectUniqueOutwardFlights = createSelector([selectFilteredPackagingFlightResults], (packagingFlightResults): PackagingFlightResponse[] => {
27
+ const map = new Map<string, PackagingFlightResponse>();
28
+
29
+ packagingFlightResults.forEach((flight) => {
30
+ const key = getFlightKey(flight.outward.segments);
31
+
32
+ if (!map.has(key)) {
33
+ map.set(key, flight);
34
+ }
35
+ });
36
+
37
+ return Array.from(map.values());
38
+ });
39
+
40
+ export const selectUniqueReturnFlights = createSelector(
41
+ [selectFilteredPackagingFlightResults, selectSelectedOutwardKey],
42
+ (packagingFlightResults, selectedOutwardKey): PackagingFlightResponse[] => {
43
+ if (!selectedOutwardKey) return [];
44
+
45
+ const matchingCombinations = packagingFlightResults.filter((flight) => getFlightKey(flight.outward.segments) === selectedOutwardKey);
46
+
47
+ const map = new Map<string, PackagingFlightResponse>();
48
+
49
+ matchingCombinations.forEach((flight) => {
50
+ const key = getFlightKey(flight.return.segments);
51
+
52
+ if (!map.has(key)) {
53
+ map.set(key, flight);
54
+ }
55
+ });
56
+
57
+ return Array.from(map.values());
58
+ }
59
+ );
60
+
61
+ export const selectSelectedOutward = createSelector([selectPackagingFlightResults, selectSelectedOutwardKey], (packagingFlightResults, selectedOutwardKey) => {
62
+ if (!selectedOutwardKey) return null;
63
+
64
+ return packagingFlightResults.find((flight) => getFlightKey(flight.outward.segments) === selectedOutwardKey) ?? null;
65
+ });
66
+
67
+ export const selectSelectedReturn = createSelector([selectPackagingFlightResults, selectSelectedReturnKey], (packagingFlightResults, selectedReturnKey) => {
68
+ if (!selectedReturnKey) return null;
69
+
70
+ return packagingFlightResults.find((flight) => getFlightKey(flight.return.segments) === selectedReturnKey) ?? null;
71
+ });
72
+
73
+ export const selectSelectedCombinationFlight = createSelector(
74
+ [selectPackagingFlightResults, selectSelectedOutwardKey, selectSelectedReturnKey],
75
+ (packagingFlightResults, selectedOutwardKey, selectedReturnKey) => {
76
+ if (!selectedOutwardKey || !selectedReturnKey) return null;
77
+
78
+ return (
79
+ packagingFlightResults.find(
80
+ (flight) => getFlightKey(flight.outward.segments) === selectedOutwardKey && getFlightKey(flight.return.segments) === selectedReturnKey
81
+ ) ?? null
82
+ );
83
+ }
84
+ );
@@ -1,5 +1,5 @@
1
1
  import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2
- import { AccommodationFlyInStep, ExtendedFlightSearchResponseItem, Filter, SortByType } from '../types';
2
+ import { ExcursionSearchParams, ExtendedFlightSearchResponseItem, Filter, FlyInType, SortByType } from '../types';
3
3
  import {
4
4
  BookingPackage,
5
5
  BookingPackageItem,
@@ -14,54 +14,96 @@ export interface SearchResultsState {
14
14
  results: BookingPackageItem[];
15
15
  filteredResults: BookingPackageItem[];
16
16
  selectedSearchResult: BookingPackageItem | null;
17
+
17
18
  packagingAccoResults: PackagingAccommodationResponse[];
18
19
  filteredPackagingAccoResults: PackagingAccommodationResponse[];
19
20
  packagingAccoSearchDetails: PackagingAccommodationResponse[];
20
21
  selectedPackagingAccoResultCode: string | null;
22
+
21
23
  packagingFlightResults: PackagingFlightResponse[];
24
+ filteredPackagingFlightResults: PackagingFlightResponse[];
22
25
  selectedPackagingFlight: PackagingFlightResponse | null;
26
+ selectedOutwardKey: string | null;
27
+ selectedReturnKey: string | null;
28
+
23
29
  selectedFlight: ExtendedFlightSearchResponseItem | null;
24
30
  selectedFlightDetails: ExtendedFlightSearchResponseItem | null;
31
+
25
32
  bookingPackageDetails: BookingPackage | null;
33
+ priceDetails: BookingPriceDetails | null;
34
+
26
35
  isLoading: boolean;
27
36
  flightsLoading: boolean;
28
- filters: Filter[];
37
+
29
38
  selectedSortType: SortByType | null;
39
+ selectedFlightSortType: SortByType | null;
40
+ filters: Filter[];
41
+ initialFilters: Filter[];
42
+ flightFilters: Filter[];
43
+ initialFlightFilters: Filter[];
44
+
30
45
  activeTab: string | null;
31
46
  currentPage: number;
32
- flyInIsOpen: boolean;
33
- editablePackagingEntry: PackagingEntry | null;
47
+
34
48
  transactionId: string | null;
35
- accommodationFlyInStep: AccommodationFlyInStep;
36
- priceDetails: BookingPriceDetails | null;
49
+
50
+ flyInIsOpen: boolean;
51
+ flyInType: FlyInType | null;
52
+
37
53
  itinerary: ClientPortalItinerary | null;
54
+ editablePackagingEntry: PackagingEntry | null;
55
+
56
+ excursionSearchParams: ExcursionSearchParams | null;
57
+ selectedExcursionSearchResult: PackagingAccommodationResponse | null;
58
+ confirmedExcursionsByDay: Record<string, PackagingAccommodationResponse[]>;
38
59
  }
39
60
 
40
61
  const initialState: SearchResultsState = {
41
62
  results: [],
42
63
  filteredResults: [],
43
64
  selectedSearchResult: null,
65
+
44
66
  packagingAccoResults: [],
45
67
  filteredPackagingAccoResults: [],
46
68
  packagingAccoSearchDetails: [],
47
69
  selectedPackagingAccoResultCode: null,
70
+
48
71
  packagingFlightResults: [],
72
+ filteredPackagingFlightResults: [],
49
73
  selectedPackagingFlight: null,
74
+ selectedOutwardKey: null,
75
+ selectedReturnKey: null,
76
+
50
77
  selectedFlight: null,
51
78
  selectedFlightDetails: null,
79
+
52
80
  bookingPackageDetails: null,
81
+ priceDetails: null,
82
+
53
83
  isLoading: false,
54
84
  flightsLoading: false,
55
- filters: [],
85
+
56
86
  selectedSortType: null,
87
+ selectedFlightSortType: null,
88
+ initialFilters: [],
89
+ filters: [],
90
+ initialFlightFilters: [],
91
+ flightFilters: [],
92
+
57
93
  activeTab: 'compact',
58
94
  currentPage: 1,
95
+
96
+ transactionId: null,
97
+
59
98
  flyInIsOpen: false,
99
+ flyInType: null,
100
+
60
101
  editablePackagingEntry: null,
61
- transactionId: null,
62
- accommodationFlyInStep: 'details',
63
- priceDetails: null,
64
- itinerary: null
102
+ itinerary: null,
103
+
104
+ excursionSearchParams: null,
105
+ selectedExcursionSearchResult: null,
106
+ confirmedExcursionsByDay: {}
65
107
  };
66
108
 
67
109
  const searchResultsSlice = createSlice({
@@ -92,6 +134,9 @@ const searchResultsSlice = createSlice({
92
134
  setPackagingFlightResults(state, action: PayloadAction<PackagingFlightResponse[]>) {
93
135
  state.packagingFlightResults = action.payload;
94
136
  },
137
+ setFilteredPackagingFlightResults(state, action: PayloadAction<PackagingFlightResponse[]>) {
138
+ state.filteredPackagingFlightResults = action.payload;
139
+ },
95
140
  setSelectedPackagingFlight(state, action: PayloadAction<PackagingFlightResponse | null>) {
96
141
  state.selectedPackagingFlight = action.payload;
97
142
  },
@@ -122,6 +167,9 @@ const searchResultsSlice = createSlice({
122
167
  setFlightsLoading(state, action: PayloadAction<boolean>) {
123
168
  state.flightsLoading = action.payload;
124
169
  },
170
+ setInitialFilters(state, action: PayloadAction<Filter[]>) {
171
+ state.initialFilters = action.payload;
172
+ },
125
173
  setFilters(state, action: PayloadAction<Filter[]>) {
126
174
  const updatedFilters = action.payload;
127
175
 
@@ -137,9 +185,30 @@ const searchResultsSlice = createSlice({
137
185
  resetFilters(state, action: PayloadAction<Filter[]>) {
138
186
  state.filters = action.payload;
139
187
  },
188
+ setInitialFlightFilters(state, action: PayloadAction<Filter[]>) {
189
+ state.initialFlightFilters = action.payload;
190
+ },
191
+ setFlightFilters(state, action: PayloadAction<Filter[]>) {
192
+ const updatedFilters = action.payload;
193
+
194
+ updatedFilters.forEach((updatedFilter) => {
195
+ const existingIndex = state.flightFilters.findIndex((f) => f.property === updatedFilter.property);
196
+ if (existingIndex !== -1) {
197
+ state.flightFilters[existingIndex] = updatedFilter;
198
+ } else {
199
+ state.flightFilters.push(updatedFilter); // Optional: Add new filters if not present
200
+ }
201
+ });
202
+ },
203
+ resetFlightFilters(state, action: PayloadAction<Filter[]>) {
204
+ state.flightFilters = action.payload;
205
+ },
140
206
  setSortType(state, action: PayloadAction<SortByType | null>) {
141
207
  state.selectedSortType = action.payload;
142
208
  },
209
+ setFlightSortType(state, action: PayloadAction<SortByType | null>) {
210
+ state.selectedFlightSortType = action.payload;
211
+ },
143
212
  setActiveTab(state, action: PayloadAction<string | null>) {
144
213
  state.activeTab = action.payload;
145
214
  },
@@ -163,14 +232,54 @@ const searchResultsSlice = createSlice({
163
232
  setTransactionId(state, action: PayloadAction<string | null>) {
164
233
  state.transactionId = action.payload;
165
234
  },
166
- setAccommodationFlyInStep(state, action: PayloadAction<AccommodationFlyInStep>) {
167
- state.accommodationFlyInStep = action.payload;
235
+ setFlyInType(state, action: PayloadAction<FlyInType | null>) {
236
+ state.flyInType = action.payload;
168
237
  },
169
238
  setPriceDetails(state, action: PayloadAction<BookingPriceDetails | null>) {
170
239
  state.priceDetails = action.payload;
171
240
  },
172
241
  setItinerary(state, action: PayloadAction<ClientPortalItinerary | null>) {
173
242
  state.itinerary = action.payload;
243
+ },
244
+ setSelectedOutwardKey: (state, action: PayloadAction<string | null>) => {
245
+ state.selectedOutwardKey = action.payload;
246
+ },
247
+ setSelectedReturnKey: (state, action: PayloadAction<string | null>) => {
248
+ state.selectedReturnKey = action.payload;
249
+ },
250
+ resetFlightSelection: (state) => {
251
+ state.selectedOutwardKey = null;
252
+ state.selectedReturnKey = null;
253
+ },
254
+ setExcursionSearchParams(state, action: PayloadAction<ExcursionSearchParams>) {
255
+ state.excursionSearchParams = action.payload;
256
+ },
257
+ setSelectedExcursionSearchResult(state, action: PayloadAction<PackagingAccommodationResponse | null>) {
258
+ state.selectedExcursionSearchResult = action.payload;
259
+ },
260
+ confirmExcursionForDay: (state, action: PayloadAction<{ dayKey: string; excursion: PackagingAccommodationResponse }>) => {
261
+ const { dayKey, excursion } = action.payload;
262
+
263
+ const existingForDay = state.confirmedExcursionsByDay[dayKey] ?? [];
264
+
265
+ const existingIndex = existingForDay.findIndex((item) => item.code === excursion.code);
266
+
267
+ if (existingIndex >= 0) {
268
+ // replace existing confirmed version of same excursion
269
+ existingForDay[existingIndex] = excursion;
270
+ } else {
271
+ existingForDay.push(excursion);
272
+ }
273
+
274
+ state.confirmedExcursionsByDay[dayKey] = existingForDay;
275
+ },
276
+ removeConfirmedExcursionForDay: (state, action: PayloadAction<{ dayKey: string; excursionCode: string }>) => {
277
+ const { dayKey, excursionCode } = action.payload;
278
+
279
+ state.confirmedExcursionsByDay[dayKey] = (state.confirmedExcursionsByDay[dayKey] ?? []).filter((item) => item.code !== excursionCode);
280
+ },
281
+ clearConfirmedExcursionsForDay: (state, action: PayloadAction<{ dayKey: string }>) => {
282
+ delete state.confirmedExcursionsByDay[action.payload.dayKey];
174
283
  }
175
284
  }
176
285
  });
@@ -181,6 +290,7 @@ export const {
181
290
  setSelectedSearchResult,
182
291
  setPackagingAccoResults,
183
292
  setFilteredPackagingAccoResults,
293
+ setFilteredPackagingFlightResults,
184
294
  setPackagingAccoSearchDetails,
185
295
  setSelectedPackagingAccoResult,
186
296
  setPackagingFlightResults,
@@ -191,18 +301,31 @@ export const {
191
301
  selectFlight,
192
302
  setIsLoading,
193
303
  setFlightsLoading,
304
+ setInitialFilters,
194
305
  setFilters,
195
306
  resetFilters,
307
+ setInitialFlightFilters,
308
+ setFlightFilters,
309
+ resetFlightFilters,
196
310
  setSortType,
311
+ setFlightSortType,
197
312
  setActiveTab,
198
313
  setCurrentPage,
199
314
  resetSearchState,
200
315
  setFlyInIsOpen,
201
316
  setEditablePackagingEntry,
202
317
  setTransactionId,
203
- setAccommodationFlyInStep,
318
+ setFlyInType,
204
319
  setPriceDetails,
205
- setItinerary
320
+ setItinerary,
321
+ setSelectedOutwardKey,
322
+ setSelectedReturnKey,
323
+ resetFlightSelection,
324
+ setExcursionSearchParams,
325
+ setSelectedExcursionSearchResult,
326
+ confirmExcursionForDay,
327
+ removeConfirmedExcursionForDay,
328
+ clearConfirmedExcursionsForDay
206
329
  } = searchResultsSlice.actions;
207
330
 
208
331
  export default searchResultsSlice.reducer;
@@ -2,6 +2,7 @@ import {
2
2
  BookingPackage,
3
3
  BookingPackageRequestRoom,
4
4
  FlightSearchResponseItem,
5
+ PackageMainRoom,
5
6
  PackagingEntry,
6
7
  WebsiteConfigurationSearchConfiguration
7
8
  } from '@qite/tide-client';
@@ -64,7 +65,19 @@ export interface SearchResultsConfiguration {
64
65
 
65
66
  export type FilterType = 'checkbox' | 'toggle' | 'slider' | 'star-rating';
66
67
 
67
- export type FilterProperty = 'regime' | 'accommodation' | 'max-duration' | 'price' | 'rating' | 'theme';
68
+ export type FilterProperty =
69
+ | 'regime'
70
+ | 'accommodation'
71
+ | 'max-duration'
72
+ | 'price'
73
+ | 'rating'
74
+ | 'theme'
75
+ | 'airline'
76
+ | 'numberOfStops'
77
+ | 'departureRange'
78
+ | 'departureAirport'
79
+ | 'arrivalAirport'
80
+ | 'travelDuration';
68
81
 
69
82
  export interface FilterOption {
70
83
  label: string;
@@ -205,4 +218,44 @@ export type SearchSeed = {
205
218
  rooms: BookingPackageRequestRoom[];
206
219
  };
207
220
 
208
- export type AccommodationFlyInStep = 'results' | 'details';
221
+ export type FlyInType =
222
+ | 'flight-outward-results'
223
+ | 'flight-return-results'
224
+ | 'flight-details'
225
+ | 'acco-results'
226
+ | 'acco-details'
227
+ | 'excursion-results'
228
+ | 'excursion-details';
229
+
230
+ export interface ExcursionSearchParams {
231
+ // Core: which day are we searching for
232
+ date: string; // ISO string (e.g. "2026-07-01")
233
+
234
+ // Optional but useful if your API expects a range
235
+ fromDate: string; // usually same as date
236
+ toDate: string; // usually same as date
237
+
238
+ // Location context
239
+ countryId?: number | null;
240
+ regionId?: number | null;
241
+ oordId?: number | null;
242
+ locationId?: number | null;
243
+ locationName?: string;
244
+
245
+ // Accommodation context (important for availability/pricing)
246
+ hotelCode: string;
247
+ hotelName: string;
248
+
249
+ accommodationCode: string | null;
250
+ accommodationName: string | null;
251
+
252
+ // Occupancy (VERY likely needed later)
253
+ rooms?: PackageMainRoom[];
254
+
255
+ // Optional: currency / language (depends on your backend)
256
+ currencyCode?: string;
257
+ languageCode?: string;
258
+
259
+ // Optional: traceability/debugging
260
+ source?: 'day-by-day-excursions';
261
+ }
@@ -11,6 +11,7 @@ import { range } from 'lodash';
11
11
 
12
12
  export const GROUP_TOUR_SERVICE_TYPE = 1;
13
13
  export const ACCOMMODATION_SERVICE_TYPE = 3;
14
+ export const EXCURSION_SERVICE_TYPE = 4;
14
15
  export const FLIGHT_SERVICE_TYPE = 7;
15
16
 
16
17
  export const toDateOnlyString = (value: string | Date): string => {