@pisell/private-materials 6.11.650 → 6.11.652
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/lowcode/assets-daily.json +11 -11
- package/build/lowcode/assets-dev.json +2 -2
- package/build/lowcode/assets-prod.json +11 -11
- package/build/lowcode/meta.js +1 -1
- package/build/lowcode/render/default/view.js +18 -18
- package/build/lowcode/view.js +18 -18
- package/es/components/bigSale/components/BookingFloatingPanel/useBookingPanelController.js +0 -1
- package/es/components/bigSale/components/TimeBar/index.js +0 -1
- package/es/components/bigSale/dialog.js +0 -1
- package/es/components/bigSale/hooks/useBigSaleContext.js +0 -1
- package/es/components/bigSale/hooks/useSelectFloorMapResourceForBigSale.js +0 -1
- package/es/components/bigSale/index.js +0 -1
- package/es/components/bigSale/templates/Kiosk/index.js +0 -1
- package/es/components/sharedSecondaryBigSale/SharedSecondaryBigSaleReceiver.js +0 -1
- package/es/index.js +0 -2
- package/es/plus/pisellReservation/data/bookingToReservationTables.js +1 -1
- package/es/plus/pisellReservation/floorMap/floorPlanApi.js +1 -1
- package/es/plus/pisellReservation/floorMap/reservationMock.js +1 -1
- package/es/plus/saleDetail/Base.js +0 -1
- package/es/plus/saleDetail/components/Client/hooks/useClientSelectorProps.js +0 -1
- package/es/plus/saleDetail/components/DetailActions/index.js +0 -1
- package/es/plus/saleDetail/components/SummaryFinancialSections/index.js +0 -1
- package/es/plus/saleDetail/index.js +0 -1
- package/es/plus/saleDetail/tmpl/B/components/Dish/index.js +0 -1
- package/es/plus/saleDetail/tmpl/B/index.js +0 -1
- package/es/plus/salesSdk/utils/addProductWithFlowDebounced.js +1 -1
- package/es/plus/salesSdk/utils/bookingDate.js +1 -1
- package/es/plus/salesSdk/utils/customerAuthGate.js +1 -1
- package/es/plus/salesSdk/utils/enrichCartLineHolderDisplay.js +1 -1
- package/es/private-materials/lowcode/authmodal/meta.d.ts +1 -0
- package/es/pro/Login2.0/AuthModal.d.ts +1 -1
- package/es/pro/Login2.0/index.d.ts +1 -2
- package/es/pro/Login2.0/shared/types.d.ts +1 -1
- package/es/pro/skuDetailModal/flow/modules/time/index.js +155 -55
- package/es/pro/skuDetailModal/flow/modules/time/posCustomTime.js +59 -0
- package/lib/pro/skuDetailModal/flow/modules/time/index.js +155 -55
- package/lib/pro/skuDetailModal/flow/modules/time/posCustomTime.js +69 -0
- package/package.json +3 -3
- package/es/plus/pisellReservation/index.js +0 -17
- package/es/plus/salesSdk/index.js +0 -51
|
@@ -10,6 +10,7 @@ import { buildDraftCacheItem, getModuleOptions, getUnsupportedBookingFlowReason,
|
|
|
10
10
|
import TimeResourceSelector from "../../../../../components/eventBooking/components/timeResourceSelector/index.js";
|
|
11
11
|
import { resolveAvailabilityStatus } from "../../../../../components/eventBooking/components/bookingAvailabilityCalendar/utils.js";
|
|
12
12
|
import { validateAvailabilityTimeAutoResolution } from "../autoResolution.js";
|
|
13
|
+
import { getAvailabilityCandidateDurationMinutes, getSessionPresetCandidates, isFlexibleDurationValue, isSameAvailabilityCandidateRange, resolvePosCustomTimeBaseMinutes, resolvePosCustomTimeCandidate, resolvePosCustomTimeDefaultDurationMinutes, resolvePosCustomTimeDefaultStartTime, shouldShowPosCustomTimeCandidateCards } from "./posCustomTime.js";
|
|
13
14
|
import dayjs from "dayjs";
|
|
14
15
|
import React, { useEffect, useMemo } from "react";
|
|
15
16
|
import { Alert, Space } from "antd";
|
|
@@ -95,7 +96,18 @@ const getProductDurationMinutes = (context) => {
|
|
|
95
96
|
const duration = (_normalizeDurationMin = normalizeDurationMinutesValue(product === null || product === void 0 ? void 0 : product.duration)) !== null && _normalizeDurationMin !== void 0 ? _normalizeDurationMin : normalizeDurationMinutesValue(product === null || product === void 0 ? void 0 : product.service_duration);
|
|
96
97
|
return duration ? Math.floor(duration) : null;
|
|
97
98
|
};
|
|
98
|
-
const isPosDurationAvailabilityContext = (context) =>
|
|
99
|
+
const isPosDurationAvailabilityContext = (context) => {
|
|
100
|
+
var _product$cartDetailVa2, _product$_extend2;
|
|
101
|
+
const product = context.draft.productData;
|
|
102
|
+
const isSession = Boolean(isSessionProduct(product) || (product === null || product === void 0 || (_product$cartDetailVa2 = product.cartDetailValue) === null || _product$cartDetailVa2 === void 0 ? void 0 : _product$cartDetailVa2.session) || (product === null || product === void 0 || (_product$_extend2 = product._extend) === null || _product$_extend2 === void 0 || (_product$_extend2 = _product$_extend2.other) === null || _product$_extend2 === void 0 ? void 0 : _product$_extend2.session));
|
|
103
|
+
return context.services.presentationPlatform === "pos" && !isSession && (getProductDurationMinutes(context) !== null || isFlexibleDurationValue(product === null || product === void 0 ? void 0 : product.duration));
|
|
104
|
+
};
|
|
105
|
+
const isPosSessionAvailabilityContext = (context) => {
|
|
106
|
+
var _product$cartDetailVa3, _product$_extend3;
|
|
107
|
+
const product = context.draft.productData;
|
|
108
|
+
return context.services.presentationPlatform === "pos" && Boolean(isSessionProduct(product) || (product === null || product === void 0 || (_product$cartDetailVa3 = product.cartDetailValue) === null || _product$cartDetailVa3 === void 0 ? void 0 : _product$cartDetailVa3.session) || (product === null || product === void 0 || (_product$_extend3 = product._extend) === null || _product$_extend3 === void 0 || (_product$_extend3 = _product$_extend3.other) === null || _product$_extend3 === void 0 ? void 0 : _product$_extend3.session));
|
|
109
|
+
};
|
|
110
|
+
const isPosCustomTimeAvailabilityContext = (context) => isPosDurationAvailabilityContext(context) || isPosSessionAvailabilityContext(context);
|
|
99
111
|
const getDraftRangeDurationMinutes = (context) => {
|
|
100
112
|
const { startDate, endDate, startTime, endTime } = context.draft.booking;
|
|
101
113
|
const normalizedStartTime = normalizeStartTimeValue(startTime);
|
|
@@ -109,13 +121,13 @@ const getDraftRangeDurationMinutes = (context) => {
|
|
|
109
121
|
};
|
|
110
122
|
const getAvailabilityDurationOverride = (context, durationOverride) => {
|
|
111
123
|
var _ref, _ref2, _normalizeDurationMin2;
|
|
112
|
-
if (!
|
|
124
|
+
if (!isPosCustomTimeAvailabilityContext(context)) return void 0;
|
|
113
125
|
const duration = (_ref = (_ref2 = (_normalizeDurationMin2 = normalizeDurationMinutesValue(durationOverride)) !== null && _normalizeDurationMin2 !== void 0 ? _normalizeDurationMin2 : normalizeDurationMinutesValue(context.draft.booking.duration)) !== null && _ref2 !== void 0 ? _ref2 : getDraftRangeDurationMinutes(context)) !== null && _ref !== void 0 ? _ref : getProductDurationMinutes(context);
|
|
114
126
|
return duration && duration > 0 ? Math.floor(duration) : void 0;
|
|
115
127
|
};
|
|
116
128
|
const getAvailabilityStartTimeOverride = (context, startTimeOverride) => {
|
|
117
129
|
var _normalizeStartTimeVa;
|
|
118
|
-
if (!
|
|
130
|
+
if (!isPosCustomTimeAvailabilityContext(context)) return void 0;
|
|
119
131
|
return ((_normalizeStartTimeVa = normalizeStartTimeValue(startTimeOverride)) !== null && _normalizeStartTimeVa !== void 0 ? _normalizeStartTimeVa : normalizeStartTimeValue(context.draft.booking.startTime)) || void 0;
|
|
120
132
|
};
|
|
121
133
|
/**
|
|
@@ -150,20 +162,23 @@ const finalizeCandidateWithoutResourceStep = function() {
|
|
|
150
162
|
};
|
|
151
163
|
}();
|
|
152
164
|
const refreshAvailabilityTimes = function() {
|
|
153
|
-
var
|
|
154
|
-
var _context$getModuleDat2;
|
|
165
|
+
var _ref5 = _asyncToGenerator(function* (context, module, options = {}) {
|
|
166
|
+
var _context$getModuleDat2, _ref4;
|
|
167
|
+
const { durationOverride, startTimeOverride, selectionIntent = "restore" } = options;
|
|
155
168
|
const availability = context.services.availability;
|
|
156
169
|
const allowUnavailable = context.services.allowUnavailableBookingSelection === true;
|
|
157
170
|
const posDurationAvailability = isPosDurationAvailabilityContext(context);
|
|
171
|
+
const posSessionAvailability = isPosSessionAvailabilityContext(context);
|
|
172
|
+
const posCustomTimeAvailability = posDurationAvailability || posSessionAvailability;
|
|
158
173
|
const requestedDuration = getAvailabilityDurationOverride(context, durationOverride);
|
|
159
174
|
const requestedStartTime = getAvailabilityStartTimeOverride(context, startTimeOverride);
|
|
160
175
|
const selectedDate = context.draft.booking.startDate.format("YYYY-MM-DD");
|
|
161
176
|
const requestId = Date.now() + Math.random();
|
|
162
|
-
const
|
|
177
|
+
const posCustomTimeHydrationKey = posCustomTimeAvailability && requestedDuration && requestedStartTime ? `${selectedDate}|${requestedStartTime}|${requestedDuration}` : void 0;
|
|
163
178
|
context.setModuleData(module.key, {
|
|
164
179
|
requestId,
|
|
165
180
|
timeSlots: [],
|
|
166
|
-
|
|
181
|
+
posCustomTimeHydrationKey
|
|
167
182
|
});
|
|
168
183
|
const group = (yield availability.getProductTimeRanges(availability.contextId, _objectSpread2({
|
|
169
184
|
productIds: [availability.productId],
|
|
@@ -174,6 +189,39 @@ const refreshAvailabilityTimes = function() {
|
|
|
174
189
|
partySize: resolveSelectionFlowQueryPartySize(context.draft, availability.partySize)
|
|
175
190
|
}, requestedDuration ? _objectSpread2({ durationMinutesByProductId: { [String(availability.productId)]: requestedDuration } }, requestedStartTime ? { durationStartTimesByProductId: { [String(availability.productId)]: [requestedStartTime] } } : {}) : {}))).find((item) => String(item.productId) === String(availability.productId));
|
|
176
191
|
const candidates = (group === null || group === void 0 ? void 0 : group.ranges) || [];
|
|
192
|
+
const product = context.draft.productData;
|
|
193
|
+
if (posDurationAvailability && selectionIntent === "restore" && isFlexibleDurationValue(product === null || product === void 0 ? void 0 : product.duration)) {
|
|
194
|
+
var _context$hostContext, _moduleOptions$slice, _normalizeDurationMin3;
|
|
195
|
+
const moduleOptions = getModuleOptions(module);
|
|
196
|
+
const configuredSlice = (_context$hostContext = context.hostContext) === null || _context$hostContext === void 0 || (_context$hostContext = _context$hostContext.bookingConfig) === null || _context$hostContext === void 0 || (_context$hostContext = _context$hostContext.config) === null || _context$hostContext === void 0 || (_context$hostContext = _context$hostContext.basic) === null || _context$hostContext === void 0 ? void 0 : _context$hostContext.service_time;
|
|
197
|
+
const fallbackSlice = (_moduleOptions$slice = moduleOptions.slice) !== null && _moduleOptions$slice !== void 0 ? _moduleOptions$slice : typeof configuredSlice === "object" ? configuredSlice === null || configuredSlice === void 0 ? void 0 : configuredSlice.value : configuredSlice;
|
|
198
|
+
const baseDurationMinutes = resolvePosCustomTimeBaseMinutes(group === null || group === void 0 ? void 0 : group.slotStepMinutes, fallbackSlice);
|
|
199
|
+
const nextStartTime = resolvePosCustomTimeDefaultStartTime(context.draft.booking.startTime, baseDurationMinutes);
|
|
200
|
+
const nextDuration = resolvePosCustomTimeDefaultDurationMinutes((_normalizeDurationMin3 = normalizeDurationMinutesValue(context.draft.booking.duration)) !== null && _normalizeDurationMin3 !== void 0 ? _normalizeDurationMin3 : context.draft.booking.duration, baseDurationMinutes);
|
|
201
|
+
const changedFields = [];
|
|
202
|
+
if (nextStartTime !== context.draft.booking.startTime) changedFields.push("booking.startTime");
|
|
203
|
+
if (nextDuration !== context.draft.booking.duration) changedFields.push("booking.duration");
|
|
204
|
+
if (context.draft.booking.selectedCandidate) changedFields.push("booking.selectedCandidate");
|
|
205
|
+
if (context.draft.booking.commitCandidate) changedFields.push("booking.commitCandidate");
|
|
206
|
+
if (changedFields.length > 0 && nextStartTime) {
|
|
207
|
+
context.updateDraft({ booking: {
|
|
208
|
+
startTime: nextStartTime,
|
|
209
|
+
duration: nextDuration,
|
|
210
|
+
selectedCandidate: void 0,
|
|
211
|
+
commitCandidate: void 0
|
|
212
|
+
} }, {
|
|
213
|
+
changedFields,
|
|
214
|
+
sourceModuleKey: module.key,
|
|
215
|
+
sourceModuleType: "time"
|
|
216
|
+
});
|
|
217
|
+
yield refreshAvailabilityTimes(context, module, {
|
|
218
|
+
durationOverride: nextDuration,
|
|
219
|
+
startTimeOverride: nextStartTime,
|
|
220
|
+
selectionIntent: "custom"
|
|
221
|
+
});
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
177
225
|
if (candidates.length === 0) {
|
|
178
226
|
var _context$getModuleDat;
|
|
179
227
|
if (((_context$getModuleDat = context.getModuleData(module.key)) === null || _context$getModuleDat === void 0 ? void 0 : _context$getModuleDat.requestId) !== requestId) return;
|
|
@@ -182,7 +230,7 @@ const refreshAvailabilityTimes = function() {
|
|
|
182
230
|
timeSlots: [],
|
|
183
231
|
selectedCandidate: void 0,
|
|
184
232
|
slotStepMinutes: group === null || group === void 0 ? void 0 : group.slotStepMinutes,
|
|
185
|
-
|
|
233
|
+
posCustomTimeHydrationKey
|
|
186
234
|
});
|
|
187
235
|
return;
|
|
188
236
|
}
|
|
@@ -199,17 +247,42 @@ const refreshAvailabilityTimes = function() {
|
|
|
199
247
|
const draftStartTime = normalizeStartTimeValue(context.draft.booking.startTime);
|
|
200
248
|
const draftEndTime = normalizeStartTimeValue(context.draft.booking.endTime);
|
|
201
249
|
const requestedPosStartTime = requestedStartTime || draftStartTime;
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
250
|
+
const requestedPosDuration = (_ref4 = requestedDuration !== null && requestedDuration !== void 0 ? requestedDuration : normalizeDurationMinutesValue(context.draft.booking.duration)) !== null && _ref4 !== void 0 ? _ref4 : getDraftRangeDurationMinutes(context);
|
|
251
|
+
const restoredDraftCandidate = draftStartTime ? times.find((candidate) => isAvailabilityCandidateSelectable(candidate, allowUnavailable) && (posSessionAvailability ? isSameAvailabilityCandidateRange(candidate, {
|
|
252
|
+
date: selectedDate,
|
|
253
|
+
startTime: draftStartTime,
|
|
254
|
+
durationMinutes: requestedPosDuration
|
|
255
|
+
}) : isSameCandidateStart(candidate, selectedDate, draftStartTime) && (posDurationAvailability || normalizeStartTimeValue(candidate.endTime) === draftEndTime))) : void 0;
|
|
256
|
+
const restoredExistingCandidate = existingCandidate ? times.find((candidate) => isAvailabilityCandidateSelectable(candidate, allowUnavailable) && (candidate.key === existingCandidate.key || (posSessionAvailability ? candidate.source === existingCandidate.source && isSameAvailabilityCandidateRange(candidate, {
|
|
257
|
+
date: existingCandidate.date,
|
|
258
|
+
startTime: normalizeStartTimeValue(existingCandidate.startTime),
|
|
259
|
+
durationMinutes: getAvailabilityCandidateDurationMinutes(existingCandidate)
|
|
260
|
+
}) : posDurationAvailability && isSameCandidateStart(candidate, existingCandidate.date, normalizeStartTimeValue(existingCandidate.startTime))))) : void 0;
|
|
261
|
+
const fallbackOsCandidate = posCustomTimeAvailability && requestedPosStartTime ? candidates.find((candidate) => posSessionAvailability ? isSameAvailabilityCandidateRange(candidate, {
|
|
262
|
+
date: selectedDate,
|
|
263
|
+
startTime: requestedPosStartTime,
|
|
264
|
+
durationMinutes: requestedPosDuration
|
|
265
|
+
}) : isSameCandidateStart(candidate, selectedDate, requestedPosStartTime)) : void 0;
|
|
266
|
+
const customSelectionIntent = posCustomTimeAvailability && selectionIntent === "custom";
|
|
267
|
+
const restoredCandidate = resolvePosCustomTimeCandidate({
|
|
268
|
+
candidates: times.filter((candidate) => isAvailabilityCandidateSelectable(candidate, allowUnavailable)),
|
|
269
|
+
customSelectionIntent,
|
|
270
|
+
requestedCustomRange: customSelectionIntent && requestedPosStartTime && requestedPosDuration ? {
|
|
271
|
+
date: selectedDate,
|
|
272
|
+
startTime: requestedPosStartTime,
|
|
273
|
+
durationMinutes: requestedPosDuration
|
|
274
|
+
} : void 0,
|
|
275
|
+
restoredDraftCandidate,
|
|
276
|
+
restoredExistingCandidate,
|
|
277
|
+
fallbackCandidate: fallbackOsCandidate
|
|
278
|
+
});
|
|
206
279
|
const normallySelectableCandidates = times.filter((candidate) => isAvailabilityCandidateSelectable(candidate));
|
|
207
280
|
const selectableCandidates = normallySelectableCandidates.length > 0 || !allowUnavailable ? normallySelectableCandidates : times;
|
|
208
|
-
const initialCandidate = restoredCandidate || (
|
|
281
|
+
const initialCandidate = restoredCandidate || (posCustomTimeAvailability && Boolean(requestedPosStartTime && requestedPosDuration) ? void 0 : selectableCandidates[0]);
|
|
209
282
|
context.setModuleData(module.key, {
|
|
210
283
|
requestId,
|
|
211
284
|
slotStepMinutes: group === null || group === void 0 ? void 0 : group.slotStepMinutes,
|
|
212
|
-
timeSlots: times.map((candidate) => ({
|
|
285
|
+
timeSlots: (posSessionAvailability ? getSessionPresetCandidates(times) : times).map((candidate) => ({
|
|
213
286
|
id: candidate.key,
|
|
214
287
|
start_time: candidate.startTime,
|
|
215
288
|
end_time: candidate.endTime,
|
|
@@ -219,9 +292,9 @@ const refreshAvailabilityTimes = function() {
|
|
|
219
292
|
candidate
|
|
220
293
|
})),
|
|
221
294
|
selectedCandidate: initialCandidate,
|
|
222
|
-
|
|
295
|
+
posCustomTimeHydrationKey
|
|
223
296
|
});
|
|
224
|
-
const shouldWriteInitialCandidate = Boolean(initialCandidate) && (
|
|
297
|
+
const shouldWriteInitialCandidate = Boolean(initialCandidate) && (posCustomTimeAvailability || !existingCandidate || initialCandidate.key !== existingCandidate.key);
|
|
225
298
|
if (initialCandidate && shouldWriteInitialCandidate) {
|
|
226
299
|
const startAt = dayjs(initialCandidate.startAt);
|
|
227
300
|
const endAt = dayjs(initialCandidate.endAt);
|
|
@@ -249,8 +322,8 @@ const refreshAvailabilityTimes = function() {
|
|
|
249
322
|
}
|
|
250
323
|
if (initialCandidate && !hasCompiledResourceModule(context)) yield finalizeCandidateWithoutResourceStep(context, initialCandidate);
|
|
251
324
|
});
|
|
252
|
-
return function refreshAvailabilityTimes(_x3, _x4
|
|
253
|
-
return
|
|
325
|
+
return function refreshAvailabilityTimes(_x3, _x4) {
|
|
326
|
+
return _ref5.apply(this, arguments);
|
|
254
327
|
};
|
|
255
328
|
}();
|
|
256
329
|
const hasDurationValue = (value) => typeof value === "number" && value > 0 || typeof value === "string" && value.length > 0;
|
|
@@ -328,7 +401,7 @@ const getFlexibleDuration = (timeObj) => {
|
|
|
328
401
|
return (timeObj === null || timeObj === void 0 || (_timeObj$durationSlic = timeObj.durationSlicesBasedOnTime) === null || _timeObj$durationSlic === void 0 || (_timeObj$durationSlic = _timeObj$durationSlic.find((item) => typeof (item === null || item === void 0 ? void 0 : item.value) === "string" && item.value.startsWith("flexible_") && !item.disabled)) === null || _timeObj$durationSlic === void 0 ? void 0 : _timeObj$durationSlic.value) || (timeObj === null || timeObj === void 0 || (_timeObj$durationSlic2 = timeObj.durationSlicesBasedOnTime) === null || _timeObj$durationSlic2 === void 0 || (_timeObj$durationSlic2 = _timeObj$durationSlic2.find((item) => typeof (item === null || item === void 0 ? void 0 : item.value) === "string" && item.value.startsWith("flexible_"))) === null || _timeObj$durationSlic2 === void 0 ? void 0 : _timeObj$durationSlic2.value);
|
|
329
402
|
};
|
|
330
403
|
const resolveInitialDuration = (context) => {
|
|
331
|
-
var _context$services$get, _context$services, _serviceCacheItem$_ex, _serviceCacheItem$_ex2, _context$draft$produc, _context$draft$produc2, _timeObj$durationSlic3,
|
|
404
|
+
var _context$services$get, _context$services, _serviceCacheItem$_ex, _serviceCacheItem$_ex2, _context$draft$produc, _context$draft$produc2, _timeObj$durationSlic3, _ref6, _configuredOption$val, _timeObj$durationSlic4;
|
|
332
405
|
if (hasDurationValue(context.draft.booking.duration)) return context.draft.booking.duration;
|
|
333
406
|
const serviceCacheItem = (_context$services$get = (_context$services = context.services).getCurrentCacheItem) === null || _context$services$get === void 0 ? void 0 : _context$services$get.call(_context$services);
|
|
334
407
|
const existingDuration = normalizeSelectionDuration((_serviceCacheItem$_ex = serviceCacheItem === null || serviceCacheItem === void 0 || (_serviceCacheItem$_ex2 = serviceCacheItem._extend) === null || _serviceCacheItem$_ex2 === void 0 ? void 0 : _serviceCacheItem$_ex2.duration) !== null && _serviceCacheItem$_ex !== void 0 ? _serviceCacheItem$_ex : (_context$draft$produc = context.draft.productData) === null || _context$draft$produc === void 0 || (_context$draft$produc = _context$draft$produc._extend) === null || _context$draft$produc === void 0 ? void 0 : _context$draft$produc.duration);
|
|
@@ -340,7 +413,7 @@ const resolveInitialDuration = (context) => {
|
|
|
340
413
|
if (hasDurationValue(normalizedDuration)) return normalizedDuration;
|
|
341
414
|
const configuredValue = productDuration === null || productDuration === void 0 ? void 0 : productDuration.value;
|
|
342
415
|
const configuredOption = timeObj === null || timeObj === void 0 || (_timeObj$durationSlic3 = timeObj.durationSlicesBasedOnTime) === null || _timeObj$durationSlic3 === void 0 ? void 0 : _timeObj$durationSlic3.find((item) => (item === null || item === void 0 ? void 0 : item.value) == configuredValue);
|
|
343
|
-
return (
|
|
416
|
+
return (_ref6 = (_configuredOption$val = configuredOption === null || configuredOption === void 0 ? void 0 : configuredOption.value) !== null && _configuredOption$val !== void 0 ? _configuredOption$val : timeObj === null || timeObj === void 0 || (_timeObj$durationSlic4 = timeObj.durationSlicesBasedOnTime) === null || _timeObj$durationSlic4 === void 0 || (_timeObj$durationSlic4 = _timeObj$durationSlic4[0]) === null || _timeObj$durationSlic4 === void 0 ? void 0 : _timeObj$durationSlic4.value) !== null && _ref6 !== void 0 ? _ref6 : null;
|
|
344
417
|
};
|
|
345
418
|
const deriveTimeBooking = (context, startTime, duration) => {
|
|
346
419
|
let nextDuration = duration;
|
|
@@ -387,7 +460,7 @@ const refreshTimeModule = (context, module) => {
|
|
|
387
460
|
});
|
|
388
461
|
};
|
|
389
462
|
const TimeFlowModuleComponent = ({ context, module, registerHandle }) => {
|
|
390
|
-
var _context$moduleState$2, _context$moduleState$3, _context$moduleState$4, _context$
|
|
463
|
+
var _context$moduleState$2, _context$moduleState$3, _context$moduleState$4, _context$hostContext2, _options$slice, _durationProps$select2, _options$durationSele2;
|
|
391
464
|
const options = getModuleOptions(module);
|
|
392
465
|
const unsupportedReason = getUnsupportedBookingFlowReason(context.draft.productData);
|
|
393
466
|
const required = options.required !== false;
|
|
@@ -395,7 +468,9 @@ const TimeFlowModuleComponent = ({ context, module, registerHandle }) => {
|
|
|
395
468
|
const duration = context.draft.booking.duration;
|
|
396
469
|
const useAvailability = options.mode === "availability";
|
|
397
470
|
const productDurationMinutes = getProductDurationMinutes(context);
|
|
398
|
-
const usePosDurationAvailability = useAvailability && isPosDurationAvailabilityContext(context)
|
|
471
|
+
const usePosDurationAvailability = useAvailability && isPosDurationAvailabilityContext(context);
|
|
472
|
+
const usePosSessionAvailability = useAvailability && isPosSessionAvailabilityContext(context);
|
|
473
|
+
const usePosCustomTimeAvailability = usePosDurationAvailability || usePosSessionAvailability;
|
|
399
474
|
const availability = useAvailability ? context.services.availability : void 0;
|
|
400
475
|
const availabilityData = context.getModuleData(module.key);
|
|
401
476
|
const capacityDisplaySettings = getCapacityDisplaySettings(context.hostContext);
|
|
@@ -405,7 +480,7 @@ const TimeFlowModuleComponent = ({ context, module, registerHandle }) => {
|
|
|
405
480
|
const dateModule = context.steps.flatMap((step) => step.modules).find((item) => item.type === "date");
|
|
406
481
|
const isDateModuleLoading = dateModule ? ((_context$moduleState$3 = context.moduleState[dateModule.key]) === null || _context$moduleState$3 === void 0 ? void 0 : _context$moduleState$3.status) === "loading" : false;
|
|
407
482
|
const hasNoSelectableAvailabilityDate = Boolean(useAvailability && dateModule && ((_context$moduleState$4 = context.moduleState[dateModule.key]) === null || _context$moduleState$4 === void 0 ? void 0 : _context$moduleState$4.status) === "ready" && !isAvailabilityDateReadyForTime(context));
|
|
408
|
-
const configuredSlice = (_context$
|
|
483
|
+
const configuredSlice = (_context$hostContext2 = context.hostContext) === null || _context$hostContext2 === void 0 || (_context$hostContext2 = _context$hostContext2.bookingConfig) === null || _context$hostContext2 === void 0 || (_context$hostContext2 = _context$hostContext2.config) === null || _context$hostContext2 === void 0 || (_context$hostContext2 = _context$hostContext2.basic) === null || _context$hostContext2 === void 0 ? void 0 : _context$hostContext2.service_time;
|
|
409
484
|
const slice = (_options$slice = options.slice) !== null && _options$slice !== void 0 ? _options$slice : typeof configuredSlice === "object" ? configuredSlice === null || configuredSlice === void 0 ? void 0 : configuredSlice.value : configuredSlice;
|
|
410
485
|
const resourceModule = context.steps.flatMap((step) => step.modules).find((item) => item.type === "resource");
|
|
411
486
|
const resourceModuleData = resourceModule ? context.getModuleData(resourceModule.key) : void 0;
|
|
@@ -426,14 +501,16 @@ const TimeFlowModuleComponent = ({ context, module, registerHandle }) => {
|
|
|
426
501
|
resourceModuleData === null || resourceModuleData === void 0 ? void 0 : resourceModuleData.cacheItem,
|
|
427
502
|
resourceModuleData === null || resourceModuleData === void 0 ? void 0 : resourceModuleData.requestId
|
|
428
503
|
]);
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
504
|
+
const posCustomTimeBaseMinutes = usePosDurationAvailability ? resolvePosCustomTimeBaseMinutes(productDurationMinutes, availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.slotStepMinutes, slice) : usePosSessionAvailability ? availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.slotStepMinutes : null;
|
|
505
|
+
const posCustomTimeObj = useMemo(() => usePosCustomTimeAvailability && posCustomTimeBaseMinutes ? buildPosDurationTimeObj(runtime.timeObj, posCustomTimeBaseMinutes, duration) : runtime.timeObj, [
|
|
506
|
+
usePosCustomTimeAvailability,
|
|
507
|
+
posCustomTimeBaseMinutes,
|
|
432
508
|
runtime.timeObj,
|
|
433
509
|
duration
|
|
434
510
|
]);
|
|
435
511
|
const durationProps = runtime.durationProps;
|
|
436
512
|
const applyAvailabilityCandidate = (candidate) => {
|
|
513
|
+
if (!availabilityData) return;
|
|
437
514
|
context.setModuleData(module.key, _objectSpread2(_objectSpread2({}, availabilityData), {}, { selectedCandidate: candidate }));
|
|
438
515
|
if (!candidate) return;
|
|
439
516
|
const startAt = dayjs(candidate.startAt);
|
|
@@ -508,7 +585,7 @@ const TimeFlowModuleComponent = ({ context, module, registerHandle }) => {
|
|
|
508
585
|
}, [handle, registerHandle]);
|
|
509
586
|
useEffect(() => {
|
|
510
587
|
var _context$draft$bookin2;
|
|
511
|
-
if (!
|
|
588
|
+
if (!usePosCustomTimeAvailability || !availability) return;
|
|
512
589
|
if (!startTime || !hasDurationValue(duration)) return;
|
|
513
590
|
if (availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.selectedCandidate) return;
|
|
514
591
|
if (moduleStatus === "loading") return;
|
|
@@ -517,12 +594,16 @@ const TimeFlowModuleComponent = ({ context, module, registerHandle }) => {
|
|
|
517
594
|
const requestedStartTime = getAvailabilityStartTimeOverride(context);
|
|
518
595
|
if (!selectedDate || !requestedDuration || !requestedStartTime) return;
|
|
519
596
|
const hydrationKey = `${selectedDate}|${requestedStartTime}|${requestedDuration}`;
|
|
520
|
-
if ((availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.
|
|
597
|
+
if ((availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.posCustomTimeHydrationKey) === hydrationKey) return;
|
|
521
598
|
context.setModuleStatus(module.key, "loading");
|
|
522
|
-
refreshAvailabilityTimes(context, module,
|
|
599
|
+
refreshAvailabilityTimes(context, module, {
|
|
600
|
+
durationOverride: duration,
|
|
601
|
+
startTimeOverride: startTime,
|
|
602
|
+
selectionIntent: "custom"
|
|
603
|
+
}).then(() => context.setModuleStatus(module.key, "ready")).catch((error) => context.setModuleStatus(module.key, "error", error instanceof Error ? error.message : String(error), error));
|
|
523
604
|
}, [
|
|
524
605
|
availability,
|
|
525
|
-
availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.
|
|
606
|
+
availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.posCustomTimeHydrationKey,
|
|
526
607
|
availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.selectedCandidate,
|
|
527
608
|
context,
|
|
528
609
|
context.draft.booking.startDate,
|
|
@@ -530,8 +611,23 @@ const TimeFlowModuleComponent = ({ context, module, registerHandle }) => {
|
|
|
530
611
|
module,
|
|
531
612
|
moduleStatus,
|
|
532
613
|
startTime,
|
|
533
|
-
|
|
614
|
+
usePosCustomTimeAvailability
|
|
534
615
|
]);
|
|
616
|
+
const renderAvailabilityTimeSelector = () => /* @__PURE__ */ React.createElement(TimeResourceSelector, {
|
|
617
|
+
className: classNames("selection-flow-time-resource-selector", `selection-flow-time-resource-selector--columns-${timeSlotColumns}`),
|
|
618
|
+
displayMode: "plain",
|
|
619
|
+
timeSlots: hasNoSelectableAvailabilityDate ? [] : (availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.timeSlots) || [],
|
|
620
|
+
defaultSelectFirst: false,
|
|
621
|
+
showEmptySelectionError: false,
|
|
622
|
+
columns: timeSlotColumns,
|
|
623
|
+
capacityDisplaySettings,
|
|
624
|
+
allowUnavailableSelection: context.services.allowUnavailableBookingSelection === true,
|
|
625
|
+
value: !hasNoSelectableAvailabilityDate && (availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.selectedCandidate) ? [availabilityData.selectedCandidate.key] : [],
|
|
626
|
+
onSelectionChange: (items) => {
|
|
627
|
+
var _items$;
|
|
628
|
+
applyAvailabilityCandidate((_items$ = items[0]) === null || _items$ === void 0 ? void 0 : _items$.candidate);
|
|
629
|
+
}
|
|
630
|
+
});
|
|
535
631
|
if (unsupportedReason) return /* @__PURE__ */ React.createElement(Alert, {
|
|
536
632
|
type: "error",
|
|
537
633
|
showIcon: true,
|
|
@@ -545,15 +641,25 @@ const TimeFlowModuleComponent = ({ context, module, registerHandle }) => {
|
|
|
545
641
|
if (useAvailability) {
|
|
546
642
|
if (isDateModuleLoading) return null;
|
|
547
643
|
if (!hasNoSelectableAvailabilityDate && (moduleStatus === "loading" || !(availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.timeSlots))) return /* @__PURE__ */ React.createElement(SkuDetailLoadingPanel, null);
|
|
548
|
-
if (
|
|
549
|
-
var _availabilityData$slo, _durationProps$select, _options$durationSele;
|
|
644
|
+
if (usePosCustomTimeAvailability) {
|
|
645
|
+
var _availabilityData$slo, _availabilityData$tim, _durationProps$select, _options$durationSele;
|
|
646
|
+
if (usePosSessionAvailability && !posCustomTimeBaseMinutes) return /* @__PURE__ */ React.createElement(Alert, {
|
|
647
|
+
type: "error",
|
|
648
|
+
showIcon: true,
|
|
649
|
+
message: selectionFlowText("pisell2.text.sku.detail.modal.validation.availability.wait")
|
|
650
|
+
});
|
|
550
651
|
const selectedCandidate = availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.selectedCandidate;
|
|
551
|
-
const posStartTimeSlice = (_availabilityData$slo = availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.slotStepMinutes) !== null && _availabilityData$slo !== void 0 ? _availabilityData$slo : slice;
|
|
652
|
+
const posStartTimeSlice = usePosSessionAvailability ? availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.slotStepMinutes : (_availabilityData$slo = availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.slotStepMinutes) !== null && _availabilityData$slo !== void 0 ? _availabilityData$slo : slice;
|
|
552
653
|
selectedCandidate && context.services.allowUnavailableBookingSelection === true && isAvailabilityCandidateSelectable(selectedCandidate);
|
|
654
|
+
const showCandidateCards = shouldShowPosCustomTimeCandidateCards({
|
|
655
|
+
isSessionAvailability: usePosSessionAvailability,
|
|
656
|
+
isDurationAvailability: usePosDurationAvailability,
|
|
657
|
+
candidateCount: (availabilityData === null || availabilityData === void 0 || (_availabilityData$tim = availabilityData.timeSlots) === null || _availabilityData$tim === void 0 ? void 0 : _availabilityData$tim.length) || 0
|
|
658
|
+
});
|
|
553
659
|
return /* @__PURE__ */ React.createElement(Space, {
|
|
554
660
|
direction: "vertical",
|
|
555
661
|
style: { width: "100%" }
|
|
556
|
-
}, /* @__PURE__ */ React.createElement("div", { style: { fontWeight: 500 } }, selectionFlowText("pisell2.text.start_time")), /* @__PURE__ */ React.createElement(SelectTime, {
|
|
662
|
+
}, showCandidateCards ? renderAvailabilityTimeSelector() : null, /* @__PURE__ */ React.createElement("div", { style: { fontWeight: 500 } }, selectionFlowText("pisell2.text.start_time")), /* @__PURE__ */ React.createElement(SelectTime, {
|
|
557
663
|
value: startTime || "",
|
|
558
664
|
slice: posStartTimeSlice,
|
|
559
665
|
theme: options.theme,
|
|
@@ -577,10 +683,14 @@ const TimeFlowModuleComponent = ({ context, module, registerHandle }) => {
|
|
|
577
683
|
sourceModuleType: "time"
|
|
578
684
|
});
|
|
579
685
|
context.setModuleStatus(module.key, "loading");
|
|
580
|
-
refreshAvailabilityTimes(context, module,
|
|
686
|
+
refreshAvailabilityTimes(context, module, {
|
|
687
|
+
durationOverride: duration,
|
|
688
|
+
startTimeOverride: nextStartTime,
|
|
689
|
+
selectionIntent: "custom"
|
|
690
|
+
}).then(() => context.setModuleStatus(module.key, "ready")).catch((error) => context.setModuleStatus(module.key, "error", error instanceof Error ? error.message : String(error), error));
|
|
581
691
|
}
|
|
582
692
|
}), /* @__PURE__ */ React.createElement("div", { style: { fontWeight: 500 } }, selectionFlowText("pisell2.text.duration")), /* @__PURE__ */ React.createElement(Duration, _objectSpread2(_objectSpread2(_objectSpread2({}, durationProps), options.durationProps), {}, {
|
|
583
|
-
timeObj:
|
|
693
|
+
timeObj: posCustomTimeObj,
|
|
584
694
|
value: duration !== null && duration !== void 0 ? duration : void 0,
|
|
585
695
|
selectProps: _objectSpread2(_objectSpread2(_objectSpread2({}, (durationProps === null || durationProps === void 0 ? void 0 : durationProps.selectProps) || {}), options.durationSelectProps), {}, { style: _objectSpread2(_objectSpread2({ width: "100%" }, (durationProps === null || durationProps === void 0 || (_durationProps$select = durationProps.selectProps) === null || _durationProps$select === void 0 ? void 0 : _durationProps$select.style) || {}), ((_options$durationSele = options.durationSelectProps) === null || _options$durationSele === void 0 ? void 0 : _options$durationSele.style) || {}) }),
|
|
586
696
|
style: { width: "100%" },
|
|
@@ -600,25 +710,15 @@ const TimeFlowModuleComponent = ({ context, module, registerHandle }) => {
|
|
|
600
710
|
sourceModuleType: "time"
|
|
601
711
|
});
|
|
602
712
|
context.setModuleStatus(module.key, "loading");
|
|
603
|
-
refreshAvailabilityTimes(context, module,
|
|
713
|
+
refreshAvailabilityTimes(context, module, {
|
|
714
|
+
durationOverride: nextDuration,
|
|
715
|
+
startTimeOverride: startTime,
|
|
716
|
+
selectionIntent: "custom"
|
|
717
|
+
}).then(() => context.setModuleStatus(module.key, "ready")).catch((error) => context.setModuleStatus(module.key, "error", error instanceof Error ? error.message : String(error), error));
|
|
604
718
|
}
|
|
605
719
|
})));
|
|
606
720
|
}
|
|
607
|
-
return
|
|
608
|
-
className: classNames("selection-flow-time-resource-selector", `selection-flow-time-resource-selector--columns-${timeSlotColumns}`),
|
|
609
|
-
displayMode: "plain",
|
|
610
|
-
timeSlots: hasNoSelectableAvailabilityDate ? [] : (availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.timeSlots) || [],
|
|
611
|
-
defaultSelectFirst: false,
|
|
612
|
-
showEmptySelectionError: false,
|
|
613
|
-
columns: timeSlotColumns,
|
|
614
|
-
capacityDisplaySettings,
|
|
615
|
-
allowUnavailableSelection: context.services.allowUnavailableBookingSelection === true,
|
|
616
|
-
value: !hasNoSelectableAvailabilityDate && (availabilityData === null || availabilityData === void 0 ? void 0 : availabilityData.selectedCandidate) ? [availabilityData.selectedCandidate.key] : [],
|
|
617
|
-
onSelectionChange: (items) => {
|
|
618
|
-
var _items$;
|
|
619
|
-
applyAvailabilityCandidate((_items$ = items[0]) === null || _items$ === void 0 ? void 0 : _items$.candidate);
|
|
620
|
-
}
|
|
621
|
-
});
|
|
721
|
+
return renderAvailabilityTimeSelector();
|
|
622
722
|
}
|
|
623
723
|
if (!SelectTime) return /* @__PURE__ */ React.createElement(Alert, {
|
|
624
724
|
type: "error",
|
|
@@ -700,8 +800,8 @@ const timeFlowModule = {
|
|
|
700
800
|
"booking.capacity"
|
|
701
801
|
],
|
|
702
802
|
isApplicable: (context) => {
|
|
703
|
-
var _context$
|
|
704
|
-
return !isNormalProductByDurationSchedule(context.draft.productData) && ((_context$
|
|
803
|
+
var _context$hostContext3;
|
|
804
|
+
return !isNormalProductByDurationSchedule(context.draft.productData) && ((_context$hostContext3 = context.hostContext) === null || _context$hostContext3 === void 0 ? void 0 : _context$hostContext3.renderType) !== "eventBooking";
|
|
705
805
|
},
|
|
706
806
|
canInitialize: (context, module) => {
|
|
707
807
|
const unsupportedReason = getUnsupportedBookingFlowReason(context.draft.productData);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import dayjs from "dayjs";
|
|
2
|
+
//#region src/pro/skuDetailModal/flow/modules/time/posCustomTime.ts
|
|
3
|
+
const isFlexibleDurationValue = (value) => {
|
|
4
|
+
if (typeof value === "string") {
|
|
5
|
+
const text = value.trim().toLowerCase();
|
|
6
|
+
return text === "flexible" || text.startsWith("flexible_");
|
|
7
|
+
}
|
|
8
|
+
return Boolean(value && typeof value === "object" && String(value.type || "").trim().toLowerCase() === "flexible");
|
|
9
|
+
};
|
|
10
|
+
const resolvePosCustomTimeBaseMinutes = (...values) => {
|
|
11
|
+
for (const value of values) {
|
|
12
|
+
const minutes = Number(value);
|
|
13
|
+
if (Number.isFinite(minutes) && minutes > 0) return Math.max(1, Math.floor(minutes));
|
|
14
|
+
}
|
|
15
|
+
return 30;
|
|
16
|
+
};
|
|
17
|
+
const resolvePosCustomTimeDefaultStartTime = (currentValue, sliceMinutes, now) => {
|
|
18
|
+
if (typeof currentValue === "string") {
|
|
19
|
+
const matched = currentValue.trim().match(/^([01]\d|2[0-3]):([0-5]\d)(?::[0-5]\d)?$/);
|
|
20
|
+
if (matched) return `${matched[1]}:${matched[2]}`;
|
|
21
|
+
}
|
|
22
|
+
const current = now === void 0 ? dayjs() : dayjs(now);
|
|
23
|
+
if (!current.isValid()) return null;
|
|
24
|
+
const step = Math.min(resolvePosCustomTimeBaseMinutes(sliceMinutes), 1440);
|
|
25
|
+
const minuteOfDay = current.hour() * 60 + current.minute();
|
|
26
|
+
const alignedMinute = Math.floor(minuteOfDay / step) * step;
|
|
27
|
+
const hours = Math.floor(alignedMinute / 60);
|
|
28
|
+
const minutes = alignedMinute % 60;
|
|
29
|
+
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
|
|
30
|
+
};
|
|
31
|
+
const resolvePosCustomTimeDefaultDurationMinutes = (currentValue, baseDurationMinutes) => {
|
|
32
|
+
if (typeof currentValue === "string") {
|
|
33
|
+
const flexibleMatch = currentValue.trim().toLowerCase().match(/^flexible_(\d+(?:\.\d+)?)$/);
|
|
34
|
+
if (flexibleMatch) return Math.max(1, Math.floor(Number(flexibleMatch[1])));
|
|
35
|
+
}
|
|
36
|
+
const currentMinutes = Number(currentValue);
|
|
37
|
+
if (Number.isFinite(currentMinutes) && currentMinutes > 0) return Math.max(1, Math.floor(currentMinutes));
|
|
38
|
+
return resolvePosCustomTimeBaseMinutes(baseDurationMinutes);
|
|
39
|
+
};
|
|
40
|
+
const shouldShowPosCustomTimeCandidateCards = (params) => params.isSessionAvailability || params.isDurationAvailability && params.candidateCount > 0;
|
|
41
|
+
const getAvailabilityCandidateDurationMinutes = (candidate) => {
|
|
42
|
+
const startAt = dayjs(candidate.startAt);
|
|
43
|
+
const endAt = dayjs(candidate.endAt);
|
|
44
|
+
if (!startAt.isValid() || !endAt.isValid()) return null;
|
|
45
|
+
const duration = endAt.diff(startAt, "minute");
|
|
46
|
+
return duration > 0 ? duration : null;
|
|
47
|
+
};
|
|
48
|
+
const isSameAvailabilityCandidateRange = (candidate, params) => Boolean(params.startTime) && candidate.date === params.date && candidate.startTime.slice(0, 5) === params.startTime && Boolean(params.durationMinutes) && getAvailabilityCandidateDurationMinutes(candidate) === params.durationMinutes;
|
|
49
|
+
const resolvePosCustomTimeCandidate = (params) => {
|
|
50
|
+
const requestedCustomRange = params.requestedCustomRange;
|
|
51
|
+
if (params.customSelectionIntent) {
|
|
52
|
+
if (!requestedCustomRange) return void 0;
|
|
53
|
+
return params.candidates.find((candidate) => candidate.source === "duration_window" && isSameAvailabilityCandidateRange(candidate, requestedCustomRange));
|
|
54
|
+
}
|
|
55
|
+
return params.restoredDraftCandidate || params.restoredExistingCandidate || params.fallbackCandidate;
|
|
56
|
+
};
|
|
57
|
+
const getSessionPresetCandidates = (candidates) => candidates.filter((candidate) => candidate.source === "session_schedule");
|
|
58
|
+
//#endregion
|
|
59
|
+
export { getAvailabilityCandidateDurationMinutes, getSessionPresetCandidates, isFlexibleDurationValue, isSameAvailabilityCandidateRange, resolvePosCustomTimeBaseMinutes, resolvePosCustomTimeCandidate, resolvePosCustomTimeDefaultDurationMinutes, resolvePosCustomTimeDefaultStartTime, shouldShowPosCustomTimeCandidateCards };
|