@escapenavigator/types 1.10.167 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/email-builder/index.d.ts +3 -3
- package/dist/email-builder/index.js +15 -17
- package/dist/openapi/morty/morty-attraction.ro.d.ts +1 -1
- package/dist/openapi/morty/morty-attraction.ro.js +1 -1
- package/dist/openapi/morty/morty-timeslots-query.dto.d.ts +3 -8
- package/dist/openapi/morty/morty-timeslots-query.dto.js +3 -10
- package/dist/order-promocode/create-order-refund-promocode.dto.js +2 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/widget-chat/widget-chat-conversation.ro.d.ts +2 -0
- package/dist/widget-funnel/widget-funnel-dimension.d.ts +44 -0
- package/dist/widget-funnel/widget-funnel-dimension.js +113 -0
- package/dist/widget-funnel/widget-funnel-event.dto.d.ts +30 -0
- package/dist/widget-funnel/widget-funnel-event.dto.js +88 -0
- package/dist/widget-funnel/widget-funnel-kind.enum.d.ts +9 -0
- package/dist/widget-funnel/widget-funnel-kind.enum.js +13 -0
- package/dist/widget-funnel/widget-funnel-step.enum.d.ts +45 -0
- package/dist/widget-funnel/widget-funnel-step.enum.js +83 -0
- package/dist/widget-funnel/widget-funnel.ro.d.ts +133 -0
- package/dist/widget-funnel/widget-funnel.ro.js +2 -0
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { WidgetChatConversationStatusEnum } from './enum/widget-chat-conversation-status.enum';
|
|
2
|
+
import { WidgetChatMessageAuthorEnum } from './enum/widget-chat-message-author.enum';
|
|
2
3
|
import { WidgetChatOutcomeEnum } from './enum/widget-chat-outcome.enum';
|
|
3
4
|
import { WidgetChatResolutionReasonEnum } from './enum/widget-chat-resolution-reason.enum';
|
|
4
5
|
import { WidgetChatResolvedByEnum } from './enum/widget-chat-resolved-by.enum';
|
|
@@ -16,6 +17,7 @@ export type WidgetChatConversationRO = {
|
|
|
16
17
|
visitorLastSeenAt?: Date;
|
|
17
18
|
lastMessageText?: string;
|
|
18
19
|
lastMessageAt?: Date;
|
|
20
|
+
lastMessageAuthor?: WidgetChatMessageAuthorEnum | null;
|
|
19
21
|
unreadCount: number;
|
|
20
22
|
aiEnabled: boolean;
|
|
21
23
|
aiPaused: boolean;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { WidgetFunnelKindEnum } from './widget-funnel-kind.enum';
|
|
2
|
+
import { WidgetFunnelStepEnum } from './widget-funnel-step.enum';
|
|
3
|
+
/**
|
|
4
|
+
* Реестр «измерений» (dimensions) воронки — параметров шага, по которым
|
|
5
|
+
* мы режем конверсию (например: сколько доп.услуг предложено на шаге
|
|
6
|
+
* выбора игроков). ЕДИНЫЙ источник правды:
|
|
7
|
+
* • бэк (`rollupDay`) использует `bucketize`, чтобы сгруппировать сырое
|
|
8
|
+
* значение `meta[metaKey]` в низко-кардинальный бакет;
|
|
9
|
+
* • фронт админки использует `label` / `buckets[].label` для отрисовки.
|
|
10
|
+
*
|
|
11
|
+
* Значение измерения кладётся виджетом в `meta` события того шага, где
|
|
12
|
+
* параметр уже известен (см. funnelTracker.track(kind, step, meta)).
|
|
13
|
+
* Бакетирование делаем на бэке, чтобы менять границы без передеплоя
|
|
14
|
+
* embed-виджета.
|
|
15
|
+
*/
|
|
16
|
+
export type WidgetFunnelDimensionBucket = {
|
|
17
|
+
/** Канонический ключ бакета (хранится в БД, стабилен). */
|
|
18
|
+
value: string;
|
|
19
|
+
/** Подпись для админ-UI. */
|
|
20
|
+
label: string;
|
|
21
|
+
};
|
|
22
|
+
export type WidgetFunnelDimensionDef = {
|
|
23
|
+
/** Стабильный id измерения (ключ в dim-кэше). */
|
|
24
|
+
id: string;
|
|
25
|
+
kind: WidgetFunnelKindEnum;
|
|
26
|
+
/** Шаг, на котором параметр известен и берётся из meta. */
|
|
27
|
+
step: WidgetFunnelStepEnum;
|
|
28
|
+
/** Ключ в объекте meta события этого шага. */
|
|
29
|
+
metaKey: string;
|
|
30
|
+
/** Заголовок измерения для UI. */
|
|
31
|
+
label: string;
|
|
32
|
+
/** Упорядоченный список бакетов (порядок = порядок отрисовки). */
|
|
33
|
+
buckets: WidgetFunnelDimensionBucket[];
|
|
34
|
+
/** Сырое значение meta → ключ бакета (или null = пропустить сессию). */
|
|
35
|
+
bucketize: (raw: unknown) => string | null;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Все измерения. Сейчас покрыта booking-воронка (три шага из примеров +
|
|
39
|
+
* близкие параметры оплаты). Сертификатная воронка добавляется сюда же
|
|
40
|
+
* по мере появления эмиссии meta на её шагах.
|
|
41
|
+
*/
|
|
42
|
+
export declare const WIDGET_FUNNEL_DIMENSIONS: WidgetFunnelDimensionDef[];
|
|
43
|
+
/** Измерения, привязанные к конкретному виду воронки. */
|
|
44
|
+
export declare const getDimensionsForKind: (kind: WidgetFunnelKindEnum) => WidgetFunnelDimensionDef[];
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDimensionsForKind = exports.WIDGET_FUNNEL_DIMENSIONS = void 0;
|
|
4
|
+
const widget_funnel_kind_enum_1 = require("./widget-funnel-kind.enum");
|
|
5
|
+
const widget_funnel_step_enum_1 = require("./widget-funnel-step.enum");
|
|
6
|
+
/** Бакетер чисел по списку правил «первое подходящее». */
|
|
7
|
+
const numberBucketizer = (rules) => (raw) => {
|
|
8
|
+
var _a, _b;
|
|
9
|
+
const n = typeof raw === 'number' ? raw : Number(raw);
|
|
10
|
+
if (!Number.isFinite(n))
|
|
11
|
+
return null;
|
|
12
|
+
return (_b = (_a = rules.find((r) => r.test(n))) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null;
|
|
13
|
+
};
|
|
14
|
+
/** Бакетер булева флага (принимает boolean ИЛИ 'true'/'false'). */
|
|
15
|
+
const boolBucketizer = (raw) => {
|
|
16
|
+
if (typeof raw === 'boolean')
|
|
17
|
+
return raw ? 'yes' : 'no';
|
|
18
|
+
if (raw === 'true' || raw === 'false')
|
|
19
|
+
return raw === 'true' ? 'yes' : 'no';
|
|
20
|
+
return null;
|
|
21
|
+
};
|
|
22
|
+
const YES_NO_BUCKETS = [
|
|
23
|
+
{ value: 'yes', label: 'Есть' },
|
|
24
|
+
{ value: 'no', label: 'Нет' },
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Все измерения. Сейчас покрыта booking-воронка (три шага из примеров +
|
|
28
|
+
* близкие параметры оплаты). Сертификатная воронка добавляется сюда же
|
|
29
|
+
* по мере появления эмиссии meta на её шагах.
|
|
30
|
+
*/
|
|
31
|
+
exports.WIDGET_FUNNEL_DIMENSIONS = [
|
|
32
|
+
{
|
|
33
|
+
id: 'upsellsOffered',
|
|
34
|
+
kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
|
|
35
|
+
step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.PLAYERS_STEP,
|
|
36
|
+
metaKey: 'upsellsOffered',
|
|
37
|
+
label: 'Доп. услуги предложено',
|
|
38
|
+
buckets: [
|
|
39
|
+
{ value: 'none', label: 'Нет доп. услуг' },
|
|
40
|
+
{ value: '1-3', label: '1–3 услуги' },
|
|
41
|
+
{ value: '3+', label: 'Больше трёх' },
|
|
42
|
+
],
|
|
43
|
+
bucketize: numberBucketizer([
|
|
44
|
+
{ test: (n) => n <= 0, value: 'none' },
|
|
45
|
+
{ test: (n) => n <= 3, value: '1-3' },
|
|
46
|
+
{ test: () => true, value: '3+' },
|
|
47
|
+
]),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 'seatsUrgency',
|
|
51
|
+
kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
|
|
52
|
+
step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.PLAYERS_STEP,
|
|
53
|
+
metaKey: 'seatsUrgency',
|
|
54
|
+
label: 'Показана срочность («осталось N мест»)',
|
|
55
|
+
buckets: YES_NO_BUCKETS,
|
|
56
|
+
bucketize: boolBucketizer,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'clientFieldsCount',
|
|
60
|
+
kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
|
|
61
|
+
step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.CLIENT_STEP,
|
|
62
|
+
metaKey: 'clientFieldsCount',
|
|
63
|
+
label: 'Полей в форме контактов',
|
|
64
|
+
buckets: [
|
|
65
|
+
{ value: '0-3', label: '≤ 3 поля' },
|
|
66
|
+
{ value: '4-6', label: '4–6 полей' },
|
|
67
|
+
{ value: '6+', label: '> 6 полей' },
|
|
68
|
+
],
|
|
69
|
+
bucketize: numberBucketizer([
|
|
70
|
+
{ test: (n) => n <= 3, value: '0-3' },
|
|
71
|
+
{ test: (n) => n <= 6, value: '4-6' },
|
|
72
|
+
{ test: () => true, value: '6+' },
|
|
73
|
+
]),
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: 'payWithoutPayment',
|
|
77
|
+
kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
|
|
78
|
+
step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.PAYMENT_STEP,
|
|
79
|
+
metaKey: 'payWithoutPayment',
|
|
80
|
+
label: 'Доступно «записаться без оплаты»',
|
|
81
|
+
buckets: YES_NO_BUCKETS,
|
|
82
|
+
bucketize: boolBucketizer,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'paymentMethodsCount',
|
|
86
|
+
kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
|
|
87
|
+
step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.PAYMENT_STEP,
|
|
88
|
+
metaKey: 'paymentMethodsCount',
|
|
89
|
+
label: 'Способов оплаты',
|
|
90
|
+
buckets: [
|
|
91
|
+
{ value: '1', label: '1 способ' },
|
|
92
|
+
{ value: '2', label: '2 способа' },
|
|
93
|
+
{ value: '3+', label: '3 и более' },
|
|
94
|
+
],
|
|
95
|
+
bucketize: numberBucketizer([
|
|
96
|
+
{ test: (n) => n <= 1, value: '1' },
|
|
97
|
+
{ test: (n) => n === 2, value: '2' },
|
|
98
|
+
{ test: () => true, value: '3+' },
|
|
99
|
+
]),
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'prepaymentAvailable',
|
|
103
|
+
kind: widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING,
|
|
104
|
+
step: widget_funnel_step_enum_1.WidgetFunnelStepEnum.PAYMENT_STEP,
|
|
105
|
+
metaKey: 'prepaymentAvailable',
|
|
106
|
+
label: 'Доступна предоплата (half)',
|
|
107
|
+
buckets: YES_NO_BUCKETS,
|
|
108
|
+
bucketize: boolBucketizer,
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
/** Измерения, привязанные к конкретному виду воронки. */
|
|
112
|
+
const getDimensionsForKind = (kind) => exports.WIDGET_FUNNEL_DIMENSIONS.filter((d) => d.kind === kind);
|
|
113
|
+
exports.getDimensionsForKind = getDimensionsForKind;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { WidgetFunnelKindEnum } from './widget-funnel-kind.enum';
|
|
2
|
+
import { WidgetFunnelStepEnum } from './widget-funnel-step.enum';
|
|
3
|
+
/**
|
|
4
|
+
* Одно событие воронки. `profileId` НЕ принимаем из тела — он берётся
|
|
5
|
+
* из widget-токена на бэке (см. WidgetBeaconGuard), чтобы embed не мог
|
|
6
|
+
* подделать чужую компанию.
|
|
7
|
+
*
|
|
8
|
+
* `eventId` генерит фронт (uuid v4) — нужен для идемпотентности: beacon
|
|
9
|
+
* может ретраиться (sendBeacon + fetch fallback), бэк дедупит по
|
|
10
|
+
* (sessionId, eventId).
|
|
11
|
+
*/
|
|
12
|
+
export declare class WidgetFunnelEventDto {
|
|
13
|
+
eventId: string;
|
|
14
|
+
sessionId: string;
|
|
15
|
+
widgetUid: string;
|
|
16
|
+
widgetType?: string;
|
|
17
|
+
kind: WidgetFunnelKindEnum;
|
|
18
|
+
step: WidgetFunnelStepEnum;
|
|
19
|
+
/** ISO-строка момента события на клиенте. */
|
|
20
|
+
occurredAt: string;
|
|
21
|
+
/** Произвольный контекст шага: questroomId, slotId, amount, language... */
|
|
22
|
+
meta?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Батч событий за один flush. Лимит 50 — обычная сессия порождает 5-10
|
|
26
|
+
* шагов; запас на случай агрегированного flush'а при unload.
|
|
27
|
+
*/
|
|
28
|
+
export declare class WidgetFunnelEventBatchDto {
|
|
29
|
+
events: WidgetFunnelEventDto[];
|
|
30
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.WidgetFunnelEventBatchDto = exports.WidgetFunnelEventDto = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
const widget_funnel_kind_enum_1 = require("./widget-funnel-kind.enum");
|
|
16
|
+
const widget_funnel_step_enum_1 = require("./widget-funnel-step.enum");
|
|
17
|
+
/**
|
|
18
|
+
* Одно событие воронки. `profileId` НЕ принимаем из тела — он берётся
|
|
19
|
+
* из widget-токена на бэке (см. WidgetBeaconGuard), чтобы embed не мог
|
|
20
|
+
* подделать чужую компанию.
|
|
21
|
+
*
|
|
22
|
+
* `eventId` генерит фронт (uuid v4) — нужен для идемпотентности: beacon
|
|
23
|
+
* может ретраиться (sendBeacon + fetch fallback), бэк дедупит по
|
|
24
|
+
* (sessionId, eventId).
|
|
25
|
+
*/
|
|
26
|
+
class WidgetFunnelEventDto {
|
|
27
|
+
}
|
|
28
|
+
exports.WidgetFunnelEventDto = WidgetFunnelEventDto;
|
|
29
|
+
__decorate([
|
|
30
|
+
(0, class_validator_1.IsUUID)(),
|
|
31
|
+
(0, class_transformer_1.Expose)(),
|
|
32
|
+
__metadata("design:type", String)
|
|
33
|
+
], WidgetFunnelEventDto.prototype, "eventId", void 0);
|
|
34
|
+
__decorate([
|
|
35
|
+
(0, class_validator_1.IsUUID)(),
|
|
36
|
+
(0, class_transformer_1.Expose)(),
|
|
37
|
+
__metadata("design:type", String)
|
|
38
|
+
], WidgetFunnelEventDto.prototype, "sessionId", void 0);
|
|
39
|
+
__decorate([
|
|
40
|
+
(0, class_validator_1.IsString)(),
|
|
41
|
+
(0, class_validator_1.MaxLength)(64),
|
|
42
|
+
(0, class_transformer_1.Expose)(),
|
|
43
|
+
__metadata("design:type", String)
|
|
44
|
+
], WidgetFunnelEventDto.prototype, "widgetUid", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
(0, class_validator_1.IsOptional)(),
|
|
47
|
+
(0, class_validator_1.IsString)(),
|
|
48
|
+
(0, class_validator_1.MaxLength)(32),
|
|
49
|
+
(0, class_transformer_1.Expose)(),
|
|
50
|
+
__metadata("design:type", String)
|
|
51
|
+
], WidgetFunnelEventDto.prototype, "widgetType", void 0);
|
|
52
|
+
__decorate([
|
|
53
|
+
(0, class_validator_1.IsEnum)(widget_funnel_kind_enum_1.WidgetFunnelKindEnum),
|
|
54
|
+
(0, class_transformer_1.Expose)(),
|
|
55
|
+
__metadata("design:type", String)
|
|
56
|
+
], WidgetFunnelEventDto.prototype, "kind", void 0);
|
|
57
|
+
__decorate([
|
|
58
|
+
(0, class_validator_1.IsEnum)(widget_funnel_step_enum_1.WidgetFunnelStepEnum),
|
|
59
|
+
(0, class_transformer_1.Expose)(),
|
|
60
|
+
__metadata("design:type", String)
|
|
61
|
+
], WidgetFunnelEventDto.prototype, "step", void 0);
|
|
62
|
+
__decorate([
|
|
63
|
+
(0, class_validator_1.IsISO8601)(),
|
|
64
|
+
(0, class_transformer_1.Expose)(),
|
|
65
|
+
__metadata("design:type", String)
|
|
66
|
+
], WidgetFunnelEventDto.prototype, "occurredAt", void 0);
|
|
67
|
+
__decorate([
|
|
68
|
+
(0, class_validator_1.IsOptional)(),
|
|
69
|
+
(0, class_validator_1.IsObject)(),
|
|
70
|
+
(0, class_transformer_1.Expose)(),
|
|
71
|
+
__metadata("design:type", Object)
|
|
72
|
+
], WidgetFunnelEventDto.prototype, "meta", void 0);
|
|
73
|
+
/**
|
|
74
|
+
* Батч событий за один flush. Лимит 50 — обычная сессия порождает 5-10
|
|
75
|
+
* шагов; запас на случай агрегированного flush'а при unload.
|
|
76
|
+
*/
|
|
77
|
+
class WidgetFunnelEventBatchDto {
|
|
78
|
+
}
|
|
79
|
+
exports.WidgetFunnelEventBatchDto = WidgetFunnelEventBatchDto;
|
|
80
|
+
__decorate([
|
|
81
|
+
(0, class_validator_1.IsArray)(),
|
|
82
|
+
(0, class_validator_1.ArrayMinSize)(1),
|
|
83
|
+
(0, class_validator_1.ArrayMaxSize)(50),
|
|
84
|
+
(0, class_validator_1.ValidateNested)({ each: true }),
|
|
85
|
+
(0, class_transformer_1.Type)(() => WidgetFunnelEventDto),
|
|
86
|
+
(0, class_transformer_1.Expose)(),
|
|
87
|
+
__metadata("design:type", Array)
|
|
88
|
+
], WidgetFunnelEventBatchDto.prototype, "events", void 0);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Тип воронки виджета. Один embeddable-виджет может обслуживать обе
|
|
3
|
+
* воронки (например WIDGET_BUTTON показывает и бронирование, и покупку
|
|
4
|
+
* сертификата), поэтому `kind` — это про funnel, а не про widget.type.
|
|
5
|
+
*/
|
|
6
|
+
export declare enum WidgetFunnelKindEnum {
|
|
7
|
+
BOOKING = "booking",
|
|
8
|
+
CERTIFICATE = "certificate"
|
|
9
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WidgetFunnelKindEnum = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Тип воронки виджета. Один embeddable-виджет может обслуживать обе
|
|
6
|
+
* воронки (например WIDGET_BUTTON показывает и бронирование, и покупку
|
|
7
|
+
* сертификата), поэтому `kind` — это про funnel, а не про widget.type.
|
|
8
|
+
*/
|
|
9
|
+
var WidgetFunnelKindEnum;
|
|
10
|
+
(function (WidgetFunnelKindEnum) {
|
|
11
|
+
WidgetFunnelKindEnum["BOOKING"] = "booking";
|
|
12
|
+
WidgetFunnelKindEnum["CERTIFICATE"] = "certificate";
|
|
13
|
+
})(WidgetFunnelKindEnum || (exports.WidgetFunnelKindEnum = WidgetFunnelKindEnum = {}));
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { WidgetFunnelKindEnum } from './widget-funnel-kind.enum';
|
|
2
|
+
/**
|
|
3
|
+
* Канонические шаги воронок виджета. Один общий enum на обе воронки —
|
|
4
|
+
* проще для PG enum-колонки и для агрегации; `kind` всё равно отделяет
|
|
5
|
+
* booking от certificate, но значения шагов не пересекаются намеренно
|
|
6
|
+
* (cert_-префикс), чтобы случайная путаница в коде была невозможна.
|
|
7
|
+
*
|
|
8
|
+
* Порядок шагов внутри каждой воронки задаётся `WIDGET_FUNNEL_STEP_ORDER`.
|
|
9
|
+
*/
|
|
10
|
+
export declare enum WidgetFunnelStepEnum {
|
|
11
|
+
/** Показ расписания (срез date|view|questroom). Дедупится per-session. */
|
|
12
|
+
SCHEDULE_VIEW = "schedule_view",
|
|
13
|
+
/** Клик по слоту, hold успешно создан. */
|
|
14
|
+
SLOT_CLICK = "slot_click",
|
|
15
|
+
/** Экран выбора игроков / параметров брони. */
|
|
16
|
+
PLAYERS_STEP = "players_step",
|
|
17
|
+
/** Экран контактных данных. */
|
|
18
|
+
CLIENT_STEP = "client_step",
|
|
19
|
+
/** Preorder создан (зарезервированный слот + client data). */
|
|
20
|
+
PREORDER_CREATED = "preorder_created",
|
|
21
|
+
/** Экран выбора способа оплаты. */
|
|
22
|
+
PAYMENT_STEP = "payment_step",
|
|
23
|
+
/** Нажата кнопка «Оплатить» / «Записаться». */
|
|
24
|
+
PAYMENT_SUBMIT = "payment_submit",
|
|
25
|
+
/** Успех: окно подтверждения / вейвера. */
|
|
26
|
+
PURCHASE = "purchase",
|
|
27
|
+
/** Каталог: выбор доставки / номинала / дизайна. */
|
|
28
|
+
CERT_CATALOG_VIEW = "cert_catalog_view",
|
|
29
|
+
/** Форма клиента / доставки сертификата. */
|
|
30
|
+
CERT_CLIENT_STEP = "cert_client_step",
|
|
31
|
+
/** Черновик продажи создан (получен certificateToken). */
|
|
32
|
+
CERT_SALE_CREATED = "cert_sale_created",
|
|
33
|
+
/** Экран выбора способа оплаты сертификата. */
|
|
34
|
+
CERT_PAYMENT_STEP = "cert_payment_step",
|
|
35
|
+
/** Сертификат оплачен. */
|
|
36
|
+
CERT_PURCHASE = "cert_purchase"
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Упорядоченные шаги по воронкам. Используется и на бэке (rollup:
|
|
40
|
+
* «дошёл ли до следующего шага»), и на фронте админки (отрисовка
|
|
41
|
+
* воронки сверху вниз). ЕДИНЫЙ источник правды о порядке.
|
|
42
|
+
*/
|
|
43
|
+
export declare const WIDGET_FUNNEL_STEP_ORDER: Record<WidgetFunnelKindEnum, WidgetFunnelStepEnum[]>;
|
|
44
|
+
/** Человекочитаемые подписи шагов для админ-UI. */
|
|
45
|
+
export declare const WIDGET_FUNNEL_STEP_LABELS: Record<WidgetFunnelStepEnum, string>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WIDGET_FUNNEL_STEP_LABELS = exports.WIDGET_FUNNEL_STEP_ORDER = exports.WidgetFunnelStepEnum = void 0;
|
|
4
|
+
const widget_funnel_kind_enum_1 = require("./widget-funnel-kind.enum");
|
|
5
|
+
/**
|
|
6
|
+
* Канонические шаги воронок виджета. Один общий enum на обе воронки —
|
|
7
|
+
* проще для PG enum-колонки и для агрегации; `kind` всё равно отделяет
|
|
8
|
+
* booking от certificate, но значения шагов не пересекаются намеренно
|
|
9
|
+
* (cert_-префикс), чтобы случайная путаница в коде была невозможна.
|
|
10
|
+
*
|
|
11
|
+
* Порядок шагов внутри каждой воронки задаётся `WIDGET_FUNNEL_STEP_ORDER`.
|
|
12
|
+
*/
|
|
13
|
+
var WidgetFunnelStepEnum;
|
|
14
|
+
(function (WidgetFunnelStepEnum) {
|
|
15
|
+
// --- booking ---
|
|
16
|
+
/** Показ расписания (срез date|view|questroom). Дедупится per-session. */
|
|
17
|
+
WidgetFunnelStepEnum["SCHEDULE_VIEW"] = "schedule_view";
|
|
18
|
+
/** Клик по слоту, hold успешно создан. */
|
|
19
|
+
WidgetFunnelStepEnum["SLOT_CLICK"] = "slot_click";
|
|
20
|
+
/** Экран выбора игроков / параметров брони. */
|
|
21
|
+
WidgetFunnelStepEnum["PLAYERS_STEP"] = "players_step";
|
|
22
|
+
/** Экран контактных данных. */
|
|
23
|
+
WidgetFunnelStepEnum["CLIENT_STEP"] = "client_step";
|
|
24
|
+
/** Preorder создан (зарезервированный слот + client data). */
|
|
25
|
+
WidgetFunnelStepEnum["PREORDER_CREATED"] = "preorder_created";
|
|
26
|
+
/** Экран выбора способа оплаты. */
|
|
27
|
+
WidgetFunnelStepEnum["PAYMENT_STEP"] = "payment_step";
|
|
28
|
+
/** Нажата кнопка «Оплатить» / «Записаться». */
|
|
29
|
+
WidgetFunnelStepEnum["PAYMENT_SUBMIT"] = "payment_submit";
|
|
30
|
+
/** Успех: окно подтверждения / вейвера. */
|
|
31
|
+
WidgetFunnelStepEnum["PURCHASE"] = "purchase";
|
|
32
|
+
// --- certificate ---
|
|
33
|
+
/** Каталог: выбор доставки / номинала / дизайна. */
|
|
34
|
+
WidgetFunnelStepEnum["CERT_CATALOG_VIEW"] = "cert_catalog_view";
|
|
35
|
+
/** Форма клиента / доставки сертификата. */
|
|
36
|
+
WidgetFunnelStepEnum["CERT_CLIENT_STEP"] = "cert_client_step";
|
|
37
|
+
/** Черновик продажи создан (получен certificateToken). */
|
|
38
|
+
WidgetFunnelStepEnum["CERT_SALE_CREATED"] = "cert_sale_created";
|
|
39
|
+
/** Экран выбора способа оплаты сертификата. */
|
|
40
|
+
WidgetFunnelStepEnum["CERT_PAYMENT_STEP"] = "cert_payment_step";
|
|
41
|
+
/** Сертификат оплачен. */
|
|
42
|
+
WidgetFunnelStepEnum["CERT_PURCHASE"] = "cert_purchase";
|
|
43
|
+
})(WidgetFunnelStepEnum || (exports.WidgetFunnelStepEnum = WidgetFunnelStepEnum = {}));
|
|
44
|
+
/**
|
|
45
|
+
* Упорядоченные шаги по воронкам. Используется и на бэке (rollup:
|
|
46
|
+
* «дошёл ли до следующего шага»), и на фронте админки (отрисовка
|
|
47
|
+
* воронки сверху вниз). ЕДИНЫЙ источник правды о порядке.
|
|
48
|
+
*/
|
|
49
|
+
exports.WIDGET_FUNNEL_STEP_ORDER = {
|
|
50
|
+
[widget_funnel_kind_enum_1.WidgetFunnelKindEnum.BOOKING]: [
|
|
51
|
+
WidgetFunnelStepEnum.SCHEDULE_VIEW,
|
|
52
|
+
WidgetFunnelStepEnum.SLOT_CLICK,
|
|
53
|
+
WidgetFunnelStepEnum.PLAYERS_STEP,
|
|
54
|
+
WidgetFunnelStepEnum.CLIENT_STEP,
|
|
55
|
+
WidgetFunnelStepEnum.PREORDER_CREATED,
|
|
56
|
+
WidgetFunnelStepEnum.PAYMENT_STEP,
|
|
57
|
+
WidgetFunnelStepEnum.PAYMENT_SUBMIT,
|
|
58
|
+
WidgetFunnelStepEnum.PURCHASE,
|
|
59
|
+
],
|
|
60
|
+
[widget_funnel_kind_enum_1.WidgetFunnelKindEnum.CERTIFICATE]: [
|
|
61
|
+
WidgetFunnelStepEnum.CERT_CATALOG_VIEW,
|
|
62
|
+
WidgetFunnelStepEnum.CERT_CLIENT_STEP,
|
|
63
|
+
WidgetFunnelStepEnum.CERT_SALE_CREATED,
|
|
64
|
+
WidgetFunnelStepEnum.CERT_PAYMENT_STEP,
|
|
65
|
+
WidgetFunnelStepEnum.CERT_PURCHASE,
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
/** Человекочитаемые подписи шагов для админ-UI. */
|
|
69
|
+
exports.WIDGET_FUNNEL_STEP_LABELS = {
|
|
70
|
+
[WidgetFunnelStepEnum.SCHEDULE_VIEW]: 'Показ расписания',
|
|
71
|
+
[WidgetFunnelStepEnum.SLOT_CLICK]: 'Клик по слоту',
|
|
72
|
+
[WidgetFunnelStepEnum.PLAYERS_STEP]: 'Экран игроков',
|
|
73
|
+
[WidgetFunnelStepEnum.CLIENT_STEP]: 'Контактные данные',
|
|
74
|
+
[WidgetFunnelStepEnum.PREORDER_CREATED]: 'Preorder создан',
|
|
75
|
+
[WidgetFunnelStepEnum.PAYMENT_STEP]: 'Экран оплаты',
|
|
76
|
+
[WidgetFunnelStepEnum.PAYMENT_SUBMIT]: 'Нажал «Оплатить»',
|
|
77
|
+
[WidgetFunnelStepEnum.PURCHASE]: 'Покупка',
|
|
78
|
+
[WidgetFunnelStepEnum.CERT_CATALOG_VIEW]: 'Каталог сертификатов',
|
|
79
|
+
[WidgetFunnelStepEnum.CERT_CLIENT_STEP]: 'Данные / доставка',
|
|
80
|
+
[WidgetFunnelStepEnum.CERT_SALE_CREATED]: 'Черновик продажи',
|
|
81
|
+
[WidgetFunnelStepEnum.CERT_PAYMENT_STEP]: 'Экран оплаты',
|
|
82
|
+
[WidgetFunnelStepEnum.CERT_PURCHASE]: 'Покупка сертификата',
|
|
83
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { WidgetFunnelKindEnum } from './widget-funnel-kind.enum';
|
|
2
|
+
import { WidgetFunnelStepEnum } from './widget-funnel-step.enum';
|
|
3
|
+
/** Одна ступень воронки с абсолютными числами и конверсией в следующий шаг. */
|
|
4
|
+
export type WidgetFunnelStepRO = {
|
|
5
|
+
step: WidgetFunnelStepEnum;
|
|
6
|
+
/** Сколько сессий дошло до этого шага за период. */
|
|
7
|
+
sessions: number;
|
|
8
|
+
/** Сколько из них дошло до следующего шага воронки. */
|
|
9
|
+
nextStepSessions: number;
|
|
10
|
+
/** nextStepSessions / sessions (0..1). Для последнего шага = null. */
|
|
11
|
+
stepConversion: number | null;
|
|
12
|
+
/** Медиана stepConversion по компаниям (P50) — только в cross-company. */
|
|
13
|
+
benchmarkP50?: number | null;
|
|
14
|
+
/** P90 stepConversion по компаниям — только в cross-company. */
|
|
15
|
+
benchmarkP90?: number | null;
|
|
16
|
+
};
|
|
17
|
+
/** Один бакет измерения с локальной и сквозной конверсией. */
|
|
18
|
+
export type WidgetFunnelDimensionBucketRO = {
|
|
19
|
+
/** Канонический ключ бакета (см. реестр измерений). */
|
|
20
|
+
value: string;
|
|
21
|
+
/** Подпись бакета для UI. */
|
|
22
|
+
label: string;
|
|
23
|
+
/** Сессий на шаге измерения с этим значением. */
|
|
24
|
+
sessions: number;
|
|
25
|
+
/** Из них дошли до следующего шага. */
|
|
26
|
+
nextStepSessions: number;
|
|
27
|
+
/** Из них дошли до покупки (последний шаг воронки). */
|
|
28
|
+
purchasedSessions: number;
|
|
29
|
+
/** Локальная конверсия: nextStepSessions / sessions (0..1). */
|
|
30
|
+
stepConversion: number | null;
|
|
31
|
+
/** Сквозная конверсия: purchasedSessions / sessions (0..1). */
|
|
32
|
+
overallConversion: number | null;
|
|
33
|
+
};
|
|
34
|
+
/** Разрез одного шага воронки по значениям параметра. */
|
|
35
|
+
export type WidgetFunnelDimensionRO = {
|
|
36
|
+
/** id измерения из реестра. */
|
|
37
|
+
id: string;
|
|
38
|
+
/** Шаг, к которому привязано измерение. */
|
|
39
|
+
step: WidgetFunnelStepEnum;
|
|
40
|
+
/** Заголовок измерения. */
|
|
41
|
+
label: string;
|
|
42
|
+
/** Базовая (по всем бакетам) локальная конверсия шага — для дельт. */
|
|
43
|
+
baselineStepConversion: number | null;
|
|
44
|
+
/** Базовая сквозная конверсия шага → покупка. */
|
|
45
|
+
baselineOverallConversion: number | null;
|
|
46
|
+
buckets: WidgetFunnelDimensionBucketRO[];
|
|
47
|
+
};
|
|
48
|
+
/** Воронка одной компании (или платформы) за период. */
|
|
49
|
+
export type WidgetFunnelRO = {
|
|
50
|
+
profileId: number;
|
|
51
|
+
profileTitle?: string;
|
|
52
|
+
kind: WidgetFunnelKindEnum;
|
|
53
|
+
/** '' = агрегат по всем виджетам профиля. */
|
|
54
|
+
widgetUid: string;
|
|
55
|
+
steps: WidgetFunnelStepRO[];
|
|
56
|
+
/** Сессий на первом шаге воронки. */
|
|
57
|
+
entries: number;
|
|
58
|
+
/** Сессий на последнем шаге (покупка). */
|
|
59
|
+
conversions: number;
|
|
60
|
+
/** conversions / entries (0..1). */
|
|
61
|
+
overallConversion: number | null;
|
|
62
|
+
/** Разрезы шагов по параметрам (если запрошены/доступны). */
|
|
63
|
+
dimensions?: WidgetFunnelDimensionRO[];
|
|
64
|
+
};
|
|
65
|
+
/** Строка кросс-компанийной таблицы: одна компания + где она «течёт». */
|
|
66
|
+
export type WidgetFunnelCompanyRO = {
|
|
67
|
+
profileId: number;
|
|
68
|
+
profileTitle: string;
|
|
69
|
+
entries: number;
|
|
70
|
+
conversions: number;
|
|
71
|
+
overallConversion: number | null;
|
|
72
|
+
/** Шаг с наибольшим относительным оттоком (drop-off) у этой компании. */
|
|
73
|
+
worstStep: WidgetFunnelStepEnum | null;
|
|
74
|
+
worstStepConversion: number | null;
|
|
75
|
+
};
|
|
76
|
+
/** Ответ кросс-компанийного эндпоинта для продуктовой админки. */
|
|
77
|
+
export type WidgetFunnelCrossCompanyRO = {
|
|
78
|
+
kind: WidgetFunnelKindEnum;
|
|
79
|
+
from: string;
|
|
80
|
+
to: string;
|
|
81
|
+
/** Воронка-агрегат по всей платформе + benchmark percentiles на шагах. */
|
|
82
|
+
platform: WidgetFunnelRO;
|
|
83
|
+
/** Список компаний, отсортированный по overallConversion. */
|
|
84
|
+
companies: WidgetFunnelCompanyRO[];
|
|
85
|
+
};
|
|
86
|
+
/** Период сравнения: границы + воронка за этот период. */
|
|
87
|
+
export type WidgetFunnelComparePeriodRO = {
|
|
88
|
+
/** YYYY-MM-DD (UTC). */
|
|
89
|
+
from: string;
|
|
90
|
+
/** YYYY-MM-DD (UTC). */
|
|
91
|
+
to: string;
|
|
92
|
+
funnel: WidgetFunnelRO;
|
|
93
|
+
};
|
|
94
|
+
/** Дельта конверсии одного шага между текущим и базовым периодами. */
|
|
95
|
+
export type WidgetFunnelStepDeltaRO = {
|
|
96
|
+
step: WidgetFunnelStepEnum;
|
|
97
|
+
/** Локальная конверсия шага в текущем периоде. */
|
|
98
|
+
current: number | null;
|
|
99
|
+
/** Локальная конверсия шага в базовом периоде. */
|
|
100
|
+
previous: number | null;
|
|
101
|
+
/** current - previous в долях (умножить на 100 для п.п.). */
|
|
102
|
+
delta: number | null;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Сравнение двух периодов (по умолчанию текущая неделя vs прошлая) —
|
|
106
|
+
* чтобы оценивать эффект апдейтов. Платформа (profileId=0) или компания.
|
|
107
|
+
*/
|
|
108
|
+
export type WidgetFunnelCompareRO = {
|
|
109
|
+
kind: WidgetFunnelKindEnum;
|
|
110
|
+
profileId: number;
|
|
111
|
+
current: WidgetFunnelComparePeriodRO;
|
|
112
|
+
previous: WidgetFunnelComparePeriodRO;
|
|
113
|
+
stepDeltas: WidgetFunnelStepDeltaRO[];
|
|
114
|
+
/** Δ общей конверсии (current - previous) в долях. */
|
|
115
|
+
overallDelta: number | null;
|
|
116
|
+
};
|
|
117
|
+
/** Точка недельного тренда. */
|
|
118
|
+
export type WidgetFunnelTrendPointRO = {
|
|
119
|
+
/** Понедельник недели, YYYY-MM-DD (UTC). */
|
|
120
|
+
weekStart: string;
|
|
121
|
+
/** Сессий-входов (первый шаг). */
|
|
122
|
+
entries: number;
|
|
123
|
+
/** Сессий-покупок (последний шаг). */
|
|
124
|
+
conversions: number;
|
|
125
|
+
/** conversions / entries (0..1). */
|
|
126
|
+
overallConversion: number | null;
|
|
127
|
+
};
|
|
128
|
+
/** Недельный тренд конверсии за N недель. */
|
|
129
|
+
export type WidgetFunnelTrendRO = {
|
|
130
|
+
kind: WidgetFunnelKindEnum;
|
|
131
|
+
profileId: number;
|
|
132
|
+
points: WidgetFunnelTrendPointRO[];
|
|
133
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@escapenavigator/types",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"reflect-metadata": "^0.1.13",
|
|
24
24
|
"rxjs": "^7.5.5"
|
|
25
25
|
},
|
|
26
|
-
"gitHead": "
|
|
26
|
+
"gitHead": "4bc136046ad634699417e72afff25e7b28dfbe7a",
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/validator": "13.0.0",
|
|
29
29
|
"typescript": "^5.6"
|