@pisell/private-materials 6.11.659 → 6.11.661

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.
@@ -10,7 +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, getPosFlexibleDurationPresetCandidates, getSessionPresetCandidates, isFlexibleDurationValue, isSameAvailabilityCandidateRange, resolvePosCustomTimeBaseMinutes, resolvePosCustomTimeCandidate, resolvePosCustomTimeDefaultDurationMinutes, resolvePosCustomTimeDefaultStartTime, resolvePosFlexibleBusinessDurationMinutes, resolvePosFlexibleDurationInitialCandidate, shouldResetPosFlexibleTimeForDate, shouldShowPosCustomTimeCandidateCards } from "./posCustomTime.js";
13
+ import { getAvailabilityCandidateDurationMinutes, getPosFlexibleDurationPresetCandidates, getSessionPresetCandidates, isFlexibleDurationValue, isSameAvailabilityCandidateRange, resolvePosCustomTimeBaseMinutes, resolvePosCustomTimeCandidate, resolvePosCustomTimeDefaultDurationMinutes, resolvePosCustomTimeDefaultStartTime, resolvePosFlexibleDurationInitialCandidate, shouldResetPosFlexibleTimeForDate, shouldShowPosCustomTimeCandidateCards } from "./posCustomTime.js";
14
14
  import dayjs from "dayjs";
15
15
  import React, { useEffect, useMemo } from "react";
16
16
  import { Alert, Space } from "antd";
@@ -191,15 +191,15 @@ const refreshAvailabilityTimes = function() {
191
191
  }, requestedDuration ? _objectSpread2({ durationMinutesByProductId: { [String(availability.productId)]: requestedDuration } }, requestedStartTime ? { durationStartTimesByProductId: { [String(availability.productId)]: [requestedStartTime] } } : {}) : {}))).find((item) => String(item.productId) === String(availability.productId));
192
192
  const candidates = (group === null || group === void 0 ? void 0 : group.ranges) || [];
193
193
  const product = context.draft.productData;
194
- if (posDurationAvailability && selectionIntent === "restore" && isFlexibleDurationValue(product === null || product === void 0 ? void 0 : product.duration)) {
194
+ if (posDurationAvailability && selectionIntent === "restore" && isFlexibleDurationValue(product === null || product === void 0 ? void 0 : product.duration) && candidates.length === 0) {
195
195
  var _context$hostContext, _moduleOptions$slice, _context$draft$bookin2, _normalizeDurationMin3;
196
196
  const moduleOptions = getModuleOptions(module);
197
197
  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;
198
198
  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;
199
- const baseDurationMinutes = resolvePosCustomTimeBaseMinutes(group === null || group === void 0 ? void 0 : group.slotStepMinutes, fallbackSlice);
199
+ const baseDurationMinutes = resolvePosCustomTimeBaseMinutes(getProductDurationMinutes(context), group === null || group === void 0 ? void 0 : group.slotStepMinutes, fallbackSlice);
200
200
  const resetForSelectedDate = shouldResetPosFlexibleTimeForDate((_context$draft$bookin2 = context.draft.booking.selectedCandidate) !== null && _context$draft$bookin2 !== void 0 ? _context$draft$bookin2 : previousTimeData === null || previousTimeData === void 0 ? void 0 : previousTimeData.selectedCandidate, selectedDate);
201
201
  const nextStartTime = resolvePosCustomTimeDefaultStartTime(resetForSelectedDate ? null : context.draft.booking.startTime, baseDurationMinutes);
202
- const nextDuration = resolvePosCustomTimeDefaultDurationMinutes(resetForSelectedDate ? product === null || product === void 0 ? void 0 : product.duration : (_normalizeDurationMin3 = normalizeDurationMinutesValue(context.draft.booking.duration)) !== null && _normalizeDurationMin3 !== void 0 ? _normalizeDurationMin3 : context.draft.booking.duration, baseDurationMinutes, context.services.selectionFlowMode === "edit" ? void 0 : resolvePosFlexibleBusinessDurationMinutes(nextStartTime, (group === null || group === void 0 ? void 0 : group.operatingEndAt) ? dayjs(group.operatingEndAt).format("HH:mm") : void 0));
202
+ const nextDuration = resolvePosCustomTimeDefaultDurationMinutes(resetForSelectedDate ? product === null || product === void 0 ? void 0 : product.duration : (_normalizeDurationMin3 = normalizeDurationMinutesValue(context.draft.booking.duration)) !== null && _normalizeDurationMin3 !== void 0 ? _normalizeDurationMin3 : context.draft.booking.duration, baseDurationMinutes);
203
203
  const changedFields = [];
204
204
  if (nextStartTime !== context.draft.booking.startTime) changedFields.push("booking.startTime");
205
205
  if (nextDuration !== context.draft.booking.duration) changedFields.push("booking.duration");
@@ -292,7 +292,7 @@ const refreshAvailabilityTimes = function() {
292
292
  restoredCandidate,
293
293
  fallbackCandidate,
294
294
  preferPreset: preferPosFlexiblePreset,
295
- minimumPresetStartAt: preferPosFlexiblePreset ? dayjs().toISOString() : void 0
295
+ allowRestoredFallback: fallbackSelectionIntent
296
296
  }) : restoredCandidate || fallbackCandidate;
297
297
  context.setModuleData(module.key, {
298
298
  requestId,
@@ -28,24 +28,9 @@ const resolvePosCustomTimeDefaultStartTime = (currentValue, sliceMinutes, now) =
28
28
  const minutes = alignedMinute % 60;
29
29
  return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
30
30
  };
31
- const resolvePosFlexibleBusinessDurationMinutes = (startTime, closingTime) => {
32
- const toMinuteOfDay = (value) => {
33
- if (typeof value !== "string") return null;
34
- const matched = value.trim().match(/^([01]\d|2[0-3]):([0-5]\d)(?::[0-5]\d)?$/);
35
- if (!matched) return null;
36
- return Number(matched[1]) * 60 + Number(matched[2]);
37
- };
38
- const startMinute = toMinuteOfDay(startTime);
39
- const closingMinute = toMinuteOfDay(closingTime);
40
- if (startMinute === null || closingMinute === null) return null;
41
- const duration = closingMinute > startMinute ? closingMinute - startMinute : closingMinute < startMinute ? closingMinute + 1440 - startMinute : 0;
42
- return duration > 0 ? duration : null;
43
- };
44
31
  const shouldResetPosFlexibleTimeForDate = (candidate, selectedDate) => Boolean(candidate && candidate.date !== selectedDate);
45
- const resolvePosCustomTimeDefaultDurationMinutes = (currentValue, baseDurationMinutes, flexibleDefaultMinutes) => {
32
+ const resolvePosCustomTimeDefaultDurationMinutes = (currentValue, baseDurationMinutes) => {
46
33
  if (isFlexibleDurationValue(currentValue)) {
47
- const flexibleMinutes = Number(flexibleDefaultMinutes);
48
- if (Number.isFinite(flexibleMinutes) && flexibleMinutes > 0) return Math.max(1, Math.floor(flexibleMinutes));
49
34
  if (typeof currentValue === "string") {
50
35
  const flexibleMatch = currentValue.trim().toLowerCase().match(/^flexible_(\d+(?:\.\d+)?)$/);
51
36
  if (flexibleMatch) return Math.max(1, Math.floor(Number(flexibleMatch[1])));
@@ -79,15 +64,11 @@ const getPosFlexibleDurationPresetCandidates = (candidates, requestedCustomRange
79
64
  return candidates.filter((candidate) => !isSameAvailabilityCandidateRange(candidate, requestedCustomRange));
80
65
  };
81
66
  const resolvePosFlexibleDurationInitialCandidate = (params) => {
82
- const minimumPresetStartAt = params.minimumPresetStartAt === void 0 ? null : dayjs(params.minimumPresetStartAt);
83
67
  const firstAvailablePreset = params.presetCandidates.find((candidate) => {
84
- if (!((!candidate.status || candidate.status === "available" || candidate.status === "limited") && !(typeof candidate.maxPartySize === "number" && candidate.maxPartySize <= 0))) return false;
85
- if (!(minimumPresetStartAt === null || minimumPresetStartAt === void 0 ? void 0 : minimumPresetStartAt.isValid())) return true;
86
- const candidateStartAt = dayjs(candidate.startAt);
87
- return candidateStartAt.isValid() && !candidateStartAt.isBefore(minimumPresetStartAt);
68
+ return (!candidate.status || candidate.status === "available" || candidate.status === "limited") && !(typeof candidate.maxPartySize === "number" && candidate.maxPartySize <= 0);
88
69
  });
89
- if (params.preferPreset && firstAvailablePreset) return firstAvailablePreset;
70
+ if (params.preferPreset) return firstAvailablePreset || (params.allowRestoredFallback ? params.restoredCandidate : void 0);
90
71
  return params.restoredCandidate || params.fallbackCandidate;
91
72
  };
92
73
  //#endregion
93
- export { getAvailabilityCandidateDurationMinutes, getPosFlexibleDurationPresetCandidates, getSessionPresetCandidates, isFlexibleDurationValue, isSameAvailabilityCandidateRange, resolvePosCustomTimeBaseMinutes, resolvePosCustomTimeCandidate, resolvePosCustomTimeDefaultDurationMinutes, resolvePosCustomTimeDefaultStartTime, resolvePosFlexibleBusinessDurationMinutes, resolvePosFlexibleDurationInitialCandidate, shouldResetPosFlexibleTimeForDate, shouldShowPosCustomTimeCandidateCards };
74
+ export { getAvailabilityCandidateDurationMinutes, getPosFlexibleDurationPresetCandidates, getSessionPresetCandidates, isFlexibleDurationValue, isSameAvailabilityCandidateRange, resolvePosCustomTimeBaseMinutes, resolvePosCustomTimeCandidate, resolvePosCustomTimeDefaultDurationMinutes, resolvePosCustomTimeDefaultStartTime, resolvePosFlexibleDurationInitialCandidate, shouldResetPosFlexibleTimeForDate, shouldShowPosCustomTimeCandidateCards };
@@ -24,5 +24,7 @@ const getPosAutoResolutionDraftKey = (draft) => {
24
24
  });
25
25
  };
26
26
  const shouldDirectlyConfirmPosSelectionFlow = ({ eligible, status, currentStepIndex }) => eligible && status === "resolved" && currentStepIndex === 0;
27
+ const shouldPreparePosSelectionFlowOnConfirm = ({ eligible, currentStepIndex, abandoned }) => eligible && currentStepIndex === 0 && !abandoned;
28
+ const isCurrentPosAutoResolutionRun = ({ expectedRunId, currentRunId, expectedOpenTaskId, currentOpenTaskId, expectedDraftKey, currentDraftKey, abandoned, currentStepIndex }) => expectedRunId === currentRunId && expectedOpenTaskId === currentOpenTaskId && expectedDraftKey === currentDraftKey && !abandoned && currentStepIndex === 0;
27
29
  //#endregion
28
- export { getPosAutoResolutionDraftKey, isPosCreateAutoResolutionCandidate, shouldDirectlyConfirmPosSelectionFlow };
30
+ export { getPosAutoResolutionDraftKey, isCurrentPosAutoResolutionRun, isPosCreateAutoResolutionCandidate, shouldDirectlyConfirmPosSelectionFlow, shouldPreparePosSelectionFlowOnConfirm };
@@ -35,7 +35,7 @@ import resolveBookingPriceDisplayAmounts, { canOpenBookingManualPriceChange } fr
35
35
  import { normalizeSelectionDuration } from "./flow/modules/time/index.js";
36
36
  import { flowModuleRegistry } from "./flow/registry.js";
37
37
  import SkuDetailSelectionFlowView from "./flow/SkuDetailSelectionFlowView.js";
38
- import { getPosAutoResolutionDraftKey, isPosCreateAutoResolutionCandidate, shouldDirectlyConfirmPosSelectionFlow } from "./flow/posAutoResolution.js";
38
+ import { getPosAutoResolutionDraftKey, isCurrentPosAutoResolutionRun, isPosCreateAutoResolutionCandidate, shouldDirectlyConfirmPosSelectionFlow, shouldPreparePosSelectionFlowOnConfirm } from "./flow/posAutoResolution.js";
39
39
  import dayjs from "dayjs";
40
40
  import React, { forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
41
41
  import { locales } from "@pisell/utils";
@@ -132,7 +132,7 @@ const resolveInitialAvailabilityCandidate = (source, startDate, endDate, startTi
132
132
  if (endDate && candidateEndDate && candidateEndDate !== endDate.format("YYYY-MM-DD")) return;
133
133
  return rawCandidate;
134
134
  };
135
- const PcActionButtons = ({ isCreateMode, isRemoveDisabled, isShowManualPriceChange, isShowNote, isShowRemove, confirmLabel, isConfirmDisabled = false, isManualPriceChangeDisabled = false, hidePrimaryActions = false, onCancel, onRemove, onManualPriceChange, onOpenNote, onConfirm }) => {
135
+ const PcActionButtons = ({ isCreateMode, isRemoveDisabled, isShowManualPriceChange, isShowNote, isShowRemove, confirmLabel, isConfirmDisabled = false, isConfirmLoading = false, isManualPriceChangeDisabled = false, hidePrimaryActions = false, onCancel, onRemove, onManualPriceChange, onOpenNote, onConfirm }) => {
136
136
  const auxiliaryActions = [isShowNote ? /* @__PURE__ */ React.createElement(Button, {
137
137
  key: "note",
138
138
  type: "default",
@@ -164,6 +164,7 @@ const PcActionButtons = ({ isCreateMode, isRemoveDisabled, isShowManualPriceChan
164
164
  type: "primary",
165
165
  size: "large",
166
166
  disabled: isConfirmDisabled,
167
+ loading: isConfirmLoading,
167
168
  onClick: onConfirm,
168
169
  className: "sku-detail-side-actions-btn sku-detail-side-actions-confirm-btn"
169
170
  }, /* @__PURE__ */ React.createElement("span", { className: "sku-detail-content-footer-confirm-btn-text" }, confirmLabel))) : null);
@@ -236,8 +237,10 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
236
237
  const [selectionFlowProcedureSteps, setSelectionFlowProcedureSteps] = useState(null);
237
238
  const [compiledSelectionFlowSteps, setCompiledSelectionFlowSteps] = useState(null);
238
239
  const [posAutoResolutionStatus, setPosAutoResolutionStatus] = useState("idle");
240
+ const [posAutoResolutionConfirmPending, setPosAutoResolutionConfirmPending] = useState(false);
239
241
  const posAutoResolutionRunRef = useRef(0);
240
242
  const posAutoResolutionAbandonedRef = useRef(false);
243
+ const posAutoResolutionConfirmPendingRunRef = useRef(null);
241
244
  const [effectiveSelectionFlowSteps, setEffectiveSelectionFlowSteps] = useState(void 0);
242
245
  const [skuDetailConfig, setSkuDetailConfig] = useState({
243
246
  isShowProductSummary: false,
@@ -786,6 +789,8 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
786
789
  setLatestSelectionFlowDraft(null);
787
790
  posAutoResolutionRunRef.current += 1;
788
791
  posAutoResolutionAbandonedRef.current = false;
792
+ posAutoResolutionConfirmPendingRunRef.current = null;
793
+ setPosAutoResolutionConfirmPending(false);
789
794
  setPosAutoResolutionStatus("idle");
790
795
  setEffectiveSelectionFlowSteps(void 0);
791
796
  setNoteModalOpen(false);
@@ -1296,6 +1301,8 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
1296
1301
  setLatestSelectionFlowDraft(null);
1297
1302
  posAutoResolutionRunRef.current += 1;
1298
1303
  posAutoResolutionAbandonedRef.current = false;
1304
+ posAutoResolutionConfirmPendingRunRef.current = null;
1305
+ setPosAutoResolutionConfirmPending(false);
1299
1306
  setPosAutoResolutionStatus("idle");
1300
1307
  setCurrentStep(0);
1301
1308
  }, []);
@@ -1303,6 +1310,8 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
1303
1310
  openTaskIdRef.current += 1;
1304
1311
  flowDateHydrationVersionRef.current += 1;
1305
1312
  posAutoResolutionRunRef.current += 1;
1313
+ posAutoResolutionConfirmPendingRunRef.current = null;
1314
+ setPosAutoResolutionConfirmPending(false);
1306
1315
  setOpen(false);
1307
1316
  setDetailLoading(false);
1308
1317
  setNoteModalOpen(false);
@@ -1321,20 +1330,48 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
1321
1330
  if (isCustomSelectionFlow && !flowDraft) {
1322
1331
  const flow = selectionFlowRef.current;
1323
1332
  if (!flow) return false;
1324
- if (canDirectlyConfirmPosSelectionFlow) {
1333
+ const currentFlowStepIndex = flow.getState().currentStepIndex;
1334
+ if (shouldPreparePosSelectionFlowOnConfirm({
1335
+ eligible: isPosCreateAutoResolutionEligible,
1336
+ currentStepIndex: currentFlowStepIndex,
1337
+ abandoned: posAutoResolutionAbandonedRef.current
1338
+ })) {
1339
+ if (posAutoResolutionConfirmPendingRunRef.current !== null) return false;
1325
1340
  const openTaskId = openTaskIdRef.current;
1326
1341
  const draftKey = getPosAutoResolutionDraftKey(flow.getState().draft);
1327
1342
  const runId = posAutoResolutionRunRef.current + 1;
1328
1343
  posAutoResolutionRunRef.current = runId;
1329
- const result = yield flow.prepareSteps({ fromStepIndex: 1 });
1330
- if (posAutoResolutionRunRef.current !== runId || openTaskIdRef.current !== openTaskId || posAutoResolutionAbandonedRef.current || getPosAutoResolutionDraftKey(flow.getState().draft) !== draftKey) return false;
1331
- if (!result.prepared || result.cancelled) {
1332
- setPosAutoResolutionStatus("retained");
1333
- return false;
1344
+ posAutoResolutionConfirmPendingRunRef.current = runId;
1345
+ setPosAutoResolutionConfirmPending(true);
1346
+ setPosAutoResolutionStatus("checking");
1347
+ try {
1348
+ const result = yield flow.prepareSteps({ fromStepIndex: 1 });
1349
+ if (!isCurrentPosAutoResolutionRun({
1350
+ expectedRunId: runId,
1351
+ currentRunId: posAutoResolutionRunRef.current,
1352
+ expectedOpenTaskId: openTaskId,
1353
+ currentOpenTaskId: openTaskIdRef.current,
1354
+ expectedDraftKey: draftKey,
1355
+ currentDraftKey: getPosAutoResolutionDraftKey(flow.getState().draft),
1356
+ abandoned: posAutoResolutionAbandonedRef.current,
1357
+ currentStepIndex: flow.getState().currentStepIndex
1358
+ }) || result.cancelled) return false;
1359
+ if (!result.prepared) {
1360
+ posAutoResolutionAbandonedRef.current = true;
1361
+ posAutoResolutionRunRef.current += 1;
1362
+ setPosAutoResolutionStatus("retained");
1363
+ return (yield flow.next()) || false;
1364
+ }
1365
+ setPosAutoResolutionStatus("resolved");
1366
+ const completed = yield flow.complete();
1367
+ if (!completed && openTaskIdRef.current === openTaskId && posAutoResolutionRunRef.current === runId) setPosAutoResolutionStatus("retained");
1368
+ return completed;
1369
+ } finally {
1370
+ if (posAutoResolutionConfirmPendingRunRef.current === runId) {
1371
+ posAutoResolutionConfirmPendingRunRef.current = null;
1372
+ setPosAutoResolutionConfirmPending(false);
1373
+ }
1334
1374
  }
1335
- const completed = yield flow.complete();
1336
- if (!completed && openTaskIdRef.current === openTaskId && posAutoResolutionRunRef.current === runId) setPosAutoResolutionStatus("retained");
1337
- return completed;
1338
1375
  }
1339
1376
  if (isPosCreateAutoResolutionEligible) {
1340
1377
  posAutoResolutionAbandonedRef.current = true;
@@ -1709,8 +1746,9 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
1709
1746
  isShowNote: !!(skuDetailConfig === null || skuDetailConfig === void 0 ? void 0 : skuDetailConfig.isShowNote),
1710
1747
  isShowRemove: (skuDetailConfig === null || skuDetailConfig === void 0 ? void 0 : skuDetailConfig.isShowRemove) !== false,
1711
1748
  confirmLabel: pcConfirmButtonText,
1749
+ isConfirmLoading: posAutoResolutionConfirmPending,
1712
1750
  isManualPriceChangeDisabled: !canOpenManualPriceChange,
1713
- isConfirmDisabled: hasReachedBookingPriceStep && (selectionFlowBookingPricePending || selectionFlowBookingPriceError),
1751
+ isConfirmDisabled: posAutoResolutionConfirmPending || hasReachedBookingPriceStep && (selectionFlowBookingPricePending || selectionFlowBookingPriceError),
1714
1752
  onCancel: handleCancel,
1715
1753
  onRemove: handleRemove,
1716
1754
  onManualPriceChange: handleManualPriceChange,
@@ -195,15 +195,15 @@ const refreshAvailabilityTimes = function() {
195
195
  }, requestedDuration ? require_objectSpread2._objectSpread2({ durationMinutesByProductId: { [String(availability.productId)]: requestedDuration } }, requestedStartTime ? { durationStartTimesByProductId: { [String(availability.productId)]: [requestedStartTime] } } : {}) : {}))).find((item) => String(item.productId) === String(availability.productId));
196
196
  const candidates = (group === null || group === void 0 ? void 0 : group.ranges) || [];
197
197
  const product = context.draft.productData;
198
- if (posDurationAvailability && selectionIntent === "restore" && require_posCustomTime.isFlexibleDurationValue(product === null || product === void 0 ? void 0 : product.duration)) {
198
+ if (posDurationAvailability && selectionIntent === "restore" && require_posCustomTime.isFlexibleDurationValue(product === null || product === void 0 ? void 0 : product.duration) && candidates.length === 0) {
199
199
  var _context$hostContext, _moduleOptions$slice, _context$draft$bookin2, _normalizeDurationMin3;
200
200
  const moduleOptions = require_index$1.getModuleOptions(module);
201
201
  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;
202
202
  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;
203
- const baseDurationMinutes = require_posCustomTime.resolvePosCustomTimeBaseMinutes(group === null || group === void 0 ? void 0 : group.slotStepMinutes, fallbackSlice);
203
+ const baseDurationMinutes = require_posCustomTime.resolvePosCustomTimeBaseMinutes(getProductDurationMinutes(context), group === null || group === void 0 ? void 0 : group.slotStepMinutes, fallbackSlice);
204
204
  const resetForSelectedDate = require_posCustomTime.shouldResetPosFlexibleTimeForDate((_context$draft$bookin2 = context.draft.booking.selectedCandidate) !== null && _context$draft$bookin2 !== void 0 ? _context$draft$bookin2 : previousTimeData === null || previousTimeData === void 0 ? void 0 : previousTimeData.selectedCandidate, selectedDate);
205
205
  const nextStartTime = require_posCustomTime.resolvePosCustomTimeDefaultStartTime(resetForSelectedDate ? null : context.draft.booking.startTime, baseDurationMinutes);
206
- const nextDuration = require_posCustomTime.resolvePosCustomTimeDefaultDurationMinutes(resetForSelectedDate ? product === null || product === void 0 ? void 0 : product.duration : (_normalizeDurationMin3 = normalizeDurationMinutesValue(context.draft.booking.duration)) !== null && _normalizeDurationMin3 !== void 0 ? _normalizeDurationMin3 : context.draft.booking.duration, baseDurationMinutes, context.services.selectionFlowMode === "edit" ? void 0 : require_posCustomTime.resolvePosFlexibleBusinessDurationMinutes(nextStartTime, (group === null || group === void 0 ? void 0 : group.operatingEndAt) ? (0, dayjs.default)(group.operatingEndAt).format("HH:mm") : void 0));
206
+ const nextDuration = require_posCustomTime.resolvePosCustomTimeDefaultDurationMinutes(resetForSelectedDate ? product === null || product === void 0 ? void 0 : product.duration : (_normalizeDurationMin3 = normalizeDurationMinutesValue(context.draft.booking.duration)) !== null && _normalizeDurationMin3 !== void 0 ? _normalizeDurationMin3 : context.draft.booking.duration, baseDurationMinutes);
207
207
  const changedFields = [];
208
208
  if (nextStartTime !== context.draft.booking.startTime) changedFields.push("booking.startTime");
209
209
  if (nextDuration !== context.draft.booking.duration) changedFields.push("booking.duration");
@@ -296,7 +296,7 @@ const refreshAvailabilityTimes = function() {
296
296
  restoredCandidate,
297
297
  fallbackCandidate,
298
298
  preferPreset: preferPosFlexiblePreset,
299
- minimumPresetStartAt: preferPosFlexiblePreset ? (0, dayjs.default)().toISOString() : void 0
299
+ allowRestoredFallback: fallbackSelectionIntent
300
300
  }) : restoredCandidate || fallbackCandidate;
301
301
  context.setModuleData(module.key, {
302
302
  requestId,
@@ -30,24 +30,9 @@ const resolvePosCustomTimeDefaultStartTime = (currentValue, sliceMinutes, now) =
30
30
  const minutes = alignedMinute % 60;
31
31
  return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
32
32
  };
33
- const resolvePosFlexibleBusinessDurationMinutes = (startTime, closingTime) => {
34
- const toMinuteOfDay = (value) => {
35
- if (typeof value !== "string") return null;
36
- const matched = value.trim().match(/^([01]\d|2[0-3]):([0-5]\d)(?::[0-5]\d)?$/);
37
- if (!matched) return null;
38
- return Number(matched[1]) * 60 + Number(matched[2]);
39
- };
40
- const startMinute = toMinuteOfDay(startTime);
41
- const closingMinute = toMinuteOfDay(closingTime);
42
- if (startMinute === null || closingMinute === null) return null;
43
- const duration = closingMinute > startMinute ? closingMinute - startMinute : closingMinute < startMinute ? closingMinute + 1440 - startMinute : 0;
44
- return duration > 0 ? duration : null;
45
- };
46
33
  const shouldResetPosFlexibleTimeForDate = (candidate, selectedDate) => Boolean(candidate && candidate.date !== selectedDate);
47
- const resolvePosCustomTimeDefaultDurationMinutes = (currentValue, baseDurationMinutes, flexibleDefaultMinutes) => {
34
+ const resolvePosCustomTimeDefaultDurationMinutes = (currentValue, baseDurationMinutes) => {
48
35
  if (isFlexibleDurationValue(currentValue)) {
49
- const flexibleMinutes = Number(flexibleDefaultMinutes);
50
- if (Number.isFinite(flexibleMinutes) && flexibleMinutes > 0) return Math.max(1, Math.floor(flexibleMinutes));
51
36
  if (typeof currentValue === "string") {
52
37
  const flexibleMatch = currentValue.trim().toLowerCase().match(/^flexible_(\d+(?:\.\d+)?)$/);
53
38
  if (flexibleMatch) return Math.max(1, Math.floor(Number(flexibleMatch[1])));
@@ -81,14 +66,10 @@ const getPosFlexibleDurationPresetCandidates = (candidates, requestedCustomRange
81
66
  return candidates.filter((candidate) => !isSameAvailabilityCandidateRange(candidate, requestedCustomRange));
82
67
  };
83
68
  const resolvePosFlexibleDurationInitialCandidate = (params) => {
84
- const minimumPresetStartAt = params.minimumPresetStartAt === void 0 ? null : (0, dayjs.default)(params.minimumPresetStartAt);
85
69
  const firstAvailablePreset = params.presetCandidates.find((candidate) => {
86
- if (!((!candidate.status || candidate.status === "available" || candidate.status === "limited") && !(typeof candidate.maxPartySize === "number" && candidate.maxPartySize <= 0))) return false;
87
- if (!(minimumPresetStartAt === null || minimumPresetStartAt === void 0 ? void 0 : minimumPresetStartAt.isValid())) return true;
88
- const candidateStartAt = (0, dayjs.default)(candidate.startAt);
89
- return candidateStartAt.isValid() && !candidateStartAt.isBefore(minimumPresetStartAt);
70
+ return (!candidate.status || candidate.status === "available" || candidate.status === "limited") && !(typeof candidate.maxPartySize === "number" && candidate.maxPartySize <= 0);
90
71
  });
91
- if (params.preferPreset && firstAvailablePreset) return firstAvailablePreset;
72
+ if (params.preferPreset) return firstAvailablePreset || (params.allowRestoredFallback ? params.restoredCandidate : void 0);
92
73
  return params.restoredCandidate || params.fallbackCandidate;
93
74
  };
94
75
  //#endregion
@@ -101,7 +82,6 @@ exports.resolvePosCustomTimeBaseMinutes = resolvePosCustomTimeBaseMinutes;
101
82
  exports.resolvePosCustomTimeCandidate = resolvePosCustomTimeCandidate;
102
83
  exports.resolvePosCustomTimeDefaultDurationMinutes = resolvePosCustomTimeDefaultDurationMinutes;
103
84
  exports.resolvePosCustomTimeDefaultStartTime = resolvePosCustomTimeDefaultStartTime;
104
- exports.resolvePosFlexibleBusinessDurationMinutes = resolvePosFlexibleBusinessDurationMinutes;
105
85
  exports.resolvePosFlexibleDurationInitialCandidate = resolvePosFlexibleDurationInitialCandidate;
106
86
  exports.shouldResetPosFlexibleTimeForDate = shouldResetPosFlexibleTimeForDate;
107
87
  exports.shouldShowPosCustomTimeCandidateCards = shouldShowPosCustomTimeCandidateCards;
@@ -24,7 +24,11 @@ const getPosAutoResolutionDraftKey = (draft) => {
24
24
  });
25
25
  };
26
26
  const shouldDirectlyConfirmPosSelectionFlow = ({ eligible, status, currentStepIndex }) => eligible && status === "resolved" && currentStepIndex === 0;
27
+ const shouldPreparePosSelectionFlowOnConfirm = ({ eligible, currentStepIndex, abandoned }) => eligible && currentStepIndex === 0 && !abandoned;
28
+ const isCurrentPosAutoResolutionRun = ({ expectedRunId, currentRunId, expectedOpenTaskId, currentOpenTaskId, expectedDraftKey, currentDraftKey, abandoned, currentStepIndex }) => expectedRunId === currentRunId && expectedOpenTaskId === currentOpenTaskId && expectedDraftKey === currentDraftKey && !abandoned && currentStepIndex === 0;
27
29
  //#endregion
28
30
  exports.getPosAutoResolutionDraftKey = getPosAutoResolutionDraftKey;
31
+ exports.isCurrentPosAutoResolutionRun = isCurrentPosAutoResolutionRun;
29
32
  exports.isPosCreateAutoResolutionCandidate = isPosCreateAutoResolutionCandidate;
30
33
  exports.shouldDirectlyConfirmPosSelectionFlow = shouldDirectlyConfirmPosSelectionFlow;
34
+ exports.shouldPreparePosSelectionFlowOnConfirm = shouldPreparePosSelectionFlowOnConfirm;
@@ -138,7 +138,7 @@ const resolveInitialAvailabilityCandidate = (source, startDate, endDate, startTi
138
138
  if (endDate && candidateEndDate && candidateEndDate !== endDate.format("YYYY-MM-DD")) return;
139
139
  return rawCandidate;
140
140
  };
141
- const PcActionButtons = ({ isCreateMode, isRemoveDisabled, isShowManualPriceChange, isShowNote, isShowRemove, confirmLabel, isConfirmDisabled = false, isManualPriceChangeDisabled = false, hidePrimaryActions = false, onCancel, onRemove, onManualPriceChange, onOpenNote, onConfirm }) => {
141
+ const PcActionButtons = ({ isCreateMode, isRemoveDisabled, isShowManualPriceChange, isShowNote, isShowRemove, confirmLabel, isConfirmDisabled = false, isConfirmLoading = false, isManualPriceChangeDisabled = false, hidePrimaryActions = false, onCancel, onRemove, onManualPriceChange, onOpenNote, onConfirm }) => {
142
142
  const auxiliaryActions = [isShowNote ? /* @__PURE__ */ react.default.createElement(_pisell_materials.Button, {
143
143
  key: "note",
144
144
  type: "default",
@@ -170,6 +170,7 @@ const PcActionButtons = ({ isCreateMode, isRemoveDisabled, isShowManualPriceChan
170
170
  type: "primary",
171
171
  size: "large",
172
172
  disabled: isConfirmDisabled,
173
+ loading: isConfirmLoading,
173
174
  onClick: onConfirm,
174
175
  className: "sku-detail-side-actions-btn sku-detail-side-actions-confirm-btn"
175
176
  }, /* @__PURE__ */ react.default.createElement("span", { className: "sku-detail-content-footer-confirm-btn-text" }, confirmLabel))) : null);
@@ -242,8 +243,10 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
242
243
  const [selectionFlowProcedureSteps, setSelectionFlowProcedureSteps] = (0, react.useState)(null);
243
244
  const [compiledSelectionFlowSteps, setCompiledSelectionFlowSteps] = (0, react.useState)(null);
244
245
  const [posAutoResolutionStatus, setPosAutoResolutionStatus] = (0, react.useState)("idle");
246
+ const [posAutoResolutionConfirmPending, setPosAutoResolutionConfirmPending] = (0, react.useState)(false);
245
247
  const posAutoResolutionRunRef = (0, react.useRef)(0);
246
248
  const posAutoResolutionAbandonedRef = (0, react.useRef)(false);
249
+ const posAutoResolutionConfirmPendingRunRef = (0, react.useRef)(null);
247
250
  const [effectiveSelectionFlowSteps, setEffectiveSelectionFlowSteps] = (0, react.useState)(void 0);
248
251
  const [skuDetailConfig, setSkuDetailConfig] = (0, react.useState)({
249
252
  isShowProductSummary: false,
@@ -792,6 +795,8 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
792
795
  setLatestSelectionFlowDraft(null);
793
796
  posAutoResolutionRunRef.current += 1;
794
797
  posAutoResolutionAbandonedRef.current = false;
798
+ posAutoResolutionConfirmPendingRunRef.current = null;
799
+ setPosAutoResolutionConfirmPending(false);
795
800
  setPosAutoResolutionStatus("idle");
796
801
  setEffectiveSelectionFlowSteps(void 0);
797
802
  setNoteModalOpen(false);
@@ -1302,6 +1307,8 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
1302
1307
  setLatestSelectionFlowDraft(null);
1303
1308
  posAutoResolutionRunRef.current += 1;
1304
1309
  posAutoResolutionAbandonedRef.current = false;
1310
+ posAutoResolutionConfirmPendingRunRef.current = null;
1311
+ setPosAutoResolutionConfirmPending(false);
1305
1312
  setPosAutoResolutionStatus("idle");
1306
1313
  setCurrentStep(0);
1307
1314
  }, []);
@@ -1309,6 +1316,8 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
1309
1316
  openTaskIdRef.current += 1;
1310
1317
  flowDateHydrationVersionRef.current += 1;
1311
1318
  posAutoResolutionRunRef.current += 1;
1319
+ posAutoResolutionConfirmPendingRunRef.current = null;
1320
+ setPosAutoResolutionConfirmPending(false);
1312
1321
  setOpen(false);
1313
1322
  setDetailLoading(false);
1314
1323
  setNoteModalOpen(false);
@@ -1327,20 +1336,48 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
1327
1336
  if (isCustomSelectionFlow && !flowDraft) {
1328
1337
  const flow = selectionFlowRef.current;
1329
1338
  if (!flow) return false;
1330
- if (canDirectlyConfirmPosSelectionFlow) {
1339
+ const currentFlowStepIndex = flow.getState().currentStepIndex;
1340
+ if (require_posAutoResolution.shouldPreparePosSelectionFlowOnConfirm({
1341
+ eligible: isPosCreateAutoResolutionEligible,
1342
+ currentStepIndex: currentFlowStepIndex,
1343
+ abandoned: posAutoResolutionAbandonedRef.current
1344
+ })) {
1345
+ if (posAutoResolutionConfirmPendingRunRef.current !== null) return false;
1331
1346
  const openTaskId = openTaskIdRef.current;
1332
1347
  const draftKey = require_posAutoResolution.getPosAutoResolutionDraftKey(flow.getState().draft);
1333
1348
  const runId = posAutoResolutionRunRef.current + 1;
1334
1349
  posAutoResolutionRunRef.current = runId;
1335
- const result = yield flow.prepareSteps({ fromStepIndex: 1 });
1336
- if (posAutoResolutionRunRef.current !== runId || openTaskIdRef.current !== openTaskId || posAutoResolutionAbandonedRef.current || require_posAutoResolution.getPosAutoResolutionDraftKey(flow.getState().draft) !== draftKey) return false;
1337
- if (!result.prepared || result.cancelled) {
1338
- setPosAutoResolutionStatus("retained");
1339
- return false;
1350
+ posAutoResolutionConfirmPendingRunRef.current = runId;
1351
+ setPosAutoResolutionConfirmPending(true);
1352
+ setPosAutoResolutionStatus("checking");
1353
+ try {
1354
+ const result = yield flow.prepareSteps({ fromStepIndex: 1 });
1355
+ if (!require_posAutoResolution.isCurrentPosAutoResolutionRun({
1356
+ expectedRunId: runId,
1357
+ currentRunId: posAutoResolutionRunRef.current,
1358
+ expectedOpenTaskId: openTaskId,
1359
+ currentOpenTaskId: openTaskIdRef.current,
1360
+ expectedDraftKey: draftKey,
1361
+ currentDraftKey: require_posAutoResolution.getPosAutoResolutionDraftKey(flow.getState().draft),
1362
+ abandoned: posAutoResolutionAbandonedRef.current,
1363
+ currentStepIndex: flow.getState().currentStepIndex
1364
+ }) || result.cancelled) return false;
1365
+ if (!result.prepared) {
1366
+ posAutoResolutionAbandonedRef.current = true;
1367
+ posAutoResolutionRunRef.current += 1;
1368
+ setPosAutoResolutionStatus("retained");
1369
+ return (yield flow.next()) || false;
1370
+ }
1371
+ setPosAutoResolutionStatus("resolved");
1372
+ const completed = yield flow.complete();
1373
+ if (!completed && openTaskIdRef.current === openTaskId && posAutoResolutionRunRef.current === runId) setPosAutoResolutionStatus("retained");
1374
+ return completed;
1375
+ } finally {
1376
+ if (posAutoResolutionConfirmPendingRunRef.current === runId) {
1377
+ posAutoResolutionConfirmPendingRunRef.current = null;
1378
+ setPosAutoResolutionConfirmPending(false);
1379
+ }
1340
1380
  }
1341
- const completed = yield flow.complete();
1342
- if (!completed && openTaskIdRef.current === openTaskId && posAutoResolutionRunRef.current === runId) setPosAutoResolutionStatus("retained");
1343
- return completed;
1344
1381
  }
1345
1382
  if (isPosCreateAutoResolutionEligible) {
1346
1383
  posAutoResolutionAbandonedRef.current = true;
@@ -1715,8 +1752,9 @@ const SkuDetailModal = ({ onConfirm, onRemove, onClose, variant }, ref) => {
1715
1752
  isShowNote: !!(skuDetailConfig === null || skuDetailConfig === void 0 ? void 0 : skuDetailConfig.isShowNote),
1716
1753
  isShowRemove: (skuDetailConfig === null || skuDetailConfig === void 0 ? void 0 : skuDetailConfig.isShowRemove) !== false,
1717
1754
  confirmLabel: pcConfirmButtonText,
1755
+ isConfirmLoading: posAutoResolutionConfirmPending,
1718
1756
  isManualPriceChangeDisabled: !canOpenManualPriceChange,
1719
- isConfirmDisabled: hasReachedBookingPriceStep && (selectionFlowBookingPricePending || selectionFlowBookingPriceError),
1757
+ isConfirmDisabled: posAutoResolutionConfirmPending || hasReachedBookingPriceStep && (selectionFlowBookingPricePending || selectionFlowBookingPriceError),
1720
1758
  onCancel: handleCancel,
1721
1759
  onRemove: handleRemove,
1722
1760
  onManualPriceChange: handleManualPriceChange,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pisell/private-materials",
3
- "version": "6.11.659",
3
+ "version": "6.11.661",
4
4
  "main": "./lib/index.js",
5
5
  "module": "./es/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -70,8 +70,8 @@
70
70
  "styled-components": "^6.0.0-rc.3",
71
71
  "use-sync-external-store": "^1.6.0",
72
72
  "@pisell/pi-payment-sdk": "0.0.3",
73
- "@pisell/utils": "3.0.4",
74
73
  "@pisell/materials": "6.11.256",
74
+ "@pisell/utils": "3.0.4",
75
75
  "@pisell/icon": "0.0.11",
76
76
  "@pisell/date-picker": "3.0.10"
77
77
  },