@escapenavigator/utils 2.1.1 → 2.1.3

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.
@@ -6,10 +6,30 @@ const date_1 = require("../date");
6
6
  function getSlotCancelationDate({ date, time, minHoursForFreeCanceling, cancelationRule, timeZone, now = new Date(), }) {
7
7
  const minHours = cancelationRule === questroom_cancelation_type_enum_1.QuestroomCancelationTypeEnum.NO ? 0 : minHoursForFreeCanceling;
8
8
  const timeHm = /^(\d{2}:\d{2})/.exec(time.trim())?.[1] ?? '00:00';
9
- const slotUtc = (0, date_1.zonedTimeToUtc)(`${date} ${timeHm}`, timeZone);
9
+ const fallback = {
10
+ canCancel: false,
11
+ slotCancelationDate: now,
12
+ slotCancelationHumenDate: '',
13
+ };
14
+ // Invalid Date: date-fns-tz возвращает NaN, наш zonedTimeToUtc кидает
15
+ // RangeError в formatToParts. Оба пути — ESCAPE-NAVIGATOR-WIDGET-7Q
16
+ // (`deadlineUtc.toISOString()`).
17
+ let slotUtc;
18
+ try {
19
+ slotUtc = (0, date_1.zonedTimeToUtc)(`${date} ${timeHm}`, timeZone);
20
+ }
21
+ catch {
22
+ return fallback;
23
+ }
24
+ if (Number.isNaN(slotUtc.getTime())) {
25
+ return fallback;
26
+ }
10
27
  /** Виджет передаёт отрицательное значение часов до слота; в тестах — положительное. */
11
28
  const deadlineHours = minHours <= 0 ? minHours : -minHours;
12
29
  const deadlineUtc = (0, date_1.addHours)(slotUtc, deadlineHours);
30
+ if (Number.isNaN(deadlineUtc.getTime())) {
31
+ return fallback;
32
+ }
13
33
  const d = (0, date_1.utcToZonedTime)(deadlineUtc.toISOString(), timeZone);
14
34
  return {
15
35
  canCancel: (0, date_1.isBefore)(now, deadlineUtc),
@@ -77,4 +77,24 @@ describe('getSlotCancelationDate function', () => {
77
77
  });
78
78
  expect(result.slotCancelationHumenDate).toBe('01.06.2023, 09:00');
79
79
  });
80
+ test('does not throw on unparseable date', () => {
81
+ const result = (0, _1.getSlotCancelationDate)({
82
+ cancelationRule: questroom_cancelation_type_enum_1.QuestroomCancelationTypeEnum.FULL_PRICE,
83
+ date: 'not-a-date',
84
+ time: '',
85
+ minHoursForFreeCanceling: 48,
86
+ timeZone: 'Europe/Vienna',
87
+ });
88
+ expect(result.canCancel).toBe(false);
89
+ expect(result.slotCancelationHumenDate).toBe('');
90
+ });
91
+ test('does not throw when widget passes utcDate ISO as date and empty time', () => {
92
+ expect(() => (0, _1.getSlotCancelationDate)({
93
+ cancelationRule: questroom_cancelation_type_enum_1.QuestroomCancelationTypeEnum.FULL_PRICE,
94
+ date: '2023-01-03T08:00:00.000Z',
95
+ time: '',
96
+ minHoursForFreeCanceling: -48,
97
+ timeZone: 'Europe/Vienna',
98
+ })).not.toThrow();
99
+ });
80
100
  });
@@ -0,0 +1,7 @@
1
+ import { PartOfDayEnum } from '@escapenavigator/types/dist/packages/part-of-day.enum';
2
+ /** Порядок сегментов в UI — от раннего к позднему. */
3
+ export declare const PARTS_OF_DAY: PartOfDayEnum[];
4
+ /** `HH:mm` → минуты от полуночи. Невалидная строка даёт 0. */
5
+ export declare const timeToMinutes: (time: string) => number;
6
+ export declare const getPartOfDay: (start: string) => PartOfDayEnum;
7
+ export declare const isInPartOfDay: (start: string, part?: PartOfDayEnum | null) => boolean;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isInPartOfDay = exports.getPartOfDay = exports.timeToMinutes = exports.PARTS_OF_DAY = void 0;
4
+ const part_of_day_enum_1 = require("@escapenavigator/types/dist/packages/part-of-day.enum");
5
+ /**
6
+ * Классификация времени старта по частям дня. Живёт в utils, потому что
7
+ * границы нужны и бэкенду (он режет и считает варианты), и виджету (он
8
+ * подписывает сегменты) — разъезд границ дал бы «Вечер · 5», в котором
9
+ * оказалось бы 4 варианта.
10
+ */
11
+ /** Начало части дня в минутах от полуночи. Верхняя граница — начало следующей. */
12
+ const PART_OF_DAY_START_MINUTES = {
13
+ [part_of_day_enum_1.PartOfDayEnum.MORNING]: 0,
14
+ [part_of_day_enum_1.PartOfDayEnum.DAY]: 12 * 60,
15
+ [part_of_day_enum_1.PartOfDayEnum.EVENING]: 17 * 60,
16
+ };
17
+ /** Порядок сегментов в UI — от раннего к позднему. */
18
+ exports.PARTS_OF_DAY = [
19
+ part_of_day_enum_1.PartOfDayEnum.MORNING,
20
+ part_of_day_enum_1.PartOfDayEnum.DAY,
21
+ part_of_day_enum_1.PartOfDayEnum.EVENING,
22
+ ];
23
+ /** `HH:mm` → минуты от полуночи. Невалидная строка даёт 0. */
24
+ const timeToMinutes = (time) => {
25
+ const [hours = '0', minutes = '0'] = (time ?? '').split(':');
26
+ const parsed = Number(hours) * 60 + Number(minutes);
27
+ return Number.isFinite(parsed) ? parsed : 0;
28
+ };
29
+ exports.timeToMinutes = timeToMinutes;
30
+ const getPartOfDay = (start) => {
31
+ const minutes = (0, exports.timeToMinutes)(start);
32
+ if (minutes >= PART_OF_DAY_START_MINUTES[part_of_day_enum_1.PartOfDayEnum.EVENING])
33
+ return part_of_day_enum_1.PartOfDayEnum.EVENING;
34
+ if (minutes >= PART_OF_DAY_START_MINUTES[part_of_day_enum_1.PartOfDayEnum.DAY])
35
+ return part_of_day_enum_1.PartOfDayEnum.DAY;
36
+ return part_of_day_enum_1.PartOfDayEnum.MORNING;
37
+ };
38
+ exports.getPartOfDay = getPartOfDay;
39
+ const isInPartOfDay = (start, part) => !part || (0, exports.getPartOfDay)(start) === part;
40
+ exports.isInPartOfDay = isInPartOfDay;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@escapenavigator/utils",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -14,7 +14,7 @@
14
14
  "test": "jest"
15
15
  },
16
16
  "dependencies": {
17
- "@escapenavigator/types": "^2.1.1",
17
+ "@escapenavigator/types": "^2.1.3",
18
18
  "axios": "^0.21.4",
19
19
  "class-transformer": "^0.5.1",
20
20
  "class-validator": "^0.13.2",
@@ -29,5 +29,5 @@
29
29
  "ts-jest": "^29.1.1",
30
30
  "typescript": "^5.6"
31
31
  },
32
- "gitHead": "a12ec3a77f18fd9acd233aa2d15696c279b4137f"
32
+ "gitHead": "5b85efe5deb145b844c018076f1bfcd2a14a3299"
33
33
  }