@escapenavigator/utils 1.10.106 → 1.10.108

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.
Files changed (53) hide show
  1. package/dist/date-timezone.d.ts +5 -0
  2. package/dist/date-timezone.js +190 -0
  3. package/dist/date.d.ts +53 -0
  4. package/dist/date.js +362 -0
  5. package/dist/date.test.d.ts +1 -0
  6. package/dist/date.test.js +61 -0
  7. package/dist/format-amount/index.js +12 -12
  8. package/dist/get-documents-links.js +1 -2
  9. package/dist/get-email-result-section.js +1 -2
  10. package/dist/get-email-upsales-section.js +1 -2
  11. package/dist/get-full-name.js +1 -1
  12. package/dist/get-handled-error-message.js +1 -1
  13. package/dist/get-order-cancelation-date/index.js +4 -10
  14. package/dist/get-order-cancelation-state/index.js +12 -11
  15. package/dist/get-order-cancelation-state/index.test.js +5 -5
  16. package/dist/get-players-price.js +1 -1
  17. package/dist/get-promocode-discount.js +2 -0
  18. package/dist/get-service-error.js +3 -3
  19. package/dist/get-slot-cancelation-date/index.d.ts +3 -1
  20. package/dist/get-slot-cancelation-date/index.js +11 -14
  21. package/dist/get-slot-cancelation-date/index.test.js +4 -8
  22. package/dist/get-static-color.js +1 -2
  23. package/dist/has-text-outside-tags.js +1 -2
  24. package/dist/index.d.ts +9 -3
  25. package/dist/index.js +9 -3
  26. package/dist/is-axios-error.js +1 -2
  27. package/dist/is-network-error.js +1 -2
  28. package/dist/pick/index.d.ts +2 -0
  29. package/dist/pick/index.js +16 -0
  30. package/dist/pick/index.test.d.ts +1 -0
  31. package/dist/pick/index.test.js +23 -0
  32. package/dist/promocode-error-codes.d.ts +72 -0
  33. package/dist/promocode-error-codes.js +61 -0
  34. package/dist/promocode-nominal-rules.d.ts +29 -0
  35. package/dist/promocode-nominal-rules.js +39 -0
  36. package/dist/promocode-nominal-rules.spec.d.ts +1 -0
  37. package/dist/promocode-nominal-rules.spec.js +74 -0
  38. package/dist/serialize-slot.d.ts +1 -20
  39. package/dist/serialize-slot.js +8 -78
  40. package/dist/transform-text.js +6 -4
  41. package/dist/tz-date.d.ts +1 -1
  42. package/dist/tz-date.js +8 -9
  43. package/dist/utm-touchpoints.d.ts +63 -0
  44. package/dist/utm-touchpoints.js +66 -0
  45. package/dist/utm-touchpoints.spec.d.ts +1 -0
  46. package/dist/utm-touchpoints.spec.js +95 -0
  47. package/dist/validate-by-dto.d.ts +1 -1
  48. package/dist/validate-by-dto.js +2 -3
  49. package/dist/validate-promocode.d.ts +9 -4
  50. package/dist/validate-promocode.js +57 -38
  51. package/dist/validate-promocode.spec.d.ts +1 -0
  52. package/dist/validate-promocode.spec.js +129 -0
  53. package/package.json +4 -25
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateByDto = void 0;
3
+ exports.validateByDto = validateByDto;
4
4
  const class_validator_1 = require("class-validator");
5
5
  function validateByDto(t) {
6
6
  const validate = (data) => {
7
- const errors = (0, class_validator_1.validateSync)(typeof data === 'object' ? data : {});
7
+ const errors = (0, class_validator_1.validateSync)(data && typeof data === 'object' ? data : {});
8
8
  const getErrors = (err = []) => err.reduce((acc, { property, constraints, children }) => {
9
9
  if (children && typeof children === 'object' && children.length) {
10
10
  return { ...acc, [property]: getErrors(children) };
@@ -19,4 +19,3 @@ function validateByDto(t) {
19
19
  };
20
20
  return validate;
21
21
  }
22
- exports.validateByDto = validateByDto;
@@ -1,4 +1,5 @@
1
1
  import { PromocodeRO } from '@escapenavigator/types/dist/promocode/promocode.ro';
2
+ import { PromocodeError } from './promocode-error-codes';
2
3
  type Cert = {
3
4
  questroomId?: never;
4
5
  players?: never;
@@ -15,6 +16,13 @@ type Order = {
15
16
  timeZone: string;
16
17
  type: 'order';
17
18
  };
19
+ export type ValidatePromocodeResult = {
20
+ valid: true;
21
+ errors: [];
22
+ } | {
23
+ valid: false;
24
+ errors: PromocodeError[];
25
+ };
18
26
  export declare function validatePromocode({ promocode, players, questroomId, timeZone, orderDate, hasCertificates, otherPromocodes, slotDiscount, isInside, type, }: {
19
27
  promocode: PromocodeRO;
20
28
  isInside: boolean;
@@ -23,8 +31,5 @@ export declare function validatePromocode({ promocode, players, questroomId, tim
23
31
  canUseWithOtherPromocodes: boolean;
24
32
  code: string;
25
33
  }>;
26
- } & (Order | Cert)): {
27
- valid: boolean;
28
- errors: any[];
29
- };
34
+ } & (Order | Cert)): ValidatePromocodeResult;
30
35
  export {};
@@ -1,87 +1,106 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validatePromocode = void 0;
4
- const date_fns_1 = require("date-fns");
5
- const date_fns_tz_1 = require("date-fns-tz");
3
+ exports.validatePromocode = validatePromocode;
4
+ const date_1 = require("./date");
5
+ const promocode_error_codes_1 = require("./promocode-error-codes");
6
6
  function getWeekdayNumber(date) {
7
7
  const day = new Date(date).getDay();
8
8
  return (day === 0 ? 7 : day) - 1;
9
9
  }
10
10
  function validatePromocode({ promocode, players, questroomId, timeZone, orderDate, hasCertificates, otherPromocodes, slotDiscount, isInside, type, }) {
11
11
  const errors = [];
12
- const orderDateInTimeZone = type === 'order' && (0, date_fns_tz_1.utcToZonedTime)(new Date(orderDate).toISOString(), timeZone);
13
- const currentDate = type === 'order' && (0, date_fns_1.format)(orderDateInTimeZone, 'yyyy-MM-dd');
12
+ const orderDateInTimeZone = type === 'order' && (0, date_1.utcToZonedTime)(new Date(orderDate).toISOString(), timeZone);
13
+ const currentDate = type === 'order' && (0, date_1.formatDate)(orderDateInTimeZone, 'yyyy-MM-dd');
14
14
  const orderDayOfWeek = type === 'order' && getWeekdayNumber(orderDateInTimeZone);
15
- const localOrderTime = type === 'order' && (0, date_fns_1.format)(orderDateInTimeZone, 'HH:mm');
16
- const todayDate = (0, date_fns_1.format)((0, date_fns_tz_1.utcToZonedTime)(new Date(), timeZone), 'yyyy-MM-dd');
15
+ const localOrderTime = type === 'order' && (0, date_1.formatDate)(orderDateInTimeZone, 'HH:mm');
16
+ const todayDate = (0, date_1.formatDate)((0, date_1.utcToZonedTime)(new Date(), timeZone), 'yyyy-MM-dd');
17
17
  if (type === 'certificate' && !promocode.availableForCertificates) {
18
- errors.push("The promocode can't be applied for certificates.");
18
+ errors.push({ code: promocode_error_codes_1.PromocodeErrorCode.NOT_AVAILABLE_FOR_CERTIFICATES });
19
19
  }
20
20
  if (otherPromocodes?.some((p) => p.code === promocode.code)) {
21
- errors.push('Promocode already applied');
21
+ errors.push({ code: promocode_error_codes_1.PromocodeErrorCode.ALREADY_APPLIED });
22
22
  }
23
23
  if (type === 'order' && !promocode.availableForBookings) {
24
- errors.push("The promocode can't be applied for certificates.");
24
+ errors.push({ code: promocode_error_codes_1.PromocodeErrorCode.NOT_AVAILABLE_FOR_BOOKINGS });
25
25
  }
26
26
  if (promocode.inside && !isInside) {
27
- errors.push('The promocode can be applied by phone.');
27
+ errors.push({ code: promocode_error_codes_1.PromocodeErrorCode.INSIDE_ONLY });
28
28
  }
29
29
  if (promocode.multiple) {
30
30
  if (promocode.availableApplyings > 0 &&
31
31
  promocode.applyings >= promocode.availableApplyings) {
32
- errors.push('The maximum number of promocode applications has been reached.');
32
+ errors.push({ code: promocode_error_codes_1.PromocodeErrorCode.MAX_APPLYINGS_REACHED });
33
33
  }
34
34
  }
35
35
  else if (promocode.applyings > 0) {
36
- errors.push('The promocode can only be used once.');
36
+ errors.push({ code: promocode_error_codes_1.PromocodeErrorCode.SINGLE_USE });
37
37
  }
38
38
  if (!promocode.canUseWithOtherPromocodes && (otherPromocodes.length || slotDiscount)) {
39
- errors.push('The promocode cannot be used with other promocodes or discounts.');
39
+ errors.push({ code: promocode_error_codes_1.PromocodeErrorCode.NOT_COMBINABLE_WITH_OTHER_DISCOUNTS });
40
40
  }
41
41
  if (!promocode.canUseWithOtherCertificates && hasCertificates) {
42
- errors.push('The promocode cannot be used with other certificates.');
42
+ errors.push({ code: promocode_error_codes_1.PromocodeErrorCode.NOT_COMBINABLE_WITH_CERTIFICATES });
43
43
  }
44
44
  if (promocode.validFrom && todayDate < promocode.validFrom) {
45
- errors.push(`The promocode is valid from ${promocode.validFrom}.`);
45
+ errors.push({
46
+ code: promocode_error_codes_1.PromocodeErrorCode.NOT_VALID_YET,
47
+ payload: { validFrom: promocode.validFrom },
48
+ });
46
49
  }
47
50
  if (promocode.validTo && todayDate > promocode.validTo) {
48
- errors.push(`The promocode has expired. It was valid until ${promocode.validTo}.`);
51
+ errors.push({
52
+ code: promocode_error_codes_1.PromocodeErrorCode.EXPIRED,
53
+ payload: { validTo: promocode.validTo },
54
+ });
49
55
  }
50
56
  if (type === 'order' && promocode.forOrdersFrom && currentDate < promocode.forOrdersFrom) {
51
- errors.push(`The promocode is valid for games starting from ${promocode.forOrdersFrom}.`);
57
+ errors.push({
58
+ code: promocode_error_codes_1.PromocodeErrorCode.NOT_FOR_ORDER_DATE_FROM,
59
+ payload: { forOrdersFrom: promocode.forOrdersFrom },
60
+ });
52
61
  }
53
62
  if (type === 'order' && promocode.forOrdersTo && currentDate > promocode.forOrdersTo) {
54
- errors.push(`The promocode is not valid for games after ${promocode.forOrdersTo}.`);
63
+ errors.push({
64
+ code: promocode_error_codes_1.PromocodeErrorCode.NOT_FOR_ORDER_DATE_TO,
65
+ payload: { forOrdersTo: promocode.forOrdersTo },
66
+ });
55
67
  }
56
- if (!promocode.allQuestrooms && !promocode.questroomsIds?.includes(questroomId)) {
57
- errors.push('The promocode is not valid for the selected escape room.');
68
+ if (type === 'order' &&
69
+ !promocode.allQuestrooms &&
70
+ !promocode.questroomsIds?.includes(questroomId)) {
71
+ errors.push({ code: promocode_error_codes_1.PromocodeErrorCode.QUESTROOM_NOT_ALLOWED });
58
72
  }
59
73
  if (type === 'order' && promocode.availableFrom && localOrderTime < promocode.availableFrom) {
60
- errors.push(`The promocode is available from ${promocode.availableFrom}.`);
74
+ errors.push({
75
+ code: promocode_error_codes_1.PromocodeErrorCode.NOT_AVAILABLE_AT_THIS_TIME_FROM,
76
+ payload: { availableFrom: promocode.availableFrom },
77
+ });
61
78
  }
62
79
  if (type === 'order' && promocode.availableTo && localOrderTime > promocode.availableTo) {
63
- errors.push(`The promocode is only available until ${promocode.availableTo}.`);
80
+ errors.push({
81
+ code: promocode_error_codes_1.PromocodeErrorCode.NOT_AVAILABLE_AT_THIS_TIME_TO,
82
+ payload: { availableTo: promocode.availableTo },
83
+ });
64
84
  }
65
85
  if (type === 'order' &&
66
86
  promocode.availableDays &&
67
87
  !promocode.availableDays.includes(orderDayOfWeek)) {
68
- errors.push('The promocode is not valid for the selected day.');
88
+ errors.push({ code: promocode_error_codes_1.PromocodeErrorCode.NOT_AVAILABLE_THIS_DAY });
69
89
  }
70
- if (promocode.minPlayers && players < promocode.minPlayers) {
71
- errors.push(`The promocode is valid only for games with at least ${promocode.minPlayers} players.`);
90
+ if (type === 'order' && promocode.minPlayers && players < promocode.minPlayers) {
91
+ errors.push({
92
+ code: promocode_error_codes_1.PromocodeErrorCode.MIN_PLAYERS,
93
+ payload: { minPlayers: promocode.minPlayers },
94
+ });
72
95
  }
73
- if (promocode.maxPlayers && players > promocode.maxPlayers) {
74
- errors.push(`The promocode is valid only for games with no more than ${promocode.maxPlayers} players.`);
96
+ if (type === 'order' && promocode.maxPlayers && players > promocode.maxPlayers) {
97
+ errors.push({
98
+ code: promocode_error_codes_1.PromocodeErrorCode.MAX_PLAYERS,
99
+ payload: { maxPlayers: promocode.maxPlayers },
100
+ });
75
101
  }
76
102
  if (errors.length > 0) {
77
- return {
78
- valid: false,
79
- errors,
80
- };
81
- }
82
- return {
83
- valid: true,
84
- errors: [],
85
- };
103
+ return { valid: false, errors };
104
+ }
105
+ return { valid: true, errors: [] };
86
106
  }
87
- exports.validatePromocode = validatePromocode;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const promocode_type_enum_1 = require("@escapenavigator/types/dist/promocode/emun/promocode-type.enum");
4
+ const promocode_error_codes_1 = require("./promocode-error-codes");
5
+ const validate_promocode_1 = require("./validate-promocode");
6
+ const basePromocode = {
7
+ id: 1,
8
+ code: 'PROMO',
9
+ description: '',
10
+ type: promocode_type_enum_1.PromocodeTypeEnum.PERCENT_BASE_SUM,
11
+ discount: 1000,
12
+ multiple: true,
13
+ crossSale: false,
14
+ canUseWithOtherPromocodes: true,
15
+ canUseWithOtherCertificates: true,
16
+ inside: false,
17
+ availableApplyings: 0,
18
+ applyings: 0,
19
+ availableForBookings: true,
20
+ availableForCertificates: true,
21
+ validFrom: undefined,
22
+ validTo: undefined,
23
+ forOrdersFrom: undefined,
24
+ forOrdersTo: undefined,
25
+ allQuestrooms: true,
26
+ questroomsIds: [],
27
+ availableFrom: '00:00',
28
+ availableTo: '23:55',
29
+ availableDays: [0, 1, 2, 3, 4, 5, 6],
30
+ minPlayers: 0,
31
+ maxPlayers: 0,
32
+ clientDescription: undefined,
33
+ orderId: undefined,
34
+ };
35
+ const orderArgs = {
36
+ type: 'order',
37
+ questroomId: 1,
38
+ hasCertificates: false,
39
+ otherPromocodes: [],
40
+ orderDate: '2026-06-01T18:00:00.000Z',
41
+ timeZone: 'UTC',
42
+ slotDiscount: 0,
43
+ isInside: false,
44
+ players: 4,
45
+ };
46
+ describe('validatePromocode (order)', () => {
47
+ it('valid for plain promocode', () => {
48
+ const r = (0, validate_promocode_1.validatePromocode)({ promocode: basePromocode, ...orderArgs });
49
+ expect(r.valid).toBe(true);
50
+ expect(r.errors).toEqual([]);
51
+ });
52
+ it('errors with code SINGLE_USE when used multiple=false and applyings>0', () => {
53
+ const r = (0, validate_promocode_1.validatePromocode)({
54
+ promocode: { ...basePromocode, multiple: false, applyings: 1 },
55
+ ...orderArgs,
56
+ });
57
+ expect(r.valid).toBe(false);
58
+ expect(r.errors[0].code).toBe(promocode_error_codes_1.PromocodeErrorCode.SINGLE_USE);
59
+ });
60
+ it('errors EXPIRED with payload.validTo', () => {
61
+ const r = (0, validate_promocode_1.validatePromocode)({
62
+ promocode: { ...basePromocode, validTo: '2020-01-01' },
63
+ ...orderArgs,
64
+ });
65
+ expect(r.valid).toBe(false);
66
+ const exp = r.errors.find((e) => e.code === promocode_error_codes_1.PromocodeErrorCode.EXPIRED);
67
+ expect(exp).toBeTruthy();
68
+ expect(exp.payload).toEqual({ validTo: '2020-01-01' });
69
+ });
70
+ it('errors NOT_AVAILABLE_FOR_BOOKINGS when scope excludes bookings', () => {
71
+ const r = (0, validate_promocode_1.validatePromocode)({
72
+ promocode: { ...basePromocode, availableForBookings: false },
73
+ ...orderArgs,
74
+ });
75
+ expect(r.valid).toBe(false);
76
+ const codes = r.errors.map((e) => e.code);
77
+ expect(codes).toContain(promocode_error_codes_1.PromocodeErrorCode.NOT_AVAILABLE_FOR_BOOKINGS);
78
+ });
79
+ it('errors INSIDE_ONLY when inside=true and isInside=false', () => {
80
+ const r = (0, validate_promocode_1.validatePromocode)({
81
+ promocode: { ...basePromocode, inside: true },
82
+ ...orderArgs,
83
+ });
84
+ expect(r.valid).toBe(false);
85
+ const codes = r.errors.map((e) => e.code);
86
+ expect(codes).toContain(promocode_error_codes_1.PromocodeErrorCode.INSIDE_ONLY);
87
+ });
88
+ it('errors NOT_COMBINABLE_WITH_OTHER_DISCOUNTS when slotDiscount and not combinable', () => {
89
+ const r = (0, validate_promocode_1.validatePromocode)({
90
+ promocode: { ...basePromocode, canUseWithOtherPromocodes: false },
91
+ ...orderArgs,
92
+ slotDiscount: 1000,
93
+ });
94
+ expect(r.valid).toBe(false);
95
+ const codes = r.errors.map((e) => e.code);
96
+ expect(codes).toContain(promocode_error_codes_1.PromocodeErrorCode.NOT_COMBINABLE_WITH_OTHER_DISCOUNTS);
97
+ });
98
+ it('errors MIN_PLAYERS with payload', () => {
99
+ const r = (0, validate_promocode_1.validatePromocode)({
100
+ promocode: { ...basePromocode, minPlayers: 5 },
101
+ ...orderArgs,
102
+ players: 3,
103
+ });
104
+ expect(r.valid).toBe(false);
105
+ const e = r.errors.find((x) => x.code === promocode_error_codes_1.PromocodeErrorCode.MIN_PLAYERS);
106
+ expect(e?.payload).toEqual({ minPlayers: 5 });
107
+ });
108
+ });
109
+ describe('validatePromocode (certificate)', () => {
110
+ const certArgs = {
111
+ type: 'certificate',
112
+ otherPromocodes: [],
113
+ timeZone: 'UTC',
114
+ slotDiscount: 0,
115
+ isInside: false,
116
+ };
117
+ it('valid for default certificate-eligible promocode', () => {
118
+ const r = (0, validate_promocode_1.validatePromocode)({ promocode: basePromocode, ...certArgs });
119
+ expect(r.valid).toBe(true);
120
+ });
121
+ it('errors NOT_AVAILABLE_FOR_CERTIFICATES when scope excludes', () => {
122
+ const r = (0, validate_promocode_1.validatePromocode)({
123
+ promocode: { ...basePromocode, availableForCertificates: false },
124
+ ...certArgs,
125
+ });
126
+ expect(r.valid).toBe(false);
127
+ expect(r.errors[0].code).toBe(promocode_error_codes_1.PromocodeErrorCode.NOT_AVAILABLE_FOR_CERTIFICATES);
128
+ });
129
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@escapenavigator/utils",
3
- "version": "1.10.106",
3
+ "version": "1.10.108",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -14,38 +14,17 @@
14
14
  "test": "jest"
15
15
  },
16
16
  "dependencies": {
17
- "@escapenavigator/types": "^1.10.102",
17
+ "@escapenavigator/types": "^1.10.104",
18
18
  "axios": "^0.21.4",
19
19
  "class-transformer": "^0.5.1",
20
20
  "class-validator": "^0.13.2",
21
- "date-fns": "^2.22.1",
22
- "date-fns-tz": "^2.0.0",
23
21
  "i18next": "^21.6.4"
24
22
  },
25
23
  "devDependencies": {
26
- "@rollup/plugin-node-resolve": "^13.0.0",
27
- "@rollup/plugin-replace": "^2.4.2",
28
- "@rollup/plugin-typescript": "^8.2.1",
29
24
  "@types/jest": "^29.5.10",
30
- "@wessberg/rollup-plugin-ts": "^1.3.14",
31
- "alphakit-presets-lint": "^1.0.0",
32
- "babel-jest": "^26.6.3",
33
25
  "jest": "^29.7.0",
34
- "rollup-plugin-auto-external": "^2.0.0",
35
- "rollup-plugin-babel": "^4.4.0",
36
- "rollup-plugin-commonjs": "^10.1.0",
37
- "rollup-plugin-multi-input": "1.3.1",
38
- "rollup-plugin-node-resolve": "^5.2.0",
39
- "rollup-plugin-peer-deps-external": "^2.2.4",
40
- "rollup-plugin-terser": "^7.0.2",
41
26
  "ts-jest": "^29.1.1",
42
- "ts-loader": "^6.2.1",
43
- "typescript": "^4.5.4"
27
+ "typescript": "^5.6"
44
28
  },
45
- "perDependencies": {
46
- "axios": "^0.21.1",
47
- "utility-types": "^3.10.0",
48
- "uuid": "^8.3.2"
49
- },
50
- "gitHead": "2b24c3c15eb1add8eba28d8f90ca97f5fac884ab"
29
+ "gitHead": "d7810efb079eb481e21a23cb94e39be6c55f62d5"
51
30
  }