tripstorekrabi-shared 1.13.68 → 1.13.70
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/booking.js +10 -3
- package/package.json +1 -1
- package/utils.js +280 -156
package/booking.js
CHANGED
|
@@ -8,6 +8,11 @@ dayjs.extend(advancedFormat);
|
|
|
8
8
|
dayjs.extend(utc);
|
|
9
9
|
dayjs.extend(timezone);
|
|
10
10
|
|
|
11
|
+
export let OPERATOR_NOTE = 'Operator';
|
|
12
|
+
export let CUSTOMER_NOTE = 'Customer';
|
|
13
|
+
export const NOTES = [OPERATOR_NOTE, CUSTOMER_NOTE];
|
|
14
|
+
export const MAX_NOTES = 10;
|
|
15
|
+
|
|
11
16
|
const PHONE_REGEXP = /[^\d+]/g;
|
|
12
17
|
|
|
13
18
|
export function addBookingFromInvoice(
|
|
@@ -252,9 +257,11 @@ export function getStartingPointMessage(booking, product) {
|
|
|
252
257
|
text += '\n\nWHAT TO BRING: ' + product.whatToBring;
|
|
253
258
|
}
|
|
254
259
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
260
|
+
let notes = Object.values(booking.notes ?? {})
|
|
261
|
+
.filter((item) => item.visibility.includes(CUSTOMER_NOTE))
|
|
262
|
+
.map((item) => item.description);
|
|
263
|
+
if (notes.length > 0) {
|
|
264
|
+
text += '\n\nSPECIAL CUSTOMER NEEDS: ' + notes.join(', ');
|
|
258
265
|
}
|
|
259
266
|
|
|
260
267
|
if (product?.customerInformation?.length > 0) {
|
package/package.json
CHANGED
package/utils.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import dayjs from
|
|
2
|
-
import customParseFormat from
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import customParseFormat from 'dayjs/plugin/customParseFormat.js';
|
|
3
3
|
import advancedFormat from 'dayjs/plugin/advancedFormat.js';
|
|
4
|
-
import isSameOrBefore from
|
|
4
|
+
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore.js';
|
|
5
5
|
import utc from 'dayjs/plugin/utc.js';
|
|
6
6
|
import timezone from 'dayjs/plugin/timezone.js';
|
|
7
|
-
import { findEndPoint, findStartingPoint } from
|
|
7
|
+
import { findEndPoint, findStartingPoint } from './price.js';
|
|
8
8
|
|
|
9
9
|
dayjs.extend(customParseFormat);
|
|
10
10
|
dayjs.extend(advancedFormat);
|
|
@@ -12,15 +12,22 @@ dayjs.extend(isSameOrBefore);
|
|
|
12
12
|
dayjs.extend(utc);
|
|
13
13
|
dayjs.extend(timezone);
|
|
14
14
|
|
|
15
|
-
export const PROD_URL =
|
|
15
|
+
export const PROD_URL = 'https://www.tripstorekrabi.com';
|
|
16
16
|
export const MAX_AGE_SEC = 60 * 60 * 24;
|
|
17
17
|
export const NO_ROOM = 'NO ROOM';
|
|
18
18
|
export const IN_HOUSE = 'IN HOUSE';
|
|
19
19
|
export const CHECK_IN_LATE = 'CHECK-IN LATE';
|
|
20
20
|
export const ROOM_NUMBER_LIST = [NO_ROOM, IN_HOUSE, CHECK_IN_LATE];
|
|
21
21
|
|
|
22
|
-
const
|
|
23
|
-
const
|
|
22
|
+
export const TRIPSTORE_AGENCYID_IN_PHAYUN = '2Z5NPZTmd62tm22q0RNB';
|
|
23
|
+
export const GYG_AGENCYID_IN_PHAYUN = 'lPZIMbXgzaFwA366uzia';
|
|
24
|
+
export const KLK_AGENCYID_IN_PHAYUN = 'JSYggp9yw8RBdIkhuPvo';
|
|
25
|
+
export const TIQ_AGENCYID_IN_PHAYUN = 'HPiO2Z6OdD8A3O5Zbi96';
|
|
26
|
+
|
|
27
|
+
const EMAIL_PATTERN = new RegExp(
|
|
28
|
+
/^[a-zA-Z0-9.!#$%&' * +/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
|
|
29
|
+
);
|
|
30
|
+
const MEALS = ['lunch', 'meal', 'breakfast', 'dinner'];
|
|
24
31
|
const SCHEDULE_PATTERN = new RegExp('^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$');
|
|
25
32
|
|
|
26
33
|
export function validateEmail(email) {
|
|
@@ -28,13 +35,18 @@ export function validateEmail(email) {
|
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
export function resizeGoogleImage(image, size) {
|
|
31
|
-
return image
|
|
32
|
-
/\/w.\d+-.\d+-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
.replace(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
return image
|
|
39
|
+
.replace(/\/w.\d+-.\d+-p\//, '/' + size + '/')
|
|
40
|
+
.replace(/\/w.\d+-.\d+-c\//, '/' + size + '/')
|
|
41
|
+
.replace(/\/w.\d+-.\d+-no\//, '/' + size + '/')
|
|
42
|
+
.replace(/\/w.\d+-.\d+\//, '/' + size + '/')
|
|
43
|
+
.replace(/\/s.\d+\//, '/' + size + '/')
|
|
44
|
+
.replace(/\=w.\d+-.\d+-p/, '=' + size)
|
|
45
|
+
.replace(/\=w.\d+-.\d+-c/, '=' + size)
|
|
46
|
+
.replace(/\=w.\d+-.\d+-no/, '=' + size)
|
|
47
|
+
.replace(/\=w.\d+-.\d+/, '=' + size)
|
|
48
|
+
.replace(/\=s.\d+/, '=' + size)
|
|
49
|
+
.replace(/\=s.\d+/, '=' + size);
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
export function resizeStorageImage(path, size) {
|
|
@@ -46,9 +58,9 @@ export function createPdfPreview(path, size) {
|
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
export function formatNumber(number, fraction = 2) {
|
|
49
|
-
return number.toLocaleString(
|
|
61
|
+
return number.toLocaleString('th-TH', {
|
|
50
62
|
minimumFractionDigits: fraction,
|
|
51
|
-
maximumFractionDigits: fraction
|
|
63
|
+
maximumFractionDigits: fraction,
|
|
52
64
|
});
|
|
53
65
|
}
|
|
54
66
|
|
|
@@ -69,30 +81,34 @@ export function getDurationSummary(schedules) {
|
|
|
69
81
|
}
|
|
70
82
|
});
|
|
71
83
|
|
|
72
|
-
return minDuration == maxDuration
|
|
84
|
+
return minDuration == maxDuration
|
|
85
|
+
? formatDuration(minDuration)
|
|
86
|
+
: `${formatDuration(minDuration)} - ${formatDuration(maxDuration)}`;
|
|
73
87
|
}
|
|
74
88
|
|
|
75
89
|
export function getDuration(schedule) {
|
|
76
90
|
if (schedule) {
|
|
77
|
-
let schedules = schedule.split(
|
|
78
|
-
let minutes = dayjs(schedules[1].trim(),
|
|
91
|
+
let schedules = schedule.split('-');
|
|
92
|
+
let minutes = dayjs(schedules[1].trim(), 'HH:mm').diff(
|
|
93
|
+
dayjs(schedules[0].trim(), 'HH:mm'),
|
|
94
|
+
'minute'
|
|
95
|
+
);
|
|
79
96
|
if (minutes < 0) {
|
|
80
97
|
minutes = 24 * 60 + minutes;
|
|
81
98
|
}
|
|
82
99
|
return minutes;
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
100
|
+
} else {
|
|
85
101
|
return 0;
|
|
86
102
|
}
|
|
87
103
|
}
|
|
88
104
|
|
|
89
105
|
export function formatDuration(minutes) {
|
|
90
106
|
if (minutes === 0) {
|
|
91
|
-
return
|
|
107
|
+
return '-';
|
|
92
108
|
} else if (minutes > 60) {
|
|
93
|
-
return (minutes / 60).toFixed(1) +
|
|
109
|
+
return (minutes / 60).toFixed(1) + ' hours';
|
|
94
110
|
} else {
|
|
95
|
-
return minutes +
|
|
111
|
+
return minutes + ' minutes';
|
|
96
112
|
}
|
|
97
113
|
}
|
|
98
114
|
|
|
@@ -100,25 +116,30 @@ export function getPickuptimeSummary(pickupZones) {
|
|
|
100
116
|
if (pickupZones && pickupZones.length > 0) {
|
|
101
117
|
let pickupTimesArray = [];
|
|
102
118
|
pickupZones.forEach((pickupZone) => {
|
|
103
|
-
let pickupLength = pickupZone.indexOf(
|
|
119
|
+
let pickupLength = pickupZone.indexOf(': ');
|
|
104
120
|
let pickupTimes = pickupZone.substring(pickupLength + 1).trim();
|
|
105
|
-
if (pickupZone.indexOf(
|
|
106
|
-
pickupTimesArray.push(pickupTimes.split(
|
|
121
|
+
if (pickupZone.indexOf(' / ') != -1) {
|
|
122
|
+
pickupTimesArray.push(pickupTimes.split(' / '));
|
|
107
123
|
} else {
|
|
108
124
|
pickupTimesArray.push([pickupTimes]);
|
|
109
125
|
}
|
|
110
126
|
});
|
|
111
127
|
|
|
112
|
-
|
|
113
|
-
|
|
128
|
+
pickupTimesArray = pickupTimesArray[0].map((_, colIndex) =>
|
|
129
|
+
pickupTimesArray.map((row) => row[colIndex])
|
|
130
|
+
);
|
|
114
131
|
|
|
115
132
|
return pickupTimesArray.map((items) => {
|
|
116
|
-
let pickupTimes = [
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
133
|
+
let pickupTimes = [
|
|
134
|
+
...new Set(
|
|
135
|
+
items.reduce((r, e) => {
|
|
136
|
+
e.split(' - ').forEach((item) => {
|
|
137
|
+
r.push(item);
|
|
138
|
+
});
|
|
139
|
+
return r;
|
|
140
|
+
}, [])
|
|
141
|
+
),
|
|
142
|
+
].sort();
|
|
122
143
|
|
|
123
144
|
if (pickupTimes.length == 1) {
|
|
124
145
|
return pickupTimes[0];
|
|
@@ -132,62 +153,88 @@ export function getPickuptimeSummary(pickupZones) {
|
|
|
132
153
|
}
|
|
133
154
|
|
|
134
155
|
export function getDeparture(schedule) {
|
|
135
|
-
return schedule.split(
|
|
156
|
+
return schedule.split('-')[0].trim();
|
|
136
157
|
}
|
|
137
158
|
|
|
138
159
|
export function getPickupTime(schedule, offset = 30) {
|
|
139
|
-
if (schedule.indexOf(
|
|
140
|
-
return dayjs(schedule.split(
|
|
160
|
+
if (schedule.indexOf('-') != -1) {
|
|
161
|
+
return dayjs(schedule.split('-')[0].trim(), 'HH:mm')
|
|
162
|
+
.subtract(offset, 'minute')
|
|
163
|
+
.format('HH:mm');
|
|
141
164
|
} else {
|
|
142
|
-
return dayjs(schedule,
|
|
165
|
+
return dayjs(schedule, 'HH:mm').subtract(offset, 'minute').format('HH:mm');
|
|
143
166
|
}
|
|
144
167
|
}
|
|
145
168
|
|
|
146
169
|
export function getArrival(schedule) {
|
|
147
|
-
return schedule.split(
|
|
170
|
+
return schedule.split('-')[1].trim();
|
|
148
171
|
}
|
|
149
172
|
|
|
150
173
|
export function isHotelPickup(value) {
|
|
151
174
|
value = value.toLowerCase();
|
|
152
|
-
return (
|
|
175
|
+
return (
|
|
176
|
+
(value.includes('picked up') ||
|
|
177
|
+
value.includes('pickup') ||
|
|
178
|
+
value.includes('round-trip')) &&
|
|
179
|
+
value.includes('hotel')
|
|
180
|
+
);
|
|
153
181
|
}
|
|
154
182
|
|
|
155
183
|
export function isHotelDropOff(value) {
|
|
156
184
|
value = value.toLowerCase();
|
|
157
|
-
return (
|
|
185
|
+
return (
|
|
186
|
+
(value.includes('dropped off') ||
|
|
187
|
+
value.includes('drop-off') ||
|
|
188
|
+
value.includes('transfer')) &&
|
|
189
|
+
value.includes('hotel')
|
|
190
|
+
);
|
|
158
191
|
}
|
|
159
192
|
|
|
160
193
|
export function isAirportPickup(value) {
|
|
161
194
|
value = value.toLowerCase();
|
|
162
|
-
value = value
|
|
163
|
-
|
|
195
|
+
value = value
|
|
196
|
+
.replace('pick up', 'pickup')
|
|
197
|
+
.replace('picked up', 'pickup')
|
|
198
|
+
.replace('pick-up', 'pickup');
|
|
199
|
+
return (
|
|
200
|
+
(value.includes('pickup') || value.includes('meet')) &&
|
|
201
|
+
value.includes('airport')
|
|
202
|
+
);
|
|
164
203
|
}
|
|
165
204
|
|
|
166
205
|
export function isAirportDropOff(value) {
|
|
167
206
|
value = value.toLowerCase();
|
|
168
207
|
|
|
169
|
-
let result =
|
|
208
|
+
let result =
|
|
209
|
+
(value.includes('drop-off') || value.includes('transfer')) &&
|
|
210
|
+
value.includes('airport');
|
|
170
211
|
|
|
171
|
-
if (!result && value.includes(
|
|
172
|
-
result = value.substring(value.indexOf(
|
|
212
|
+
if (!result && value.includes(' to ')) {
|
|
213
|
+
result = value.substring(value.indexOf(' to ')).includes(' airport');
|
|
173
214
|
}
|
|
174
215
|
return result;
|
|
175
216
|
}
|
|
176
217
|
|
|
177
218
|
export function isMeetingPoint(value) {
|
|
178
219
|
value = value.toLowerCase();
|
|
179
|
-
value = value
|
|
180
|
-
|
|
220
|
+
value = value
|
|
221
|
+
.replace('pick up', 'pickup')
|
|
222
|
+
.replace('picked up', 'pickup')
|
|
223
|
+
.replace('pick-up', 'pickup');
|
|
224
|
+
return (
|
|
225
|
+
value.indexOf('meet ') != -1 ||
|
|
226
|
+
(value.indexOf('pickup') != -1 && value.indexOf('hotel') == -1)
|
|
227
|
+
);
|
|
181
228
|
}
|
|
182
229
|
|
|
183
230
|
export function isTrainStation(value) {
|
|
184
231
|
value = value.toLowerCase();
|
|
185
|
-
return value.includes(
|
|
232
|
+
return value.includes('train') && value.includes('station');
|
|
186
233
|
}
|
|
187
234
|
|
|
188
235
|
export function isMealIncluded(includes) {
|
|
189
236
|
if (includes) {
|
|
190
|
-
let includesString = includes.join(
|
|
237
|
+
let includesString = includes.join(' ').toLowerCase();
|
|
191
238
|
return MEALS.some((item) => includesString.includes(item));
|
|
192
239
|
} else {
|
|
193
240
|
return false;
|
|
@@ -197,7 +244,7 @@ export function isMealIncluded(includes) {
|
|
|
197
244
|
export function validateName(name) {
|
|
198
245
|
name = name.trim();
|
|
199
246
|
if (name) {
|
|
200
|
-
return name.indexOf(
|
|
247
|
+
return name.indexOf(' ') != -1;
|
|
201
248
|
} else {
|
|
202
249
|
return false;
|
|
203
250
|
}
|
|
@@ -208,7 +255,7 @@ export function scrollContainer() {
|
|
|
208
255
|
}
|
|
209
256
|
|
|
210
257
|
export function toTitleCase(str) {
|
|
211
|
-
return str.replace(/\b\S/g, t => t.toUpperCase());
|
|
258
|
+
return str.replace(/\b\S/g, (t) => t.toUpperCase());
|
|
212
259
|
}
|
|
213
260
|
|
|
214
261
|
export function capitalize(string) {
|
|
@@ -253,23 +300,25 @@ function chunkArray(array, chunk_size) {
|
|
|
253
300
|
}
|
|
254
301
|
|
|
255
302
|
export function encodeURL(url) {
|
|
256
|
-
return toTitleCase(url).replace(/ /g,
|
|
303
|
+
return toTitleCase(url).replace(/ /g, '-');
|
|
257
304
|
}
|
|
258
305
|
|
|
259
306
|
export function formatPeople(people) {
|
|
260
307
|
let result = [];
|
|
261
308
|
if (people.adults > 0) {
|
|
262
|
-
result.push(`${people.adults} ${people.adults > 1 ?
|
|
309
|
+
result.push(`${people.adults} ${people.adults > 1 ? 'adults' : 'adult'}`);
|
|
263
310
|
}
|
|
264
311
|
if (people.children > 0) {
|
|
265
|
-
result.push(
|
|
266
|
-
}`
|
|
312
|
+
result.push(
|
|
313
|
+
`${people.children} ${people.children > 1 ? 'children' : 'child'}`
|
|
314
|
+
);
|
|
267
315
|
}
|
|
268
316
|
if (people.infants > 0) {
|
|
269
|
-
result.push(
|
|
270
|
-
}`
|
|
317
|
+
result.push(
|
|
318
|
+
`${people.infants} ${people.infants > 1 ? 'infants' : 'infant'}`
|
|
319
|
+
);
|
|
271
320
|
}
|
|
272
|
-
return result.join(
|
|
321
|
+
return result.join(', ');
|
|
273
322
|
}
|
|
274
323
|
|
|
275
324
|
export function countPeople(people) {
|
|
@@ -281,34 +330,53 @@ export function isNumeric(n) {
|
|
|
281
330
|
}
|
|
282
331
|
|
|
283
332
|
export function getBookingSummary(booking, options = {}) {
|
|
284
|
-
let summary =
|
|
333
|
+
let summary = '';
|
|
285
334
|
if (!options.excludeReferenceNumber) {
|
|
286
335
|
summary += booking.referenceNumber;
|
|
287
336
|
if (booking.code) {
|
|
288
|
-
summary +=
|
|
337
|
+
summary += ', Code: ' + booking.code;
|
|
289
338
|
}
|
|
290
339
|
|
|
291
340
|
if (options.includeVersion && booking.version) {
|
|
292
|
-
summary +=
|
|
341
|
+
summary += ', Version: ' + booking.version;
|
|
293
342
|
}
|
|
294
|
-
summary +=
|
|
343
|
+
summary += ': ';
|
|
295
344
|
}
|
|
296
345
|
|
|
297
|
-
if (
|
|
298
|
-
|
|
299
|
-
|
|
346
|
+
if (
|
|
347
|
+
booking.productDescription &&
|
|
348
|
+
booking.operator &&
|
|
349
|
+
booking.departureDate &&
|
|
350
|
+
booking.schedule &&
|
|
351
|
+
booking.leadTraveller
|
|
352
|
+
) {
|
|
353
|
+
let departureDate = dayjs(booking.departureDate.toDate())
|
|
354
|
+
.tz('Asia/Bangkok')
|
|
355
|
+
.format('DD.MM.YYYY');
|
|
356
|
+
summary += booking.productDescription + ', ' + departureDate;
|
|
300
357
|
|
|
301
358
|
if (!options.hideOperator) {
|
|
302
|
-
summary +=
|
|
359
|
+
summary += ', ' + booking.operator;
|
|
303
360
|
}
|
|
304
361
|
|
|
305
|
-
summary +=
|
|
306
|
-
|
|
362
|
+
summary +=
|
|
363
|
+
', ' +
|
|
364
|
+
booking.adults +
|
|
365
|
+
', ' +
|
|
366
|
+
booking.children +
|
|
367
|
+
', ' +
|
|
368
|
+
booking.infants +
|
|
369
|
+
', ' +
|
|
370
|
+
booking.leadTraveller;
|
|
307
371
|
|
|
308
372
|
if (booking.startingPointDescription) {
|
|
309
|
-
summary +=
|
|
373
|
+
summary +=
|
|
374
|
+
', ' +
|
|
375
|
+
(isHotelPickup(booking.startingPointDescription) && booking.noHotelYet
|
|
376
|
+
? 'NO HOTEL YET'
|
|
377
|
+
: booking.startingPointDescription);
|
|
310
378
|
} else if (booking.noHotelYet) {
|
|
311
|
-
summary +=
|
|
379
|
+
summary += ', NO HOTEL YET';
|
|
312
380
|
}
|
|
313
381
|
|
|
314
382
|
let hasHotelPickup = isHotelPickup(booking.startingPointDescription);
|
|
@@ -320,31 +388,33 @@ export function getBookingSummary(booking, options = {}) {
|
|
|
320
388
|
}
|
|
321
389
|
}
|
|
322
390
|
|
|
323
|
-
summary +=
|
|
391
|
+
summary += ', ' + booking.schedule;
|
|
324
392
|
|
|
325
|
-
if (booking.pickupTime && booking.pickupTime !=
|
|
393
|
+
if (booking.pickupTime && booking.pickupTime != '?') {
|
|
326
394
|
if (hasHotelPickup) {
|
|
327
|
-
summary +=
|
|
395
|
+
summary += ' (Pickup';
|
|
328
396
|
|
|
329
|
-
if (booking.pickupTime.indexOf(
|
|
330
|
-
summary +=
|
|
397
|
+
if (booking.pickupTime.indexOf('-') != -1) {
|
|
398
|
+
summary +=
|
|
399
|
+
' between ' +
|
|
400
|
+
booking.pickupTime.replace(' - ', ' and ').replace('-', ' and ');
|
|
331
401
|
} else {
|
|
332
|
-
summary +=
|
|
402
|
+
summary += ' at ' + booking.pickupTime;
|
|
333
403
|
}
|
|
334
|
-
summary +=
|
|
404
|
+
summary += ')';
|
|
335
405
|
} else if (isMeetingPoint(booking.startingPointDescription)) {
|
|
336
|
-
summary +=
|
|
406
|
+
summary += ' (Meet';
|
|
337
407
|
|
|
338
|
-
if (booking.pickupTime.indexOf(
|
|
339
|
-
summary +=
|
|
408
|
+
if (booking.pickupTime.indexOf('-') != -1) {
|
|
409
|
+
summary += ' at ' + booking.pickupTime.split('-')[0].trim();
|
|
340
410
|
} else {
|
|
341
|
-
summary +=
|
|
411
|
+
summary += ' at ' + booking.pickupTime;
|
|
342
412
|
}
|
|
343
|
-
summary +=
|
|
413
|
+
summary += ')';
|
|
344
414
|
}
|
|
345
415
|
}
|
|
346
416
|
} else {
|
|
347
|
-
summary +=
|
|
417
|
+
summary += '«THE BOOKING IS INCOMPLETE»';
|
|
348
418
|
}
|
|
349
419
|
|
|
350
420
|
return summary;
|
|
@@ -354,24 +424,28 @@ export function getItemSummary(item, product) {
|
|
|
354
424
|
let summary = item.description;
|
|
355
425
|
|
|
356
426
|
if (item.departureDate) {
|
|
357
|
-
summary +=
|
|
427
|
+
summary +=
|
|
428
|
+
', ' + dayjs(item.departureDate).tz('Asia/Bangkok').format('DD.MM.YYYY');
|
|
358
429
|
}
|
|
359
430
|
|
|
360
431
|
if (item.schedule) {
|
|
361
|
-
summary +=
|
|
432
|
+
summary += ', ' + item.schedule;
|
|
362
433
|
}
|
|
363
434
|
|
|
364
435
|
if (item.adults || item.children || item.infants) {
|
|
365
|
-
summary +=
|
|
436
|
+
summary += ', ' + formatPeople(item) + ', ';
|
|
366
437
|
}
|
|
367
438
|
|
|
368
439
|
if (item.startingPointId) {
|
|
369
|
-
let startingPointDescription = findStartingPoint(
|
|
440
|
+
let startingPointDescription = findStartingPoint(
|
|
441
|
+
product,
|
|
442
|
+
item.startingPointId
|
|
443
|
+
).value;
|
|
370
444
|
if (isHotelPickup(startingPointDescription)) {
|
|
371
445
|
if (item.noHotelYet === true) {
|
|
372
|
-
summary +=
|
|
446
|
+
summary += 'Hotel pickup (hotel not known yet)';
|
|
373
447
|
} else {
|
|
374
|
-
summary +=
|
|
448
|
+
summary += 'Hotel pickup from ' + item.pickupHotel;
|
|
375
449
|
|
|
376
450
|
if (item.roomNumber) {
|
|
377
451
|
summary += ` (${item.roomNumber})`;
|
|
@@ -385,7 +459,7 @@ export function getItemSummary(item, product) {
|
|
|
385
459
|
if (item.endPointId) {
|
|
386
460
|
let endPointDescription = findEndPoint(product, item.endPointId).value;
|
|
387
461
|
if (isHotelDropOff(endPointDescription) && item.dropoffHotel) {
|
|
388
|
-
summary +=
|
|
462
|
+
summary += ', Hotel drop-off at ' + item.dropoffHotel;
|
|
389
463
|
}
|
|
390
464
|
}
|
|
391
465
|
|
|
@@ -393,26 +467,36 @@ export function getItemSummary(item, product) {
|
|
|
393
467
|
}
|
|
394
468
|
|
|
395
469
|
export function validateSchedule(schedule, schedules = [], context) {
|
|
396
|
-
if (schedule ===
|
|
470
|
+
if (schedule === '?') {
|
|
397
471
|
return true;
|
|
398
|
-
} else if (schedule.indexOf(
|
|
399
|
-
let times = schedule.split(
|
|
472
|
+
} else if (schedule.indexOf(' - ') != -1) {
|
|
473
|
+
let times = schedule.split(' - ');
|
|
400
474
|
let from = times[0];
|
|
401
475
|
let to = times[1];
|
|
402
476
|
|
|
403
|
-
if (
|
|
404
|
-
|
|
477
|
+
if (
|
|
478
|
+
!SCHEDULE_PATTERN.test(from) ||
|
|
479
|
+
!SCHEDULE_PATTERN.test(to) ||
|
|
480
|
+
from === to
|
|
481
|
+
) {
|
|
482
|
+
return context.createError({
|
|
483
|
+
message: "Invalid schedule format: for example use '09:00 - 15:30'",
|
|
484
|
+
path: context.path,
|
|
485
|
+
});
|
|
405
486
|
}
|
|
406
487
|
} else {
|
|
407
|
-
return context.createError({
|
|
488
|
+
return context.createError({
|
|
489
|
+
message: "Invalid schedule format: for example use '09:00 - 15:30'",
|
|
490
|
+
path: context.path,
|
|
491
|
+
});
|
|
408
492
|
}
|
|
409
493
|
|
|
410
|
-
if (schedule !=
|
|
494
|
+
if (schedule != '') {
|
|
411
495
|
if (schedules.length > 0 && schedules.indexOf(schedule) == -1) {
|
|
412
496
|
return context.createError({
|
|
413
|
-
message:
|
|
497
|
+
message: 'The value does not match the product schedules',
|
|
414
498
|
path: context.path,
|
|
415
|
-
params: { status:
|
|
499
|
+
params: { status: 'warning' },
|
|
416
500
|
});
|
|
417
501
|
}
|
|
418
502
|
}
|
|
@@ -420,26 +504,42 @@ export function validateSchedule(schedule, schedules = [], context) {
|
|
|
420
504
|
return true;
|
|
421
505
|
}
|
|
422
506
|
|
|
423
|
-
export function validatePickupTime(pickupTime, schedule =
|
|
424
|
-
let departureTime = schedule.split(
|
|
507
|
+
export function validatePickupTime(pickupTime, schedule = '', context) {
|
|
508
|
+
let departureTime = schedule.split(' - ')[0];
|
|
425
509
|
|
|
426
|
-
if (pickupTime ===
|
|
510
|
+
if (pickupTime === '?' || schedule === '?') {
|
|
427
511
|
return true;
|
|
428
|
-
} else if (pickupTime.indexOf(
|
|
429
|
-
let times = pickupTime.split(
|
|
512
|
+
} else if (pickupTime.indexOf(' - ') != -1) {
|
|
513
|
+
let times = pickupTime.split(' - ');
|
|
430
514
|
let from = times[0];
|
|
431
515
|
let to = times[1];
|
|
432
516
|
|
|
433
|
-
if (
|
|
434
|
-
|
|
517
|
+
if (
|
|
518
|
+
!SCHEDULE_PATTERN.test(from) ||
|
|
519
|
+
!SCHEDULE_PATTERN.test(to) ||
|
|
520
|
+
from === to
|
|
521
|
+
) {
|
|
522
|
+
return context.createError({
|
|
523
|
+
message:
|
|
524
|
+
"Invalid pickup time format: for example use '09:00' or '08:45 - 09:00'",
|
|
525
|
+
});
|
|
435
526
|
} else {
|
|
436
527
|
return checkTime(from, departureTime, context);
|
|
437
528
|
}
|
|
438
|
-
} else if (pickupTime.indexOf(
|
|
439
|
-
return context.createError({
|
|
529
|
+
} else if (pickupTime.indexOf('-') != -1) {
|
|
530
|
+
return context.createError({
|
|
531
|
+
message: `Invalid pickup time format, use spaces around the dash: ${pickupTime
|
|
532
|
+
.replace(/ /g, '')
|
|
533
|
+
.replace('-', ' - ')}`,
|
|
534
|
+
path: context.path,
|
|
535
|
+
});
|
|
440
536
|
} else {
|
|
441
537
|
if (!SCHEDULE_PATTERN.test(pickupTime)) {
|
|
442
|
-
return context.createError({
|
|
538
|
+
return context.createError({
|
|
539
|
+
message:
|
|
540
|
+
"Invalid pickup time format: for example use '09:00' or '08:45 - 09:00'",
|
|
541
|
+
path: context.path,
|
|
542
|
+
});
|
|
443
543
|
} else {
|
|
444
544
|
return checkTime(pickupTime, departureTime, context);
|
|
445
545
|
}
|
|
@@ -447,11 +547,11 @@ export function validatePickupTime(pickupTime, schedule = "", context) {
|
|
|
447
547
|
}
|
|
448
548
|
|
|
449
549
|
export function isPickupTimeBeforeDepartureTime(schedule, pickupTime) {
|
|
450
|
-
let departureTime = schedule.split(
|
|
451
|
-
if (pickupTime ===
|
|
550
|
+
let departureTime = schedule.split(' - ')[0];
|
|
551
|
+
if (pickupTime === '?' || schedule === '?') {
|
|
452
552
|
return true;
|
|
453
|
-
} else if (pickupTime.indexOf(
|
|
454
|
-
let times = pickupTime.split(
|
|
553
|
+
} else if (pickupTime.indexOf(' - ') != -1) {
|
|
554
|
+
let times = pickupTime.split(' - ');
|
|
455
555
|
pickupTime = times[0];
|
|
456
556
|
}
|
|
457
557
|
|
|
@@ -459,25 +559,39 @@ export function isPickupTimeBeforeDepartureTime(schedule, pickupTime) {
|
|
|
459
559
|
}
|
|
460
560
|
|
|
461
561
|
function checkTime(pickupTimeValue, departureTimeValue, context) {
|
|
462
|
-
if (pickupTimeValue ===
|
|
562
|
+
if (pickupTimeValue === '' || departureTimeValue === '') {
|
|
463
563
|
return false;
|
|
464
564
|
}
|
|
465
565
|
|
|
466
566
|
try {
|
|
467
|
-
let pickupTimeValues = pickupTimeValue.split(
|
|
468
|
-
let pickupTime = dayjs()
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
567
|
+
let pickupTimeValues = pickupTimeValue.split(':');
|
|
568
|
+
let pickupTime = dayjs()
|
|
569
|
+
.hour(pickupTimeValues[0])
|
|
570
|
+
.minute(pickupTimeValues[1])
|
|
571
|
+
.second(0);
|
|
572
|
+
|
|
573
|
+
let departureTimeValues = departureTimeValue.split(':');
|
|
574
|
+
let departureTime = dayjs()
|
|
575
|
+
.hour(departureTimeValues[0])
|
|
576
|
+
.minute(departureTimeValues[1])
|
|
577
|
+
.second(0);
|
|
578
|
+
|
|
579
|
+
return pickupTime.isSameOrBefore(departureTime)
|
|
580
|
+
? true
|
|
581
|
+
: context
|
|
582
|
+
? context.createError({
|
|
583
|
+
message: 'Pickup time should be before or equals departure time',
|
|
584
|
+
path: context.path,
|
|
585
|
+
params: { status: 'warning' },
|
|
586
|
+
})
|
|
587
|
+
: false;
|
|
474
588
|
} catch (e) {
|
|
475
589
|
return false;
|
|
476
590
|
}
|
|
477
591
|
}
|
|
478
592
|
|
|
479
593
|
export function isActivity(url) {
|
|
480
|
-
return url.includes(
|
|
594
|
+
return url.includes('/Activities/');
|
|
481
595
|
}
|
|
482
596
|
|
|
483
597
|
export function getGoogleDocId(url) {
|
|
@@ -488,18 +602,22 @@ export function createVoucherRequest(booking, product) {
|
|
|
488
602
|
let request = {
|
|
489
603
|
booking: {
|
|
490
604
|
referenceNumber: booking.referenceNumber,
|
|
491
|
-
specialRequirements: booking.specialRequirements
|
|
605
|
+
specialRequirements: booking.specialRequirements
|
|
606
|
+
? booking.specialRequirements.toUpperCase()
|
|
607
|
+
: '',
|
|
492
608
|
nationalParkFee:
|
|
493
609
|
product && product.nationalPark
|
|
494
|
-
?
|
|
495
|
-
|
|
496
|
-
:
|
|
610
|
+
? 'NATIONAL PARK ENTRANCE FEE: ' +
|
|
611
|
+
booking.nationalParkFee.toUpperCase()
|
|
612
|
+
: '',
|
|
497
613
|
productDescription: booking.productDescription,
|
|
498
614
|
leadTraveller: booking.leadTraveller,
|
|
499
615
|
adults: booking.adults,
|
|
500
616
|
children: booking.children,
|
|
501
617
|
infants: booking.infants,
|
|
502
|
-
departureDate: dayjs(booking.departureDate.toDate())
|
|
618
|
+
departureDate: dayjs(booking.departureDate.toDate())
|
|
619
|
+
.tz('Asia/Bangkok')
|
|
620
|
+
.format('Do MMM YYYY'),
|
|
503
621
|
operator: booking.operator,
|
|
504
622
|
startingPointDescription: booking.startingPointDescription,
|
|
505
623
|
roomNumber: booking.roomNumber,
|
|
@@ -507,84 +625,84 @@ export function createVoucherRequest(booking, product) {
|
|
|
507
625
|
pickupTime: booking.pickupTime,
|
|
508
626
|
mobileVoucher: product
|
|
509
627
|
? product.operator.mobileVoucher ??
|
|
510
|
-
|
|
628
|
+
product.operator.default.mobileVoucher
|
|
511
629
|
: true,
|
|
512
630
|
},
|
|
513
631
|
};
|
|
514
632
|
if (booking.voucherUrl) {
|
|
515
|
-
request[
|
|
633
|
+
request['id'] = getGoogleDocId(booking.voucherUrl);
|
|
516
634
|
}
|
|
517
635
|
|
|
518
636
|
return request;
|
|
519
637
|
}
|
|
520
638
|
|
|
521
639
|
export function isGYGBooking(referenceNumber) {
|
|
522
|
-
return referenceNumber.startsWith(
|
|
640
|
+
return referenceNumber.startsWith('GYG');
|
|
523
641
|
}
|
|
524
642
|
|
|
525
643
|
export function isViatorBooking(referenceNumber) {
|
|
526
|
-
return referenceNumber.startsWith(
|
|
644
|
+
return referenceNumber.startsWith('BR-');
|
|
527
645
|
}
|
|
528
646
|
|
|
529
647
|
export function isExpediaBooking(referenceNumber) {
|
|
530
|
-
return referenceNumber.startsWith(
|
|
648
|
+
return referenceNumber.startsWith('EXP-');
|
|
531
649
|
}
|
|
532
650
|
|
|
533
651
|
export function isKlookBooking(referenceNumber) {
|
|
534
|
-
return referenceNumber.startsWith(
|
|
652
|
+
return referenceNumber.startsWith('KLK-');
|
|
535
653
|
}
|
|
536
654
|
|
|
537
655
|
export function isMusementBooking(referenceNumber) {
|
|
538
|
-
return referenceNumber.startsWith(
|
|
656
|
+
return referenceNumber.startsWith('MUS');
|
|
539
657
|
}
|
|
540
658
|
|
|
541
659
|
export function isAirbnbBooking(referenceNumber) {
|
|
542
|
-
return referenceNumber.startsWith(
|
|
660
|
+
return referenceNumber.startsWith('Airbnb-');
|
|
543
661
|
}
|
|
544
662
|
|
|
545
663
|
export function isKKdayBooking(referenceNumber) {
|
|
546
|
-
return referenceNumber.startsWith(
|
|
664
|
+
return referenceNumber.startsWith('KKday-');
|
|
547
665
|
}
|
|
548
666
|
|
|
549
667
|
export function isTiqetsBooking(referenceNumber) {
|
|
550
|
-
return referenceNumber.startsWith(
|
|
668
|
+
return referenceNumber.startsWith('TIQ-');
|
|
551
669
|
}
|
|
552
670
|
|
|
553
671
|
export function isCivitatisBooking(referenceNumber) {
|
|
554
|
-
return referenceNumber.startsWith(
|
|
672
|
+
return referenceNumber.startsWith('CIV-');
|
|
555
673
|
}
|
|
556
674
|
|
|
557
675
|
export function isTSKBooking(referenceNumber) {
|
|
558
|
-
return referenceNumber.startsWith(
|
|
676
|
+
return referenceNumber.startsWith('TSK');
|
|
559
677
|
}
|
|
560
678
|
|
|
561
679
|
export function getBookingType(referenceNumber) {
|
|
562
680
|
if (!referenceNumber) {
|
|
563
|
-
return
|
|
681
|
+
return '';
|
|
564
682
|
}
|
|
565
683
|
if (isGYGBooking(referenceNumber)) {
|
|
566
|
-
return
|
|
684
|
+
return 'gyg';
|
|
567
685
|
} else if (isViatorBooking(referenceNumber)) {
|
|
568
|
-
return
|
|
686
|
+
return 'br';
|
|
569
687
|
} else if (isExpediaBooking(referenceNumber)) {
|
|
570
|
-
return
|
|
688
|
+
return 'exp';
|
|
571
689
|
} else if (isKlookBooking(referenceNumber)) {
|
|
572
|
-
return
|
|
690
|
+
return 'klk';
|
|
573
691
|
} else if (isMusementBooking(referenceNumber)) {
|
|
574
|
-
return
|
|
692
|
+
return 'mus';
|
|
575
693
|
} else if (isAirbnbBooking(referenceNumber)) {
|
|
576
|
-
return
|
|
694
|
+
return 'air';
|
|
577
695
|
} else if (isKKdayBooking(referenceNumber)) {
|
|
578
|
-
return
|
|
696
|
+
return 'kkday';
|
|
579
697
|
} else if (isTiqetsBooking(referenceNumber)) {
|
|
580
|
-
return
|
|
698
|
+
return 'tiq';
|
|
581
699
|
} else if (isTSKBooking(referenceNumber)) {
|
|
582
|
-
return
|
|
700
|
+
return 'tsk';
|
|
583
701
|
}
|
|
584
702
|
}
|
|
585
703
|
|
|
586
704
|
export function hasCustomPricing(pricing, bookingType) {
|
|
587
|
-
return pricing[bookingType] || bookingType ===
|
|
705
|
+
return pricing[bookingType] || bookingType === 'tsk';
|
|
588
706
|
}
|
|
589
707
|
|
|
590
708
|
export function truncate(str, num) {
|
|
@@ -592,7 +710,13 @@ export function truncate(str, num) {
|
|
|
592
710
|
}
|
|
593
711
|
|
|
594
712
|
export function isJSON(text) {
|
|
595
|
-
return /^[\],:{}\s]*$/.test(
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
713
|
+
return /^[\],:{}\s]*$/.test(
|
|
714
|
+
text
|
|
715
|
+
.replace(/\\["\\\/bfnrtu]/g, '@')
|
|
716
|
+
.replace(
|
|
717
|
+
/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
|
|
718
|
+
']'
|
|
719
|
+
)
|
|
720
|
+
.replace(/(?:^|:|,)(?:\s*\[)+/g, '')
|
|
721
|
+
);
|
|
722
|
+
}
|