@qite/tide-booking-component 1.4.31 → 1.4.32

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 (68) hide show
  1. package/build/build-cjs/booking-product/components/date-range-picker/index.d.ts +1 -0
  2. package/build/build-cjs/booking-product/components/dates.d.ts +5 -0
  3. package/build/build-cjs/booking-product/components/list-view.d.ts +8 -0
  4. package/build/build-cjs/booking-product/constants.d.ts +1 -0
  5. package/build/build-cjs/booking-product/types.d.ts +2 -0
  6. package/build/build-cjs/booking-product/utils/api.d.ts +6 -1
  7. package/build/build-cjs/booking-wizard/features/booking/booking-slice.d.ts +8 -1
  8. package/build/build-cjs/booking-wizard/features/booking/selectors.d.ts +3 -0
  9. package/build/build-cjs/booking-wizard/features/sidebar/sidebar-util.d.ts +1 -1
  10. package/build/build-cjs/booking-wizard/features/sidebar/sidebar.d.ts +1 -0
  11. package/build/build-cjs/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +1 -0
  12. package/build/build-cjs/booking-wizard/types.d.ts +1 -0
  13. package/build/build-cjs/index.js +5219 -1052
  14. package/build/build-cjs/search-results/store/search-results-slice.d.ts +2 -0
  15. package/build/build-cjs/search-results/types.d.ts +2 -2
  16. package/build/build-cjs/shared/utils/localization-util.d.ts +17 -2
  17. package/build/build-esm/booking-product/components/date-range-picker/index.d.ts +1 -0
  18. package/build/build-esm/booking-product/components/dates.d.ts +5 -0
  19. package/build/build-esm/booking-product/components/list-view.d.ts +8 -0
  20. package/build/build-esm/booking-product/constants.d.ts +1 -0
  21. package/build/build-esm/booking-product/types.d.ts +2 -0
  22. package/build/build-esm/booking-product/utils/api.d.ts +6 -1
  23. package/build/build-esm/booking-wizard/features/booking/booking-slice.d.ts +8 -1
  24. package/build/build-esm/booking-wizard/features/booking/selectors.d.ts +3 -0
  25. package/build/build-esm/booking-wizard/features/sidebar/sidebar-util.d.ts +1 -1
  26. package/build/build-esm/booking-wizard/features/sidebar/sidebar.d.ts +1 -0
  27. package/build/build-esm/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +1 -0
  28. package/build/build-esm/booking-wizard/types.d.ts +1 -0
  29. package/build/build-esm/index.js +5211 -1045
  30. package/build/build-esm/search-results/store/search-results-slice.d.ts +2 -0
  31. package/build/build-esm/search-results/types.d.ts +2 -2
  32. package/build/build-esm/shared/utils/localization-util.d.ts +17 -2
  33. package/package.json +1 -1
  34. package/src/booking-product/components/date-range-picker/index.tsx +29 -16
  35. package/src/booking-product/components/dates.tsx +28 -5
  36. package/src/booking-product/components/list-view.tsx +54 -0
  37. package/src/booking-product/components/product.tsx +152 -20
  38. package/src/booking-product/constants.ts +1 -0
  39. package/src/booking-product/settings-context.ts +3 -1
  40. package/src/booking-product/types.ts +2 -0
  41. package/src/booking-product/utils/api.ts +9 -3
  42. package/src/search-results/components/flight/flight-card.tsx +1 -1
  43. package/src/search-results/components/hotel/hotel-accommodation-results.tsx +11 -6
  44. package/src/search-results/components/hotel/hotel-card.tsx +15 -1
  45. package/src/search-results/components/search-results-container/search-results-container.tsx +69 -29
  46. package/src/search-results/features/flights/flight-search-results-self-contained.tsx +0 -3
  47. package/src/search-results/features/hotels/hotel-search-results-self-contained.tsx +0 -3
  48. package/src/search-results/store/search-results-slice.ts +7 -1
  49. package/src/search-results/types.ts +2 -2
  50. package/src/shared/translations/ar-SA.json +249 -0
  51. package/src/shared/translations/da-DK.json +249 -0
  52. package/src/shared/translations/de-DE.json +249 -0
  53. package/src/shared/translations/en-GB.json +3 -1
  54. package/src/shared/translations/es-ES.json +249 -0
  55. package/src/shared/translations/fr-BE.json +3 -1
  56. package/src/shared/translations/fr-FR.json +249 -0
  57. package/src/shared/translations/is-IS.json +249 -0
  58. package/src/shared/translations/it-IT.json +249 -0
  59. package/src/shared/translations/ja-JP.json +249 -0
  60. package/src/shared/translations/nl-BE.json +3 -1
  61. package/src/shared/translations/nl-NL.json +249 -0
  62. package/src/shared/translations/no-NO.json +249 -0
  63. package/src/shared/translations/pl-PL.json +249 -0
  64. package/src/shared/translations/pt-PT.json +249 -0
  65. package/src/shared/translations/sv-SE.json +249 -0
  66. package/src/shared/utils/localization-util.ts +107 -12
  67. package/styles/components/_form.scss +6 -0
  68. package/styles/components/_search.scss +1 -0
@@ -1,12 +1,23 @@
1
1
  import React from 'react';
2
2
  import { HotelResult } from '../../types';
3
3
  import Icon from '../icon';
4
+ import { useDispatch, useSelector } from 'react-redux';
5
+ import { SearchResultsRootState } from '../../store/search-results-store';
6
+ import { setSelectedHotel } from '../../store/search-results-slice';
4
7
 
5
8
  interface HotelCardProps {
6
9
  result: HotelResult;
7
10
  }
8
11
 
9
12
  const HotelCard: React.FC<HotelCardProps> = ({ result }) => {
13
+ const dispatch = useDispatch();
14
+ const { selectedHotelId } = useSelector((state: SearchResultsRootState) => state.searchResults);
15
+
16
+ const handleChange = (hotelProductId: number) => {
17
+ console.log('selected hotel changed to:', hotelProductId);
18
+ dispatch(setSelectedHotel(hotelProductId));
19
+ };
20
+
10
21
  return (
11
22
  <div
12
23
  key={result.id}
@@ -60,8 +71,11 @@ const HotelCard: React.FC<HotelCardProps> = ({ result }) => {
60
71
  <p className="search__result-card__description">{result.description}</p>
61
72
  </div>
62
73
  <div className="search__result-card__footer">
74
+ <button type="button" className={`cta ${selectedHotelId === result.id ? 'cta--selected' : 'cta--select'}`} onClick={() => handleChange(result.id)}>
75
+ {selectedHotelId === result.id ? 'Selected' : 'Select'}
76
+ </button>
63
77
  <button type="button" className="cta cta--select" onClick={() => console.log('Clicked on customCard with id:', result.id)}>
64
- {result.ctaText}
78
+ View details
65
79
  </button>
66
80
  </div>
67
81
  </div>
@@ -3,14 +3,21 @@ import { useDispatch, useSelector } from 'react-redux';
3
3
  import { SearchResultsRootState } from '../../store/search-results-store';
4
4
  import SearchResultsConfigurationContext from '../../search-results-configuration-context';
5
5
 
6
- import { resetFilters, setSortKey, setResults, setIsLoading } from '../../store/search-results-slice';
6
+ import { resetFilters, setSortKey, setResults, setIsLoading, setSelectedHotel } from '../../store/search-results-slice';
7
7
  import { Filter, SortingOption } from '../../types';
8
8
  import useMediaQuery from '../../../shared/utils/use-media-query-util';
9
9
  import Filters from '../filters/filters';
10
10
  import ItemPicker from '../item-picker';
11
11
 
12
- import { TideClientConfig, search } from '@qite/tide-client';
13
- import { BookingPackageDestination, BookingPackagePax, BookingPackageRequestRoom, BookingPackageSearchRequest } from '@qite/tide-client/build/types';
12
+ import { TideClientConfig, details, search } from '@qite/tide-client';
13
+ import {
14
+ BookingPackageDestination,
15
+ BookingPackageDetailsRequest,
16
+ BookingPackagePax,
17
+ BookingPackageRequest,
18
+ BookingPackageRequestRoom,
19
+ BookingPackageSearchRequest
20
+ } from '@qite/tide-client/build/types';
14
21
  import { getDateFromParams, getNumberFromParams, getRoomsFromParams } from '../../../shared/utils/query-string-util';
15
22
  import { range } from 'lodash';
16
23
  import { Room } from '../../../booking-wizard/types';
@@ -25,7 +32,7 @@ const SearchResultsContainer: React.FC = () => {
25
32
  const isMobile = useMediaQuery('(max-width: 1200px)');
26
33
  const dispatch = useDispatch();
27
34
  const context = useContext(SearchResultsConfigurationContext);
28
- const { results, isLoading, filters, sortKey } = useSelector((state: SearchResultsRootState) => state.searchResults);
35
+ const { results, isLoading, filters, sortKey, selectedHotelId } = useSelector((state: SearchResultsRootState) => state.searchResults);
29
36
 
30
37
  const [searchTrigger, setSearchTrigger] = useState(0);
31
38
  const [initialFiltersSet, setInitialFiltersSet] = useState(false);
@@ -81,10 +88,10 @@ const SearchResultsContainer: React.FC = () => {
81
88
  destinationIsLocation = true;
82
89
  }
83
90
 
84
- const searchRequest = {
91
+ const searchRequest: BookingPackageRequest<BookingPackageSearchRequest> = {
85
92
  officeId: 1,
86
93
  payload: {
87
- catalogueIds: context.tideConnection.catalogueIds,
94
+ catalogueIds: context.tideConnection.catalogueIds ?? [],
88
95
  serviceType:
89
96
  context?.type === 'hotel' || context?.type === 'hotel-flight' ? 3 : context?.type === 'flight' ? 7 : context?.type === 'roundTrip' ? 1 : 0,
90
97
  searchType: 0,
@@ -105,13 +112,13 @@ const SearchResultsContainer: React.FC = () => {
105
112
  filters
106
113
  .find((f) => f.property === 'regime')
107
114
  ?.options?.filter((o) => o.isChecked)
108
- .flatMap((o) => o.value) || [],
115
+ .flatMap((o) => o.value.toString()) || [],
109
116
  minPrice: filters.find((f) => f.property === 'price')?.selectedMin,
110
117
  maxPrice: filters.find((f) => f.property === 'price')?.selectedMax,
111
118
  useExactDates: true,
112
119
  onlyCachedResults: false,
113
120
  includeAllAllotments: true
114
- } as BookingPackageSearchRequest
121
+ }
115
122
  };
116
123
 
117
124
  const config: TideClientConfig = {
@@ -131,6 +138,9 @@ const SearchResultsContainer: React.FC = () => {
131
138
  }
132
139
 
133
140
  dispatch(setResults({ results: packageSearchResults }));
141
+ if (packageSearchResults?.length > 0) {
142
+ dispatch(setSelectedHotel(packageSearchResults[0].productId));
143
+ }
134
144
  dispatch(setIsLoading(false));
135
145
  } catch (err) {
136
146
  console.error('Search failed', err);
@@ -141,6 +151,57 @@ const SearchResultsContainer: React.FC = () => {
141
151
  runSearch();
142
152
  }, [location.search, searchTrigger]);
143
153
 
154
+ useEffect(() => {
155
+ const fetchPackageDetails = async () => {
156
+ if (!selectedHotelId || !context) return;
157
+
158
+ try {
159
+ const config: TideClientConfig = {
160
+ host: context.tideConnection.host,
161
+ apiKey: context.tideConnection.apiKey
162
+ };
163
+
164
+ const selectedItem = results.find((r) => r.productId === selectedHotelId);
165
+ if (!selectedItem) return;
166
+
167
+ const params = new URLSearchParams(location.search);
168
+ const rooms = getRoomsFromParams(params, 'rooms');
169
+ const requestRooms = getRequestRooms(rooms);
170
+
171
+ const detailsRequest: BookingPackageRequest<BookingPackageDetailsRequest> = {
172
+ officeId: 1,
173
+ payload: {
174
+ catalogueId: selectedItem.catalogueId,
175
+ rooms: requestRooms,
176
+ searchType: 0, // same as search
177
+ productCode: selectedItem.code,
178
+ fromDate: selectedItem.fromDate,
179
+ toDate: selectedItem.toDate,
180
+ includeFlights: true,
181
+ includeHotels: true,
182
+ includePaxTypes: true,
183
+ checkExternalAvailability: true,
184
+ expectedPrice: selectedItem.price,
185
+ duration: null,
186
+ preNights: null,
187
+ postNights: null
188
+ }
189
+ };
190
+
191
+ const detailsResponse = await details(config, detailsRequest);
192
+
193
+ console.log('Package details:', detailsResponse);
194
+
195
+ // TODO: store flights / details in redux
196
+ // dispatch(setSelectedHotelDetails(details));
197
+ } catch (err) {
198
+ console.error('Failed to fetch package details', err);
199
+ }
200
+ };
201
+
202
+ fetchPackageDetails();
203
+ }, [selectedHotelId]);
204
+
144
205
  const getRequestRooms = (rooms: Room[] | null) => {
145
206
  if (!rooms) {
146
207
  // Fall back to 2 adults
@@ -174,7 +235,6 @@ const SearchResultsContainer: React.FC = () => {
174
235
  const [isMobileFiltersOpen, setIsMobileFiltersOpen] = useState(false);
175
236
 
176
237
  const handleSortChange = (newSortKey: string) => {
177
- console.log('Sort changed to:', newSortKey);
178
238
  dispatch(setSortKey(newSortKey));
179
239
  };
180
240
 
@@ -188,26 +248,6 @@ const SearchResultsContainer: React.FC = () => {
188
248
  }
189
249
  }, [isMobileFiltersOpen]);
190
250
 
191
- // const getFilteredResults = () => {
192
- // const filteredResults = results.filter((result) => {
193
- // // Apply frontend filters here
194
-
195
- // const ratingFilter = filters.find((f) => f.property === 'rating' && f.selectedRating != null);
196
- // if (ratingFilter) {
197
- // const minRating = ratingFilter.selectedRating!;
198
- // const hotelStars = result.stars ?? 0;
199
- // if (hotelStars < minRating) {
200
- // return false;
201
- // }
202
- // }
203
-
204
- // // Add more frontend filters if needed
205
- // return true;
206
- // });
207
-
208
- // return filteredResults;
209
- // };
210
-
211
251
  const sortingOptions: SortingOption[] = [
212
252
  { key: 'price-asc', label: 'Price: Low to High' },
213
253
  { key: 'price-desc', label: 'Price: High to Low' },
@@ -236,9 +236,6 @@ const FlightSearchResultsSelfContained: React.FC<FlightSearchResultsSelfContaine
236
236
  // ---- Static results + custom renderer ----
237
237
  showCustomCards: true,
238
238
  customCardRenderer,
239
- onResultClick: (id) => {
240
- console.log('Clicked on card with id:', id);
241
- },
242
239
 
243
240
  filters,
244
241
 
@@ -156,9 +156,6 @@ const HotelSearchResultsSelfContained: React.FC<HotelSearchResultsSelfContainedP
156
156
  // results,
157
157
  showCustomCards: true,
158
158
  // customCards,
159
- onResultClick: (id) => {
160
- console.log('Clicked on card with id:', id);
161
- },
162
159
  customCardRenderer,
163
160
 
164
161
  // Map View
@@ -4,6 +4,7 @@ import { BookingPackageItem } from '@qite/tide-client/build/types';
4
4
 
5
5
  export interface SearchResultsState {
6
6
  results: BookingPackageItem[];
7
+ selectedHotelId: number | null;
7
8
  isLoading: boolean;
8
9
  filters: Filter[];
9
10
  sortKey: string | null;
@@ -13,6 +14,7 @@ export interface SearchResultsState {
13
14
 
14
15
  const initialState: SearchResultsState = {
15
16
  results: [],
17
+ selectedHotelId: null,
16
18
  isLoading: false,
17
19
  filters: [],
18
20
  sortKey: null,
@@ -27,6 +29,9 @@ const searchResultsSlice = createSlice({
27
29
  setResults(state, action: PayloadAction<{ results: BookingPackageItem[] }>) {
28
30
  state.results = action.payload.results;
29
31
  },
32
+ setSelectedHotel(state, action: PayloadAction<number | null>) {
33
+ state.selectedHotelId = action.payload;
34
+ },
30
35
  setIsLoading(state, action: PayloadAction<boolean>) {
31
36
  state.isLoading = action.payload;
32
37
  },
@@ -65,6 +70,7 @@ const searchResultsSlice = createSlice({
65
70
  }
66
71
  });
67
72
 
68
- export const { setResults, setIsLoading, setFilters, resetFilters, setSortKey, setActiveTab, setCurrentPage, resetSearchState } = searchResultsSlice.actions;
73
+ export const { setResults, setSelectedHotel, setIsLoading, setFilters, resetFilters, setSortKey, setActiveTab, setCurrentPage, resetSearchState } =
74
+ searchResultsSlice.actions;
69
75
 
70
76
  export default searchResultsSlice.reducer;
@@ -27,7 +27,6 @@ export interface SearchResultsConfiguration {
27
27
  showRoundTripResults?: boolean;
28
28
  showCustomCards?: boolean;
29
29
  customCardRenderer?: (result: SearchResult) => ReactNode;
30
- onResultClick?: (id: string) => void;
31
30
 
32
31
  // Map view
33
32
  // not supported for now
@@ -57,6 +56,7 @@ export interface SearchResultsConfiguration {
57
56
  };
58
57
 
59
58
  cmsHotelData?: any[];
59
+ languageCode?: string;
60
60
  }
61
61
 
62
62
  export type FilterType = 'checkbox' | 'toggle' | 'slider' | 'star-rating';
@@ -93,7 +93,7 @@ export interface PaginationConfig {
93
93
  export type SearchResult = HotelResult | FlightResult | RoundTripResult;
94
94
 
95
95
  export interface BaseSearchResult {
96
- id: string;
96
+ id: number;
97
97
  title: string;
98
98
  image: string;
99
99
  description?: string;
@@ -0,0 +1,249 @@
1
+ {
2
+ "STEPS": {
3
+ "PERSONAL_DETAILS": "التفاصيل الشخصية",
4
+ "EXTRA_OPTIONS": "خيارات إضافية",
5
+ "SUMMARY": "الملخص",
6
+ "CONFIRMATION": "التأكيد",
7
+ "ERROR": "فشل الحجز",
8
+ "PREVIOUS": "الخطوة السابقة",
9
+ "NEXT": "الخطوة التالية",
10
+ "SUBMIT_BOOKING": "تأكيد الحجز",
11
+ "SUBMIT_OFFER": "طلب عرض سعر",
12
+ "SUBMIT_OPTION": "اخذ خيار",
13
+ "COMPOSE": "إنشاء",
14
+ "ROOM_OPTIONS": "خيارات الغرف",
15
+ "FLIGHT_OPTIONS": "خيارات الرحلات"
16
+ },
17
+ "INPUT": {
18
+ "INCREASE": "زيادة",
19
+ "DECREASE": "إنقاص"
20
+ },
21
+ "FLIGHTS_FORM": {
22
+ "OUTWARD_FLIGHTS": "رحلات الذهاب",
23
+ "OUTWARD_FLIGHT": "رحلة الذهاب",
24
+ "RETURN_FLIGHTS": "رحلات العودة",
25
+ "RETURN_FLIGHT": "رحلة العودة",
26
+ "DIRECT_FLIGHT": "رحلة مباشرة",
27
+ "STOP": "توقف",
28
+ "STOPS": "توقفات",
29
+ "FLIGHT_STOPS": "توقف/توقفات",
30
+ "DIFFERENT_OPTION_WARNING": "تحذير: هذه الرحلة تغير مدة الإقامة.",
31
+ "FILTER_OPTIONS": "تصفية الخيارات",
32
+ "AIRLINES": "شركات الطيران",
33
+ "AIRPORTS": "المطارات",
34
+ "NUMBER_OF_STOPS": "عدد التوقفات",
35
+ "FLIGHT_OUTWARD": "رحلة الذهاب",
36
+ "DEPARTURE_TIME": "وقت المغادرة",
37
+ "TRAVEL_DURATION": "مدة السفر",
38
+ "CHANGE_TIME": "وقت التوقف",
39
+ "FLIGHT_RETURN": "رحلة العودة",
40
+ "NO_FLIGHTS_FOUND": "لم يتم العثور على رحلات.",
41
+ "STARTING": "ابتداءً من",
42
+ "LOWEST_PRICE": "أقل سعر",
43
+ "CHOOSE_YOUR_CLASS": "اختر الدرجة:",
44
+ "PLUS_ONE_DAY": "+1 يوم",
45
+ "STOP_TIME": "وقت التوقف",
46
+ "NIGHT_DEPARTURE": "ليل (00:00 - 05:00)",
47
+ "MORNING_DEPARTURE": "صباح (05:00 - 12:00)",
48
+ "AFTERNOON_DEPARTURE": "ظهر (12:00 - 18:00)",
49
+ "EVENING_DEPARTURE": "مساءً (18:00 - 00:00)",
50
+ "FLIGHTS_FOUND_1": "",
51
+ "FLIGHTS_FOUND_2": "رحلات",
52
+ "FLIGHTS_FOUND_3": "تم العثور عليها"
53
+ },
54
+ "PRODUCT": {
55
+ "STAY_INCLUDED": "الإقامة متضمنة",
56
+ "FLIGHT_INCLUDED": "الرحلة متضمنة",
57
+ "TRANSFER_INCLUDED": "النقل متضمن",
58
+ "LOADING_PRICE": "يتم حساب السعر الخاص بك.",
59
+ "PER_PERSON": "لكل شخص",
60
+ "PER_NIGHT": "لكل ليلة",
61
+ "PER_PERSON_PER_NIGHT": "لكل شخص / لكل ليلة",
62
+ "BOOK_NOW": "احجز الآن",
63
+ "TO_YOUR_OFFER": "إلى عرضك",
64
+ "NOT_AVAILABLE": "غير متاح",
65
+ "NUMBER_OF_ROOMS": "عدد الغرف",
66
+ "AGE_BY_DEPARTURE_DATE": "عمر الأطفال عند تاريخ المغادرة",
67
+ "YEAR": "سنة/سنوات",
68
+ "APPLY": "تطبيق",
69
+ "EDIT": "تعديل",
70
+ "DEPARTURE": "المغادرة",
71
+ "DEPARTURE_DATE": "تاريخ المغادرة",
72
+ "RETURN": "العودة",
73
+ "RETURN_DATE": "تاريخ العودة",
74
+ "WHO_YOU_TRAVELING_WITH": "مع من تسافر؟",
75
+ "TRAVEL_PERIOD": "مدة السفر",
76
+ "CLOSE": "إغلاق",
77
+ "NIGHTS": "ليالي",
78
+ "DAYS": "أيام"
79
+ },
80
+ "MAIN": {
81
+ "PREPARING_BOOKING": "يرجى الانتظار، يتم تجهيز حجزك",
82
+ "PREPARING_OFFER": "يرجى الانتظار، يتم تجهيز عرض السعر الخاص بك",
83
+ "PREPARING_DOSSIER": "يرجى الانتظار، يتم تجهيز ملفك",
84
+ "PRODUCT_UNAVAILABLE": "المنتج غير متاح"
85
+ },
86
+ "SHARED": {
87
+ "ROOM": "غرفة",
88
+ "ROOMS": "غرف",
89
+ "TOTAL_PRICE": "السعر الإجمالي",
90
+ "ADULTS": "بالغون",
91
+ "CHILDREN": "أطفال",
92
+ "SELECT": "اختر",
93
+ "SELECTED": "تم الاختيار"
94
+ },
95
+ "SIDEBAR": {
96
+ "OVERVIEW": "الملخص",
97
+ "SLIDE_TOTAL_PRICE": "المبلغ الإجمالي: ",
98
+ "SLIDE_DEPOSIT": "الدفعة المقدمة: ",
99
+ "TRAVEL_INFO": "معلومات السفر",
100
+ "TRAVELERS": "المسافرون",
101
+ "TRAVELERS_ADULTS": "بالغون",
102
+ "TRAVELERS_ADULT": "بالغ",
103
+ "TRAVELERS_CHILDREN": "أطفال",
104
+ "TRAVELERS_CHILD": "طفل",
105
+ "DEPARTURE": "رحلة الذهاب",
106
+ "DEPARTURE_SINGLE": "التاريخ",
107
+ "ARRIVAL": "رحلة العودة",
108
+ "FLIGHT": "رحلة",
109
+ "ACCOMMODATION": "الحجز شامل الإقامة",
110
+ "BASE_PRICE": "السعر الأساسي",
111
+ "OPTIONS": "الخيارات",
112
+ "INCLUDED_COSTS": "التكاليف المضمنة",
113
+ "EXTRA_COSTS": "التكاليف الإضافية",
114
+ "DEPOSIT": "الدفعة المقدمة",
115
+ "DEPOSIT_TEXT1": "خطوات ",
116
+ "DEPOSIT_TEXT2": "المبلغ المتبقي",
117
+ "DEPOSIT_TEXT3": " من ",
118
+ "DEPOSIT_TEXT4": " موضحة في ",
119
+ "DEPOSIT_TEXT5": "الخطوة \"الملخص\"",
120
+ "DEPOSIT_TEXT6": " من عملية الحجز.",
121
+ "LUGGAGE_INCLUDED": "الأمتعة متضمنة",
122
+ "DEPARTURE_FLIGHT": "رحلة الذهاب",
123
+ "ARRIVAL_FLIGHT": "رحلة العودة",
124
+ "FLIGHT_DEPARTURE": "المغادرة",
125
+ "FLIGHT_ARRIVAL": "الوصول",
126
+ "ON_REQUEST": "حسب الطلب",
127
+ "CHANGES": "التحويلات"
128
+ },
129
+ "TRAVELERS_FORM": {
130
+ "AGE": "العمر",
131
+ "TRAVELER": "مسافر",
132
+ "ADULT": "بالغ",
133
+ "ADULTS": "بالغون",
134
+ "CHILD": "طفل",
135
+ "CHILDREN": "أطفال",
136
+ "GENDER": "اللقب",
137
+ "MALE": "السيد",
138
+ "FEMALE": "السيدة",
139
+ "OTHER": "آخر",
140
+ "MAIN_BOOKER": "الحاجز الرئيسي",
141
+ "FIRST_NAME": "الاسم الأول",
142
+ "LAST_NAME": "اسم العائلة",
143
+ "BIRTHDATE": "تاريخ الميلاد",
144
+ "STREET": "الشارع",
145
+ "STREET_PLACEHOLDER": "اسم الشارع",
146
+ "HOUSE_NUMBER": "رقم المنزل",
147
+ "POST_BOX": "صندوق بريد",
148
+ "ZIPCODE": "الرمز البريدي",
149
+ "CITY": "المدينة",
150
+ "CITY_PLACEHOLDER": "المدينة",
151
+ "COUNTRY": "الدولة",
152
+ "SELECT_COUNTRY": "اختر الدولة",
153
+ "PHONE": "رقم الهاتف",
154
+ "EMAIL": "البريد الإلكتروني",
155
+ "REPEAT_EMAIL": "أعد إدخال البريد الإلكتروني",
156
+ "VALIDATION_MESSAGE": "يرجى التحقق من الحقول أدناه وملئها بشكل صحيح.",
157
+ "BOOK_WITH_AGENT": "أريد الحجز عبر وكيل السفر المحلي الخاص بي",
158
+ "CHOOSE_OFFICE": "أختار مكتب",
159
+ "PERSON": "شخص",
160
+ "COUNTRIES": {
161
+ "BELGIUM": "بلجيكا",
162
+ "NETHERLANDS": "هولندا",
163
+ "FRANCE": "فرنسا"
164
+ },
165
+ "CHOOSE_AGENT_PLACEHOLDER": "اختر وكيل السفر الخاص بك",
166
+ "VALIDATION": {
167
+ "TRAVELER_X_FIELD": "الغرفة {0} - المسافر {1}: {2}",
168
+ "SINGLE_ROOM_TRAVELER_X_FIELD": "المسافر {0}: {1}",
169
+ "TRAVELER_X_IS_NO_ADULT": "الغرفة {0} - المسافر {1}: ليس بالغًا",
170
+ "SINGLE_ROOM_TRAVELER_X_IS_NO_ADULT": "المسافر {0}: ليس بالغًا",
171
+ "TRAVELER_X_IS_NO_CHILD": "الغرفة {0} - المسافر {1}: ليس طفلًا",
172
+ "SINGLE_ROOM_TRAVELER_X_IS_NO_CHILD": "المسافر {0}: ليس طفلًا",
173
+ "NO_MAIN_BOOKER_SELECTED": "لم يتم اختيار حاجز رئيسي",
174
+ "MAIN_BOOKER_FIELD": "الحاجز الرئيسي: {0}",
175
+ "MAIN_BOOKER_EMAIL_IS_INVALID": "الحاجز الرئيسي: البريد الإلكتروني غير صالح",
176
+ "MAIN_BOOKER_EMAIL_DOES_NOT_MATCH": "الحاجز الرئيسي: البريد الإلكتروني لا يطابق",
177
+ "AGENT_IS_REQUIRED": "وكيل السفر مطلوب"
178
+ }
179
+ },
180
+ "OPTIONS_FORM": {
181
+ "NO_OPTIONS_TITLE": "لا توجد خيارات",
182
+ "NO_OPTIONS_MESSAGE": "هذه الرحلة لا تحتوي على خيارات إضافية.",
183
+ "UNIT_TITLE": "الحفلة",
184
+ "PACKAGE": "باقة",
185
+ "DAY": "يوم",
186
+ "DAYS": "أيام",
187
+ "NIGHT": "ليلة",
188
+ "NIGHTS": "ليالي",
189
+ "PER_PAX_TITLE": "اختر الخيارات لكل مسافر",
190
+ "PER_BOOKING_TITLE": "اختر الخيارات لكل حجز",
191
+ "PER_UNIT_TITLE": "اختر الخيارات لكل حفلة",
192
+ "NONE": "لا شيء"
193
+ },
194
+ "ROOM_OPTIONS_FORM": {
195
+ "TRAVELER_GROUP": "مجموعة المسافرين",
196
+ "ALTERNATIVES_TRAVELER_GROUP": "خيارات غرف بديلة لمجموعة المسافرين",
197
+ "SHOW_ALTERNATIVES": "عرض خيارات الغرف البديلة"
198
+ },
199
+ "SUMMARY": {
200
+ "PERSONAL_DETAILS": "التفاصيل الشخصية",
201
+ "TRAVELERS": "المسافرون",
202
+ "TRAVELER": "المسافر",
203
+ "ADULTS": "بالغون",
204
+ "ADULT": "بالغ",
205
+ "CHILDREN": "أطفال",
206
+ "CHILD": "طفل",
207
+ "MAIN_BOOKER": "الحاجز الرئيسي",
208
+ "NOTIFICATIONS_TITLE": "تنبيه",
209
+ "VALIDATE_TITLE": "تحقق من معلوماتك",
210
+ "VALIDATE_TEXT_BOOKING": "أنت على وشك تأكيد حجزك. يرجى التحقق من صحة جميع المعلومات والتأكد من تطابق الأسماء مع هويتك أو جواز السفر. هذه المعلومات نهائية ولا يمكن تعديلها.",
211
+ "VALIDATE_TEXT_OFFER": "أنت على وشك طلب عرض سعر. يرجى التحقق من صحة جميع المعلومات والتأكد من تطابق الأسماء مع هويتك أو جواز السفر لتجنب أي مشاكل عند الحجز لاحقًا.",
212
+ "VALIDATE_TEXT_OPTION": "إذا اخترت أخذ خيار، فهناك مهلة لممارسة هذا الخيار تعتمد على شركة الطيران. الخيار يضمن المكان وليس السعر. السعر المذكور في هذا العرض لكل شخص ويعتمد على التوافر. السعر مضمون فقط بعد إصدار التذكرة.",
213
+ "OPTIONS": "الخيارات",
214
+ "REMARKS": "ملاحظات",
215
+ "VOUCHERS": "قسائم",
216
+ "VOUCHER_VALIDATE": "تحقق من القسيمة",
217
+ "ADD_VOUCHER": "إضافة قسيمة",
218
+ "VOUCHER_VALID": "القسيمة صالحة",
219
+ "VOUCHER_INVALID": "القسيمة غير صالحة"
220
+ },
221
+ "CONFIRMATION": {
222
+ "TITLE_TEXT_OFFER": "تم طلب عرضك رقم {0}",
223
+ "TITLE_TEXT_BOOKING": "تم تأكيد حجزك رقم {0}",
224
+ "TITLE_TEXT_OPTION": "لقد اخترت خيار على الرقم {0}.",
225
+ "MESSAGE_TEXT1": "رحلتك الحلم قريبة جدًا الآن.",
226
+ "MESSAGE_TEXT2_OFFER": "يقوم متخصصو السفر لدينا بمعالجة طلبك وسيتواصلون معك خلال 48 ساعة.",
227
+ "MESSAGE_TEXT2_BOOKING": "يقوم متخصصو السفر لدينا بمعالجة حجزك وسيتواصلون معك خلال 48 ساعة.",
228
+ "MESSAGE_TEXT2_OPTION": "تم تسجيل خيارك من قبل متخصصي السفر وسيتواصلون معك خلال 48 ساعة لتأكيد أو مناقشة خيارك.",
229
+ "QUESTIONS_TEXT1": "هل لديك أي أسئلة؟ ",
230
+ "QUESTIONS_TEXT2": "أخبرنا",
231
+ "QUESTIONS_TEXT3": ".",
232
+ "QUESTIONS_ALT": "اتصل بنا",
233
+ "MAIL_SUBJECT": "معلومات الحجز"
234
+ },
235
+ "ERROR": {
236
+ "TRY_AGAIN": "حاول الحجز مرة أخرى",
237
+ "MESSAGE_TEXT1": "حدث خطأ أثناء تأكيد رحلتك.",
238
+ "MESSAGE_TEXT2": "انقر أدناه للمحاولة مرة أخرى.",
239
+ "ERROR_TEXT1": "لا يزال لا يعمل؟ ",
240
+ "ERROR_TEXT2": "تأكد من إعلامنا",
241
+ "ERROR_TEXT3": ".",
242
+ "ERROR_ALT": "اتصل بنا"
243
+ },
244
+ "PRINT_OFFER_BUTTON": {
245
+ "LABEL_IDLE": "طباعة العرض",
246
+ "LABEL_CREATING": "جارٍ إنشاء العرض…",
247
+ "LABEL_PRINTING": "جارٍ إنشاء ملف PDF…"
248
+ }
249
+ }