@pisell/private-materials 6.11.680 → 6.11.681

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.
@@ -1,9 +1,9 @@
1
1
  import { _objectSpread2 } from "../../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
2
2
  import BookingAvailabilityCalendar from "../../../../components/eventBooking/components/bookingAvailabilityCalendar/index.js";
3
3
  import { t } from "../i18n.js";
4
- import { buildChangeTimeCalendarProps, buildChangeTimeDateRangeProps } from "../utils/changeTime.js";
5
- import React, { useMemo } from "react";
6
- import { DatePicker, Iconfont, SelectTime } from "@pisell/materials";
4
+ import { buildChangeTimeCalendarProps, buildChangeTimeDateRangeProps, resolveChangeTimePickerDraft } from "../utils/changeTime.js";
5
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
6
+ import { DatePicker, Iconfont, SelectTime, useToast } from "@pisell/materials";
7
7
  import classNames from "classnames";
8
8
  import { LocalizationProvider, ThemeProvider, createTheme } from "@pisell/date-picker";
9
9
  import { AdapterDayjs } from "@pisell/date-picker/es/AdapterDayjs";
@@ -28,20 +28,37 @@ const datePickerDarkTheme = createTheme({
28
28
  } } } }
29
29
  });
30
30
  const ChangeTimeControls = ({ visible, value, onChange, rangeMode = "multiDay", showTime = true }) => {
31
+ const Toast = useToast();
32
+ const [pickerDraft, setPickerDraft] = useState(value);
33
+ const pickerOpenRef = useRef(false);
34
+ useEffect(() => setPickerDraft(value), [value]);
35
+ const handlePickerOpen = useCallback(() => {
36
+ pickerOpenRef.current = true;
37
+ }, []);
38
+ const handlePickerClose = useCallback(() => {
39
+ pickerOpenRef.current = false;
40
+ setPickerDraft(value);
41
+ }, [value]);
42
+ const handlePickerDateChange = useCallback((next) => {
43
+ if (!pickerOpenRef.current || !showTime) return;
44
+ setPickerDraft((previous) => resolveChangeTimePickerDraft(previous, next));
45
+ }, [showTime]);
31
46
  const calendarProps = useMemo(() => buildChangeTimeCalendarProps({
32
47
  value,
33
48
  onChange
34
49
  }), [onChange, value]);
35
50
  const dateRangeProps = useMemo(() => buildChangeTimeDateRangeProps({
36
- value,
51
+ value: pickerDraft,
37
52
  mode: rangeMode,
38
53
  showTime,
39
- onChange
54
+ onChange,
55
+ onValidationError: Toast.error
40
56
  }), [
41
57
  onChange,
42
58
  rangeMode,
43
59
  showTime,
44
- value
60
+ pickerDraft,
61
+ Toast.error
45
62
  ]);
46
63
  return /* @__PURE__ */ React.createElement("section", { className: classNames("pisell-adjust-time__change-time-panel", { "pisell-adjust-time__change-time-panel--visible": visible }) }, /* @__PURE__ */ React.createElement("div", { className: "pisell-adjust-time__change-time-card" }, /* @__PURE__ */ React.createElement("span", { className: "pisell-adjust-time__end-time-label" }, t("pisell2.adjust-time.change-time-new-schedule")), /* @__PURE__ */ React.createElement(BookingAvailabilityCalendar, _objectSpread2(_objectSpread2({}, calendarProps), {}, {
47
64
  showHeader: false,
@@ -50,6 +67,9 @@ const ChangeTimeControls = ({ visible, value, onChange, rangeMode = "multiDay",
50
67
  dateAdapter: AdapterDayjs,
51
68
  adapterLocale: "en"
52
69
  }, /* @__PURE__ */ React.createElement(ThemeProvider, { theme: datePickerDarkTheme }, /* @__PURE__ */ React.createElement(RangePicker, _objectSpread2(_objectSpread2({}, dateRangeProps), {}, {
70
+ onOpen: handlePickerOpen,
71
+ onClose: handlePickerClose,
72
+ onDateChange: handlePickerDateChange,
53
73
  timeInputComponent: SelectTime,
54
74
  timeInputProps: {
55
75
  slice: 15,
@@ -64,7 +64,7 @@ const resolveOptionalDate = (value) => {
64
64
  const date = value instanceof Date ? value : new Date(value);
65
65
  return Number.isNaN(date.getTime()) ? void 0 : date;
66
66
  };
67
- /** 任何加时结束时间都不能超过店铺/资源允许的业务结束时间。 */
67
+ /** 商品加时和补付超时按营业结束时间截断。 */
68
68
  const clampToBusinessEnd = (date, businessEnd) => {
69
69
  return date.getTime() > businessEnd.getTime() ? businessEnd : date;
70
70
  };
@@ -88,11 +88,11 @@ const resolveAdjustTimeContext = ({ current, start, end, resourceEndTime, shopCl
88
88
  const resolveAdjustTimePolicy = (context, bookingDuration) => {
89
89
  const { current, start, end, businessEnd, resourceEndDate, isFutureBooking, hasBusinessEndConflict } = context;
90
90
  const isCurrentBookingDay = isSameLocalDate(end, current);
91
+ const isOngoingBooking = start.getTime() <= current.getTime() && current.getTime() < end.getTime();
91
92
  const configuredDuration = Number(bookingDuration);
92
93
  const restartDuration = Number.isFinite(configuredDuration) && configuredDuration > 0 ? configuredDuration : minutesBetween(start, end);
93
- const canRestart = isCurrentBookingDay && current.getTime() >= start.getTime() && current.getTime() < businessEnd.getTime();
94
- const restartUncappedEnd = canRestart ? addMinutes(current, restartDuration) : end;
95
- const restartEnd = canRestart ? clampToBusinessEnd(restartUncappedEnd, businessEnd) : end;
94
+ const canRestart = isCurrentBookingDay || isFutureBooking || isOngoingBooking;
95
+ const restartEnd = canRestart ? addMinutes(current, restartDuration) : end;
96
96
  return {
97
97
  start,
98
98
  end,
@@ -110,21 +110,20 @@ const resolveAdjustTimePolicy = (context, bookingDuration) => {
110
110
  canRestart,
111
111
  payOvertimeEnd: isCurrentBookingDay && current.getTime() > end.getTime() ? current : end,
112
112
  restartStart: canRestart ? current : start,
113
- restartEnd,
114
- restartUncappedEnd
113
+ restartEnd
115
114
  };
116
115
  };
117
116
  /**
118
- * 原预约结束时间已经超过营业结束时间时,除 Manual Add time 外其它模式不可继续加时。
117
+ * 原预约结束时间已经超过营业结束时间时,商品加时和补付超时不可继续加时。
119
118
  * 这里仍返回一个可展示的方案,但 valid=false,用于 UI 展示原因和禁用提交。
120
119
  */
121
120
  const resolveBusinessConflictScenario = (activeAction, start, end, products) => {
122
121
  const productId = isProductAction(activeAction) ? activeAction.slice(8) : void 0;
123
122
  const product = productId ? products.find((item) => String(item.id) === productId) : void 0;
124
123
  return {
125
- title: activeAction === "restart" ? t("pisell2.adjust-time.restart") : (product === null || product === void 0 ? void 0 : product.title) || t("pisell2.adjust-time.pay-overtime"),
126
- subtitle: activeAction === "restart" ? t("pisell2.adjust-time.restart-subtitle") : isProductAction(activeAction) ? t("pisell2.adjust-time.product-subtitle") : t("pisell2.adjust-time.pay-overtime-subtitle"),
127
- icon: activeAction === "restart" ? "⟳" : (product === null || product === void 0 ? void 0 : product.unlimited) ? "Day" : product ? `${Number(product.minMinutes || 0)}m` : "◷",
124
+ title: (product === null || product === void 0 ? void 0 : product.title) || t("pisell2.adjust-time.pay-overtime"),
125
+ subtitle: isProductAction(activeAction) ? t("pisell2.adjust-time.product-subtitle") : t("pisell2.adjust-time.pay-overtime-subtitle"),
126
+ icon: (product === null || product === void 0 ? void 0 : product.unlimited) ? "Day" : product ? `${Number(product.minMinutes || 0)}m` : "◷",
128
127
  newStart: start,
129
128
  newEnd: end,
130
129
  uncappedNewEnd: end,
@@ -140,7 +139,7 @@ const resolveBusinessConflictScenario = (activeAction, start, end, products) =>
140
139
  */
141
140
  const buildAdjustTimeScenario = ({ activeAction, manualEndDate, changeTimeValue, policy, products }) => {
142
141
  const { start, end, addTimeStart, addTimeBaseEnd, addTimeEndLimit, hasBusinessEndConflict } = policy;
143
- if (activeAction !== "manualDuration" && activeAction !== "changeTime" && hasBusinessEndConflict) return resolveBusinessConflictScenario(activeAction, start, end, products);
142
+ if (activeAction !== "manualDuration" && activeAction !== "changeTime" && activeAction !== "restart" && hasBusinessEndConflict) return resolveBusinessConflictScenario(activeAction, start, end, products);
144
143
  if (activeAction === "changeTime") {
145
144
  const targetMinutes = minutesBetween(changeTimeValue.start, changeTimeValue.end);
146
145
  return {
@@ -160,8 +159,7 @@ const buildAdjustTimeScenario = ({ activeAction, manualEndDate, changeTimeValue,
160
159
  icon: "⟳",
161
160
  newStart: policy.restartStart,
162
161
  newEnd: policy.restartEnd,
163
- uncappedNewEnd: policy.restartUncappedEnd,
164
- effectiveEndLimit: addTimeEndLimit,
162
+ uncappedNewEnd: policy.restartEnd,
165
163
  targetMinutes: policy.canRestart ? minutesBetween(policy.restartStart, policy.restartEnd) : 0,
166
164
  valid: policy.canRestart && policy.restartEnd.getTime() > policy.restartStart.getTime()
167
165
  };
@@ -295,7 +293,8 @@ const resolveAdjustTimeHints = ({ activeAction, addedMinutes, policy, scenario,
295
293
  const { businessEnd, hasBusinessEndConflict, resourceEndDate } = policy;
296
294
  const businessEndTime = formatTime(businessEnd);
297
295
  const cappedEffectiveUntilTime = scenario.valid && pricedNewEnd.getTime() < uncappedPricedNewEnd.getTime() ? formatTime(pricedNewEnd) : void 0;
298
- const shouldShowEffectiveUntilHint = activeAction === "manualDuration" && pricedNewEnd.getTime() > businessEnd.getTime() || Boolean(cappedEffectiveUntilTime) || Boolean(hasBusinessEndConflict) || Boolean(scenario.unlimited);
296
+ const isManualBeyondBusinessEnd = activeAction === "manualDuration" && pricedNewEnd.getTime() > businessEnd.getTime();
297
+ const shouldShowEffectiveUntilHint = activeAction !== "restart" && (isManualBeyondBusinessEnd || Boolean(cappedEffectiveUntilTime) || Boolean(hasBusinessEndConflict) || Boolean(scenario.unlimited));
299
298
  const shouldShowResourceAvailabilityWarning = resourceEndDate ? !shouldShowEffectiveUntilHint && activeAction !== "restart" && activeAction !== "changeTime" && addedMinutes > 0 && resourceEndDate.getTime() < businessEnd.getTime() && pricedNewEnd.getTime() > resourceEndDate.getTime() : false;
300
299
  return {
301
300
  shouldShowEffectiveUntilHint,
@@ -25,6 +25,7 @@ var locales_default = {
25
25
  "pisell2.adjust-time.change-time-date-range": "Select schedule date",
26
26
  "pisell2.adjust-time.start-time": "Start time",
27
27
  "pisell2.adjust-time.end-time": "End time",
28
+ "pisell2.adjust-time.end-must-be-after-start": "End time must be later than the start time.",
28
29
  "pisell2.adjust-time.edit": "edit",
29
30
  "pisell2.adjust-time.amount-due": "Amount Due",
30
31
  "pisell2.adjust-time.amount-due-with-ticket-count": "Amount Due ({tickets})",
@@ -103,6 +104,7 @@ var locales_default = {
103
104
  "pisell2.adjust-time.change-time-date-range": "选择日程日期",
104
105
  "pisell2.adjust-time.start-time": "开始时间",
105
106
  "pisell2.adjust-time.end-time": "结束时间",
107
+ "pisell2.adjust-time.end-must-be-after-start": "结束时间必须晚于开始时间",
106
108
  "pisell2.adjust-time.edit": "编辑",
107
109
  "pisell2.adjust-time.amount-due": "应付金额",
108
110
  "pisell2.adjust-time.amount-due-with-ticket-count": "应付金额({tickets})",
@@ -181,6 +183,7 @@ var locales_default = {
181
183
  "pisell2.adjust-time.change-time-date-range": "選擇日程日期",
182
184
  "pisell2.adjust-time.start-time": "開始時間",
183
185
  "pisell2.adjust-time.end-time": "結束時間",
186
+ "pisell2.adjust-time.end-must-be-after-start": "結束時間必須晚於開始時間",
184
187
  "pisell2.adjust-time.edit": "編輯",
185
188
  "pisell2.adjust-time.amount-due": "應付金額",
186
189
  "pisell2.adjust-time.amount-due-with-ticket-count": "應付金額({tickets})",
@@ -259,6 +262,7 @@ var locales_default = {
259
262
  "pisell2.adjust-time.change-time-date-range": "スケジュール日を選択",
260
263
  "pisell2.adjust-time.start-time": "開始時間",
261
264
  "pisell2.adjust-time.end-time": "終了時間",
265
+ "pisell2.adjust-time.end-must-be-after-start": "終了時間は開始時間より後にしてください。",
262
266
  "pisell2.adjust-time.edit": "編集",
263
267
  "pisell2.adjust-time.amount-due": "支払い金額",
264
268
  "pisell2.adjust-time.amount-due-with-ticket-count": "支払い金額({tickets})",
@@ -337,6 +341,7 @@ var locales_default = {
337
341
  "pisell2.adjust-time.change-time-date-range": "Selecionar data do agendamento",
338
342
  "pisell2.adjust-time.start-time": "Horário de início",
339
343
  "pisell2.adjust-time.end-time": "Horário de término",
344
+ "pisell2.adjust-time.end-must-be-after-start": "O horário de término deve ser posterior ao horário de início.",
340
345
  "pisell2.adjust-time.edit": "editar",
341
346
  "pisell2.adjust-time.amount-due": "Valor devido",
342
347
  "pisell2.adjust-time.amount-due-with-ticket-count": "Valor devido ({tickets})",
@@ -1,14 +1,21 @@
1
- import { _objectSpread2 } from "../../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
2
1
  import { addMinutes, applyTimeToDate, formatTime, minutesBetween } from "./time.js";
3
2
  import dayjs from "dayjs";
3
+ import { locales } from "@pisell/utils";
4
4
  //#region src/plus/salesSdk/adjustTime/utils/changeTime.ts
5
5
  const DEFAULT_DATE_FORMAT = "YYYY/MM/DD";
6
6
  const DEFAULT_DATE_TIME_FORMAT = "YYYY/MM/DD HH:mm";
7
7
  const FALLBACK_DURATION_MINUTES = 60;
8
8
  const toPickerValue = (value) => [dayjs(value.start), dayjs(value.end)];
9
- const ensureEndAfterStart = (value) => {
10
- if (value.end.getTime() > value.start.getTime()) return value;
11
- return _objectSpread2(_objectSpread2({}, value), {}, { end: addMinutes(value.start, FALLBACK_DURATION_MINUTES) });
9
+ /** 在业务组件内联动开始时间,结束时间单独编辑时保留输入,交给 Apply 校验。 */
10
+ const resolveChangeTimePickerDraft = (previous, next) => {
11
+ var _next$, _next$2;
12
+ if (!((_next$ = next[0]) === null || _next$ === void 0 ? void 0 : _next$.isValid()) || !((_next$2 = next[1]) === null || _next$2 === void 0 ? void 0 : _next$2.isValid())) return previous;
13
+ const start = next[0].toDate();
14
+ const duration = previous.end.getTime() - previous.start.getTime();
15
+ return {
16
+ start,
17
+ end: start.getTime() !== previous.start.getTime() && duration > 0 ? new Date(start.getTime() + duration) : next[1].toDate()
18
+ };
12
19
  };
13
20
  const applyDateWithClock = (date, clockSource) => {
14
21
  return applyTimeToDate(date.toDate(), formatTime(clockSource));
@@ -24,8 +31,22 @@ const resolveDefaultChangeTimeValue = (value, minDate = dayjs().startOf("day"))
24
31
  if (!dayjs(value.start).isBefore(minDate, "day")) return value;
25
32
  return moveChangeTimeRangeToDate(value, minDate.format("YYYY-MM-DD"));
26
33
  };
27
- const buildChangeTimeDateRangeProps = ({ value, mode = "multiDay", showTime = true, placeholder, minDate, maxDate, onChange, disabledDate }) => {
34
+ const buildChangeTimeDateRangeProps = ({ value, mode = "multiDay", showTime = true, placeholder, minDate, maxDate, onChange, onValidationError, disabledDate }) => {
28
35
  const resolvedMinDate = minDate || dayjs().startOf("day");
36
+ const resolveValidNextValue = (nextValue) => {
37
+ if (!Array.isArray(nextValue) || !nextValue[0] || !nextValue[1]) return;
38
+ const [nextStartDay, nextEndDay] = nextValue;
39
+ const endDay = mode === "singleDay" && !showTime ? nextStartDay : nextEndDay;
40
+ const next = {
41
+ start: showTime ? nextStartDay.toDate() : applyDateWithClock(nextStartDay, value.start),
42
+ end: showTime ? endDay.toDate() : applyDateWithClock(endDay, value.end)
43
+ };
44
+ if (!(next.end.getTime() > next.start.getTime())) {
45
+ onValidationError === null || onValidationError === void 0 || onValidationError(locales.getText("pisell2.adjust-time.end-must-be-after-start"));
46
+ return;
47
+ }
48
+ return next;
49
+ };
29
50
  return {
30
51
  value: toPickerValue(value),
31
52
  placeholder,
@@ -50,14 +71,8 @@ const buildChangeTimeDateRangeProps = ({ value, mode = "multiDay", showTime = tr
50
71
  isHideCustomSelect: true,
51
72
  disabledDate,
52
73
  onChange: (nextValue) => {
53
- if (!Array.isArray(nextValue) || !nextValue[0]) return;
54
- const [nextStartDay, nextEndDay] = nextValue;
55
- const endDay = mode === "singleDay" ? nextStartDay : nextEndDay || nextStartDay;
56
- if (!endDay) return;
57
- onChange(ensureEndAfterStart({
58
- start: showTime ? nextStartDay.toDate() : applyDateWithClock(nextStartDay, value.start),
59
- end: showTime ? endDay.toDate() : applyDateWithClock(endDay, value.end)
60
- }));
74
+ const next = resolveValidNextValue(nextValue);
75
+ if (next) onChange(next);
61
76
  }
62
77
  };
63
78
  };
@@ -87,4 +102,4 @@ const buildChangeTimeCalendarProps = ({ value, onChange }) => {
87
102
  };
88
103
  };
89
104
  //#endregion
90
- export { buildChangeTimeCalendarProps, buildChangeTimeDateRangeProps, resolveDefaultChangeTimeValue };
105
+ export { buildChangeTimeCalendarProps, buildChangeTimeDateRangeProps, resolveChangeTimePickerDraft, resolveDefaultChangeTimeValue };
@@ -31,20 +31,37 @@ const datePickerDarkTheme = (0, _pisell_date_picker.createTheme)({
31
31
  } } } }
32
32
  });
33
33
  const ChangeTimeControls = ({ visible, value, onChange, rangeMode = "multiDay", showTime = true }) => {
34
+ const Toast = (0, _pisell_materials.useToast)();
35
+ const [pickerDraft, setPickerDraft] = (0, react.useState)(value);
36
+ const pickerOpenRef = (0, react.useRef)(false);
37
+ (0, react.useEffect)(() => setPickerDraft(value), [value]);
38
+ const handlePickerOpen = (0, react.useCallback)(() => {
39
+ pickerOpenRef.current = true;
40
+ }, []);
41
+ const handlePickerClose = (0, react.useCallback)(() => {
42
+ pickerOpenRef.current = false;
43
+ setPickerDraft(value);
44
+ }, [value]);
45
+ const handlePickerDateChange = (0, react.useCallback)((next) => {
46
+ if (!pickerOpenRef.current || !showTime) return;
47
+ setPickerDraft((previous) => require_changeTime.resolveChangeTimePickerDraft(previous, next));
48
+ }, [showTime]);
34
49
  const calendarProps = (0, react.useMemo)(() => require_changeTime.buildChangeTimeCalendarProps({
35
50
  value,
36
51
  onChange
37
52
  }), [onChange, value]);
38
53
  const dateRangeProps = (0, react.useMemo)(() => require_changeTime.buildChangeTimeDateRangeProps({
39
- value,
54
+ value: pickerDraft,
40
55
  mode: rangeMode,
41
56
  showTime,
42
- onChange
57
+ onChange,
58
+ onValidationError: Toast.error
43
59
  }), [
44
60
  onChange,
45
61
  rangeMode,
46
62
  showTime,
47
- value
63
+ pickerDraft,
64
+ Toast.error
48
65
  ]);
49
66
  return /* @__PURE__ */ react.default.createElement("section", { className: (0, classnames.default)("pisell-adjust-time__change-time-panel", { "pisell-adjust-time__change-time-panel--visible": visible }) }, /* @__PURE__ */ react.default.createElement("div", { className: "pisell-adjust-time__change-time-card" }, /* @__PURE__ */ react.default.createElement("span", { className: "pisell-adjust-time__end-time-label" }, require_i18n.t("pisell2.adjust-time.change-time-new-schedule")), /* @__PURE__ */ react.default.createElement(require_index.default, require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, calendarProps), {}, {
50
67
  showHeader: false,
@@ -53,6 +70,9 @@ const ChangeTimeControls = ({ visible, value, onChange, rangeMode = "multiDay",
53
70
  dateAdapter: _pisell_date_picker_es_AdapterDayjs.AdapterDayjs,
54
71
  adapterLocale: "en"
55
72
  }, /* @__PURE__ */ react.default.createElement(_pisell_date_picker.ThemeProvider, { theme: datePickerDarkTheme }, /* @__PURE__ */ react.default.createElement(RangePicker, require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, dateRangeProps), {}, {
73
+ onOpen: handlePickerOpen,
74
+ onClose: handlePickerClose,
75
+ onDateChange: handlePickerDateChange,
56
76
  timeInputComponent: _pisell_materials.SelectTime,
57
77
  timeInputProps: {
58
78
  slice: 15,
@@ -65,7 +65,7 @@ const resolveOptionalDate = (value) => {
65
65
  const date = value instanceof Date ? value : new Date(value);
66
66
  return Number.isNaN(date.getTime()) ? void 0 : date;
67
67
  };
68
- /** 任何加时结束时间都不能超过店铺/资源允许的业务结束时间。 */
68
+ /** 商品加时和补付超时按营业结束时间截断。 */
69
69
  const clampToBusinessEnd = (date, businessEnd) => {
70
70
  return date.getTime() > businessEnd.getTime() ? businessEnd : date;
71
71
  };
@@ -89,11 +89,11 @@ const resolveAdjustTimeContext = ({ current, start, end, resourceEndTime, shopCl
89
89
  const resolveAdjustTimePolicy = (context, bookingDuration) => {
90
90
  const { current, start, end, businessEnd, resourceEndDate, isFutureBooking, hasBusinessEndConflict } = context;
91
91
  const isCurrentBookingDay = isSameLocalDate(end, current);
92
+ const isOngoingBooking = start.getTime() <= current.getTime() && current.getTime() < end.getTime();
92
93
  const configuredDuration = Number(bookingDuration);
93
94
  const restartDuration = Number.isFinite(configuredDuration) && configuredDuration > 0 ? configuredDuration : require_time.minutesBetween(start, end);
94
- const canRestart = isCurrentBookingDay && current.getTime() >= start.getTime() && current.getTime() < businessEnd.getTime();
95
- const restartUncappedEnd = canRestart ? require_time.addMinutes(current, restartDuration) : end;
96
- const restartEnd = canRestart ? clampToBusinessEnd(restartUncappedEnd, businessEnd) : end;
95
+ const canRestart = isCurrentBookingDay || isFutureBooking || isOngoingBooking;
96
+ const restartEnd = canRestart ? require_time.addMinutes(current, restartDuration) : end;
97
97
  return {
98
98
  start,
99
99
  end,
@@ -111,21 +111,20 @@ const resolveAdjustTimePolicy = (context, bookingDuration) => {
111
111
  canRestart,
112
112
  payOvertimeEnd: isCurrentBookingDay && current.getTime() > end.getTime() ? current : end,
113
113
  restartStart: canRestart ? current : start,
114
- restartEnd,
115
- restartUncappedEnd
114
+ restartEnd
116
115
  };
117
116
  };
118
117
  /**
119
- * 原预约结束时间已经超过营业结束时间时,除 Manual Add time 外其它模式不可继续加时。
118
+ * 原预约结束时间已经超过营业结束时间时,商品加时和补付超时不可继续加时。
120
119
  * 这里仍返回一个可展示的方案,但 valid=false,用于 UI 展示原因和禁用提交。
121
120
  */
122
121
  const resolveBusinessConflictScenario = (activeAction, start, end, products) => {
123
122
  const productId = isProductAction(activeAction) ? activeAction.slice(8) : void 0;
124
123
  const product = productId ? products.find((item) => String(item.id) === productId) : void 0;
125
124
  return {
126
- title: activeAction === "restart" ? t("pisell2.adjust-time.restart") : (product === null || product === void 0 ? void 0 : product.title) || t("pisell2.adjust-time.pay-overtime"),
127
- subtitle: activeAction === "restart" ? t("pisell2.adjust-time.restart-subtitle") : isProductAction(activeAction) ? t("pisell2.adjust-time.product-subtitle") : t("pisell2.adjust-time.pay-overtime-subtitle"),
128
- icon: activeAction === "restart" ? "⟳" : (product === null || product === void 0 ? void 0 : product.unlimited) ? "Day" : product ? `${Number(product.minMinutes || 0)}m` : "◷",
125
+ title: (product === null || product === void 0 ? void 0 : product.title) || t("pisell2.adjust-time.pay-overtime"),
126
+ subtitle: isProductAction(activeAction) ? t("pisell2.adjust-time.product-subtitle") : t("pisell2.adjust-time.pay-overtime-subtitle"),
127
+ icon: (product === null || product === void 0 ? void 0 : product.unlimited) ? "Day" : product ? `${Number(product.minMinutes || 0)}m` : "◷",
129
128
  newStart: start,
130
129
  newEnd: end,
131
130
  uncappedNewEnd: end,
@@ -141,7 +140,7 @@ const resolveBusinessConflictScenario = (activeAction, start, end, products) =>
141
140
  */
142
141
  const buildAdjustTimeScenario = ({ activeAction, manualEndDate, changeTimeValue, policy, products }) => {
143
142
  const { start, end, addTimeStart, addTimeBaseEnd, addTimeEndLimit, hasBusinessEndConflict } = policy;
144
- if (activeAction !== "manualDuration" && activeAction !== "changeTime" && hasBusinessEndConflict) return resolveBusinessConflictScenario(activeAction, start, end, products);
143
+ if (activeAction !== "manualDuration" && activeAction !== "changeTime" && activeAction !== "restart" && hasBusinessEndConflict) return resolveBusinessConflictScenario(activeAction, start, end, products);
145
144
  if (activeAction === "changeTime") {
146
145
  const targetMinutes = require_time.minutesBetween(changeTimeValue.start, changeTimeValue.end);
147
146
  return {
@@ -161,8 +160,7 @@ const buildAdjustTimeScenario = ({ activeAction, manualEndDate, changeTimeValue,
161
160
  icon: "⟳",
162
161
  newStart: policy.restartStart,
163
162
  newEnd: policy.restartEnd,
164
- uncappedNewEnd: policy.restartUncappedEnd,
165
- effectiveEndLimit: addTimeEndLimit,
163
+ uncappedNewEnd: policy.restartEnd,
166
164
  targetMinutes: policy.canRestart ? require_time.minutesBetween(policy.restartStart, policy.restartEnd) : 0,
167
165
  valid: policy.canRestart && policy.restartEnd.getTime() > policy.restartStart.getTime()
168
166
  };
@@ -296,7 +294,8 @@ const resolveAdjustTimeHints = ({ activeAction, addedMinutes, policy, scenario,
296
294
  const { businessEnd, hasBusinessEndConflict, resourceEndDate } = policy;
297
295
  const businessEndTime = require_time.formatTime(businessEnd);
298
296
  const cappedEffectiveUntilTime = scenario.valid && pricedNewEnd.getTime() < uncappedPricedNewEnd.getTime() ? require_time.formatTime(pricedNewEnd) : void 0;
299
- const shouldShowEffectiveUntilHint = activeAction === "manualDuration" && pricedNewEnd.getTime() > businessEnd.getTime() || Boolean(cappedEffectiveUntilTime) || Boolean(hasBusinessEndConflict) || Boolean(scenario.unlimited);
297
+ const isManualBeyondBusinessEnd = activeAction === "manualDuration" && pricedNewEnd.getTime() > businessEnd.getTime();
298
+ const shouldShowEffectiveUntilHint = activeAction !== "restart" && (isManualBeyondBusinessEnd || Boolean(cappedEffectiveUntilTime) || Boolean(hasBusinessEndConflict) || Boolean(scenario.unlimited));
300
299
  const shouldShowResourceAvailabilityWarning = resourceEndDate ? !shouldShowEffectiveUntilHint && activeAction !== "restart" && activeAction !== "changeTime" && addedMinutes > 0 && resourceEndDate.getTime() < businessEnd.getTime() && pricedNewEnd.getTime() > resourceEndDate.getTime() : false;
301
300
  return {
302
301
  shouldShowEffectiveUntilHint,
@@ -25,6 +25,7 @@ var locales_default = {
25
25
  "pisell2.adjust-time.change-time-date-range": "Select schedule date",
26
26
  "pisell2.adjust-time.start-time": "Start time",
27
27
  "pisell2.adjust-time.end-time": "End time",
28
+ "pisell2.adjust-time.end-must-be-after-start": "End time must be later than the start time.",
28
29
  "pisell2.adjust-time.edit": "edit",
29
30
  "pisell2.adjust-time.amount-due": "Amount Due",
30
31
  "pisell2.adjust-time.amount-due-with-ticket-count": "Amount Due ({tickets})",
@@ -103,6 +104,7 @@ var locales_default = {
103
104
  "pisell2.adjust-time.change-time-date-range": "选择日程日期",
104
105
  "pisell2.adjust-time.start-time": "开始时间",
105
106
  "pisell2.adjust-time.end-time": "结束时间",
107
+ "pisell2.adjust-time.end-must-be-after-start": "结束时间必须晚于开始时间",
106
108
  "pisell2.adjust-time.edit": "编辑",
107
109
  "pisell2.adjust-time.amount-due": "应付金额",
108
110
  "pisell2.adjust-time.amount-due-with-ticket-count": "应付金额({tickets})",
@@ -181,6 +183,7 @@ var locales_default = {
181
183
  "pisell2.adjust-time.change-time-date-range": "選擇日程日期",
182
184
  "pisell2.adjust-time.start-time": "開始時間",
183
185
  "pisell2.adjust-time.end-time": "結束時間",
186
+ "pisell2.adjust-time.end-must-be-after-start": "結束時間必須晚於開始時間",
184
187
  "pisell2.adjust-time.edit": "編輯",
185
188
  "pisell2.adjust-time.amount-due": "應付金額",
186
189
  "pisell2.adjust-time.amount-due-with-ticket-count": "應付金額({tickets})",
@@ -259,6 +262,7 @@ var locales_default = {
259
262
  "pisell2.adjust-time.change-time-date-range": "スケジュール日を選択",
260
263
  "pisell2.adjust-time.start-time": "開始時間",
261
264
  "pisell2.adjust-time.end-time": "終了時間",
265
+ "pisell2.adjust-time.end-must-be-after-start": "終了時間は開始時間より後にしてください。",
262
266
  "pisell2.adjust-time.edit": "編集",
263
267
  "pisell2.adjust-time.amount-due": "支払い金額",
264
268
  "pisell2.adjust-time.amount-due-with-ticket-count": "支払い金額({tickets})",
@@ -337,6 +341,7 @@ var locales_default = {
337
341
  "pisell2.adjust-time.change-time-date-range": "Selecionar data do agendamento",
338
342
  "pisell2.adjust-time.start-time": "Horário de início",
339
343
  "pisell2.adjust-time.end-time": "Horário de término",
344
+ "pisell2.adjust-time.end-must-be-after-start": "O horário de término deve ser posterior ao horário de início.",
340
345
  "pisell2.adjust-time.edit": "editar",
341
346
  "pisell2.adjust-time.amount-due": "Valor devido",
342
347
  "pisell2.adjust-time.amount-due-with-ticket-count": "Valor devido ({tickets})",
@@ -1,16 +1,23 @@
1
1
  const require_runtime = require("../../../../_virtual/_rolldown/runtime.js");
2
- const require_objectSpread2 = require("../../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js");
3
2
  const require_time = require("./time.js");
4
3
  let dayjs = require("dayjs");
5
4
  dayjs = require_runtime.__toESM(dayjs);
5
+ let _pisell_utils = require("@pisell/utils");
6
6
  //#region src/plus/salesSdk/adjustTime/utils/changeTime.ts
7
7
  const DEFAULT_DATE_FORMAT = "YYYY/MM/DD";
8
8
  const DEFAULT_DATE_TIME_FORMAT = "YYYY/MM/DD HH:mm";
9
9
  const FALLBACK_DURATION_MINUTES = 60;
10
10
  const toPickerValue = (value) => [(0, dayjs.default)(value.start), (0, dayjs.default)(value.end)];
11
- const ensureEndAfterStart = (value) => {
12
- if (value.end.getTime() > value.start.getTime()) return value;
13
- return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, value), {}, { end: require_time.addMinutes(value.start, FALLBACK_DURATION_MINUTES) });
11
+ /** 在业务组件内联动开始时间,结束时间单独编辑时保留输入,交给 Apply 校验。 */
12
+ const resolveChangeTimePickerDraft = (previous, next) => {
13
+ var _next$, _next$2;
14
+ if (!((_next$ = next[0]) === null || _next$ === void 0 ? void 0 : _next$.isValid()) || !((_next$2 = next[1]) === null || _next$2 === void 0 ? void 0 : _next$2.isValid())) return previous;
15
+ const start = next[0].toDate();
16
+ const duration = previous.end.getTime() - previous.start.getTime();
17
+ return {
18
+ start,
19
+ end: start.getTime() !== previous.start.getTime() && duration > 0 ? new Date(start.getTime() + duration) : next[1].toDate()
20
+ };
14
21
  };
15
22
  const applyDateWithClock = (date, clockSource) => {
16
23
  return require_time.applyTimeToDate(date.toDate(), require_time.formatTime(clockSource));
@@ -26,8 +33,22 @@ const resolveDefaultChangeTimeValue = (value, minDate = (0, dayjs.default)().sta
26
33
  if (!(0, dayjs.default)(value.start).isBefore(minDate, "day")) return value;
27
34
  return moveChangeTimeRangeToDate(value, minDate.format("YYYY-MM-DD"));
28
35
  };
29
- const buildChangeTimeDateRangeProps = ({ value, mode = "multiDay", showTime = true, placeholder, minDate, maxDate, onChange, disabledDate }) => {
36
+ const buildChangeTimeDateRangeProps = ({ value, mode = "multiDay", showTime = true, placeholder, minDate, maxDate, onChange, onValidationError, disabledDate }) => {
30
37
  const resolvedMinDate = minDate || (0, dayjs.default)().startOf("day");
38
+ const resolveValidNextValue = (nextValue) => {
39
+ if (!Array.isArray(nextValue) || !nextValue[0] || !nextValue[1]) return;
40
+ const [nextStartDay, nextEndDay] = nextValue;
41
+ const endDay = mode === "singleDay" && !showTime ? nextStartDay : nextEndDay;
42
+ const next = {
43
+ start: showTime ? nextStartDay.toDate() : applyDateWithClock(nextStartDay, value.start),
44
+ end: showTime ? endDay.toDate() : applyDateWithClock(endDay, value.end)
45
+ };
46
+ if (!(next.end.getTime() > next.start.getTime())) {
47
+ onValidationError === null || onValidationError === void 0 || onValidationError(_pisell_utils.locales.getText("pisell2.adjust-time.end-must-be-after-start"));
48
+ return;
49
+ }
50
+ return next;
51
+ };
31
52
  return {
32
53
  value: toPickerValue(value),
33
54
  placeholder,
@@ -52,14 +73,8 @@ const buildChangeTimeDateRangeProps = ({ value, mode = "multiDay", showTime = tr
52
73
  isHideCustomSelect: true,
53
74
  disabledDate,
54
75
  onChange: (nextValue) => {
55
- if (!Array.isArray(nextValue) || !nextValue[0]) return;
56
- const [nextStartDay, nextEndDay] = nextValue;
57
- const endDay = mode === "singleDay" ? nextStartDay : nextEndDay || nextStartDay;
58
- if (!endDay) return;
59
- onChange(ensureEndAfterStart({
60
- start: showTime ? nextStartDay.toDate() : applyDateWithClock(nextStartDay, value.start),
61
- end: showTime ? endDay.toDate() : applyDateWithClock(endDay, value.end)
62
- }));
76
+ const next = resolveValidNextValue(nextValue);
77
+ if (next) onChange(next);
63
78
  }
64
79
  };
65
80
  };
@@ -91,4 +106,5 @@ const buildChangeTimeCalendarProps = ({ value, onChange }) => {
91
106
  //#endregion
92
107
  exports.buildChangeTimeCalendarProps = buildChangeTimeCalendarProps;
93
108
  exports.buildChangeTimeDateRangeProps = buildChangeTimeDateRangeProps;
109
+ exports.resolveChangeTimePickerDraft = resolveChangeTimePickerDraft;
94
110
  exports.resolveDefaultChangeTimeValue = resolveDefaultChangeTimeValue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pisell/private-materials",
3
- "version": "6.11.680",
3
+ "version": "6.11.681",
4
4
  "main": "./lib/index.js",
5
5
  "module": "./es/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -71,8 +71,8 @@
71
71
  "use-sync-external-store": "^1.6.0",
72
72
  "@pisell/pi-payment-sdk": "0.0.3",
73
73
  "@pisell/utils": "3.0.4",
74
- "@pisell/icon": "0.0.11",
75
74
  "@pisell/materials": "6.11.263",
75
+ "@pisell/icon": "0.0.11",
76
76
  "@pisell/date-picker": "3.0.10"
77
77
  },
78
78
  "peerDependencies": {