@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.
- package/build/build-cjs/booking-product/components/date-range-picker/index.d.ts +1 -0
- package/build/build-cjs/booking-product/components/dates.d.ts +5 -0
- package/build/build-cjs/booking-product/components/list-view.d.ts +8 -0
- package/build/build-cjs/booking-product/constants.d.ts +1 -0
- package/build/build-cjs/booking-product/types.d.ts +2 -0
- package/build/build-cjs/booking-product/utils/api.d.ts +6 -1
- package/build/build-cjs/booking-wizard/features/booking/booking-slice.d.ts +8 -1
- package/build/build-cjs/booking-wizard/features/booking/selectors.d.ts +3 -0
- package/build/build-cjs/booking-wizard/features/sidebar/sidebar-util.d.ts +1 -1
- package/build/build-cjs/booking-wizard/features/sidebar/sidebar.d.ts +1 -0
- package/build/build-cjs/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +1 -0
- package/build/build-cjs/booking-wizard/types.d.ts +1 -0
- package/build/build-cjs/index.js +5219 -1052
- package/build/build-cjs/search-results/store/search-results-slice.d.ts +2 -0
- package/build/build-cjs/search-results/types.d.ts +2 -2
- package/build/build-cjs/shared/utils/localization-util.d.ts +17 -2
- package/build/build-esm/booking-product/components/date-range-picker/index.d.ts +1 -0
- package/build/build-esm/booking-product/components/dates.d.ts +5 -0
- package/build/build-esm/booking-product/components/list-view.d.ts +8 -0
- package/build/build-esm/booking-product/constants.d.ts +1 -0
- package/build/build-esm/booking-product/types.d.ts +2 -0
- package/build/build-esm/booking-product/utils/api.d.ts +6 -1
- package/build/build-esm/booking-wizard/features/booking/booking-slice.d.ts +8 -1
- package/build/build-esm/booking-wizard/features/booking/selectors.d.ts +3 -0
- package/build/build-esm/booking-wizard/features/sidebar/sidebar-util.d.ts +1 -1
- package/build/build-esm/booking-wizard/features/sidebar/sidebar.d.ts +1 -0
- package/build/build-esm/booking-wizard/features/travelers-form/travelers-form-slice.d.ts +1 -0
- package/build/build-esm/booking-wizard/types.d.ts +1 -0
- package/build/build-esm/index.js +5211 -1045
- package/build/build-esm/search-results/store/search-results-slice.d.ts +2 -0
- package/build/build-esm/search-results/types.d.ts +2 -2
- package/build/build-esm/shared/utils/localization-util.d.ts +17 -2
- package/package.json +1 -1
- package/src/booking-product/components/date-range-picker/index.tsx +29 -16
- package/src/booking-product/components/dates.tsx +28 -5
- package/src/booking-product/components/list-view.tsx +54 -0
- package/src/booking-product/components/product.tsx +152 -20
- package/src/booking-product/constants.ts +1 -0
- package/src/booking-product/settings-context.ts +3 -1
- package/src/booking-product/types.ts +2 -0
- package/src/booking-product/utils/api.ts +9 -3
- package/src/search-results/components/flight/flight-card.tsx +1 -1
- package/src/search-results/components/hotel/hotel-accommodation-results.tsx +11 -6
- package/src/search-results/components/hotel/hotel-card.tsx +15 -1
- package/src/search-results/components/search-results-container/search-results-container.tsx +69 -29
- package/src/search-results/features/flights/flight-search-results-self-contained.tsx +0 -3
- package/src/search-results/features/hotels/hotel-search-results-self-contained.tsx +0 -3
- package/src/search-results/store/search-results-slice.ts +7 -1
- package/src/search-results/types.ts +2 -2
- package/src/shared/translations/ar-SA.json +249 -0
- package/src/shared/translations/da-DK.json +249 -0
- package/src/shared/translations/de-DE.json +249 -0
- package/src/shared/translations/en-GB.json +3 -1
- package/src/shared/translations/es-ES.json +249 -0
- package/src/shared/translations/fr-BE.json +3 -1
- package/src/shared/translations/fr-FR.json +249 -0
- package/src/shared/translations/is-IS.json +249 -0
- package/src/shared/translations/it-IT.json +249 -0
- package/src/shared/translations/ja-JP.json +249 -0
- package/src/shared/translations/nl-BE.json +3 -1
- package/src/shared/translations/nl-NL.json +249 -0
- package/src/shared/translations/no-NO.json +249 -0
- package/src/shared/translations/pl-PL.json +249 -0
- package/src/shared/translations/pt-PT.json +249 -0
- package/src/shared/translations/sv-SE.json +249 -0
- package/src/shared/utils/localization-util.ts +107 -12
- package/styles/components/_form.scss +6 -0
- 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
|
-
|
|
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 {
|
|
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
|
-
}
|
|
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 } =
|
|
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:
|
|
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
|
+
}
|