@funnelsgrove/runtime 0.1.40 → 0.1.41
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,6 +1,7 @@
|
|
|
1
1
|
import { type Dispatch, type SetStateAction } from 'react';
|
|
2
2
|
import type { FunnelContextValue } from '../components/FunnelContext.js';
|
|
3
3
|
import type { FunnelManifestExperiment } from '../config/funnel.manifest.types.js';
|
|
4
|
+
import type { FunnelUserAnswers } from '../sdk/userAnswers.js';
|
|
4
5
|
import type { FunnelStepMeta } from '../steps/types.js';
|
|
5
6
|
export type FunnelFlowControllerExperiment<StepId extends string> = FunnelManifestExperiment & {
|
|
6
7
|
stepId: StepId;
|
|
@@ -11,6 +12,8 @@ export type FunnelFlowControllerExperiment<StepId extends string> = FunnelManife
|
|
|
11
12
|
type StepComponentRegistry = Record<string, unknown>;
|
|
12
13
|
type FunnelFlowAnalyticsAdapter = {
|
|
13
14
|
trackStepStarted?: (input: {
|
|
15
|
+
userId?: string;
|
|
16
|
+
environment?: 'test' | 'live';
|
|
14
17
|
stepId: string;
|
|
15
18
|
stepName: string;
|
|
16
19
|
stepType?: string;
|
|
@@ -18,6 +21,8 @@ type FunnelFlowAnalyticsAdapter = {
|
|
|
18
21
|
featureFlags?: Record<string, string>;
|
|
19
22
|
}) => string | null;
|
|
20
23
|
trackStepCompleted?: (input: {
|
|
24
|
+
userId?: string;
|
|
25
|
+
environment?: 'test' | 'live';
|
|
21
26
|
stepId: string;
|
|
22
27
|
stepName: string;
|
|
23
28
|
stepType?: string;
|
|
@@ -27,6 +32,8 @@ type FunnelFlowAnalyticsAdapter = {
|
|
|
27
32
|
featureFlags?: Record<string, string>;
|
|
28
33
|
}) => string | null;
|
|
29
34
|
trackStepEngaged?: (input: {
|
|
35
|
+
userId?: string;
|
|
36
|
+
environment?: 'test' | 'live';
|
|
30
37
|
stepId: string;
|
|
31
38
|
stepName: string;
|
|
32
39
|
stepType?: string;
|
|
@@ -37,6 +44,8 @@ type FunnelFlowAnalyticsAdapter = {
|
|
|
37
44
|
featureFlags?: Record<string, string>;
|
|
38
45
|
}) => string | null;
|
|
39
46
|
trackFunnelStarted?: (input: {
|
|
47
|
+
userId?: string;
|
|
48
|
+
environment?: 'test' | 'live';
|
|
40
49
|
stepId: string;
|
|
41
50
|
stepName: string;
|
|
42
51
|
stepType?: string;
|
|
@@ -44,6 +53,8 @@ type FunnelFlowAnalyticsAdapter = {
|
|
|
44
53
|
featureFlags?: Record<string, string>;
|
|
45
54
|
}) => string | null;
|
|
46
55
|
trackFirstStepViewed?: (input: {
|
|
56
|
+
userId?: string;
|
|
57
|
+
environment?: 'test' | 'live';
|
|
47
58
|
stepId: string;
|
|
48
59
|
stepName: string;
|
|
49
60
|
stepType?: string;
|
|
@@ -54,6 +65,7 @@ type FunnelFlowAnalyticsAdapter = {
|
|
|
54
65
|
type UseFunnelFlowControllerInput<StepId extends string> = {
|
|
55
66
|
analytics?: FunnelFlowAnalyticsAdapter;
|
|
56
67
|
initialStepId?: StepId;
|
|
68
|
+
initialAttributes?: FunnelUserAnswers;
|
|
57
69
|
lockToInitialStep?: boolean;
|
|
58
70
|
defaultStepId: StepId;
|
|
59
71
|
stepSequence: readonly StepId[];
|
|
@@ -107,5 +119,5 @@ export declare function computeRenderSuspended(input: {
|
|
|
107
119
|
}>;
|
|
108
120
|
isPreviewRuntime?: boolean;
|
|
109
121
|
}): boolean;
|
|
110
|
-
export declare function useFunnelFlowController<StepId extends string>({ analytics, initialStepId, lockToInitialStep, defaultStepId, stepSequence, stepById, stepComponentById, funnelExperiments, getPathForStep, getStepIdFromPath, getSequentialNextStepId, getChoiceTargetsForStep, isFunnelStepId, resolveConfiguredNextStep, resolveRuntimeInitialStepId, }: UseFunnelFlowControllerInput<StepId>): UseFunnelFlowControllerResult<StepId>;
|
|
122
|
+
export declare function useFunnelFlowController<StepId extends string>({ analytics, initialStepId, initialAttributes, lockToInitialStep, defaultStepId, stepSequence, stepById, stepComponentById, funnelExperiments, getPathForStep, getStepIdFromPath, getSequentialNextStepId, getChoiceTargetsForStep, isFunnelStepId, resolveConfiguredNextStep, resolveRuntimeInitialStepId, }: UseFunnelFlowControllerInput<StepId>): UseFunnelFlowControllerResult<StepId>;
|
|
111
123
|
export {};
|
|
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
|
|
|
3
3
|
import { writeStepChoice } from '../sdk/userAnswers.js';
|
|
4
4
|
import { apiService } from '../services/api.service.js';
|
|
5
5
|
import { logger } from '../services/logger.js';
|
|
6
|
-
import { FUNNEL_ID,
|
|
6
|
+
import { FUNNEL_ID, POSTHOG_API_HOST, POSTHOG_PROJECT_API_KEY, PROJECT_ID, } from '../services/runtime-api.config.js';
|
|
7
7
|
import { buildHostedStepLocation, dispatchWindowCustomEvent, } from './browser-helpers.js';
|
|
8
8
|
import { isPreviewStepLockRequested, resolveNextStepFromContext, shouldRunAutoAdvanceTimer, } from './funnel-flow.js';
|
|
9
9
|
import { usePreviewBridge } from './preview-bridge.js';
|
|
@@ -14,47 +14,13 @@ import { bootstrapPostHog, identifyPostHog, isPostHogReady, resolveExperimentVar
|
|
|
14
14
|
import { isEditorEnabled, useRuntimeMode } from '../services/runtime-mode.service.js';
|
|
15
15
|
import { isPreviewFrameRuntime } from '../services/preview-frame.service.js';
|
|
16
16
|
const FIRST_STEP_ENGAGEMENT_THRESHOLD_MS = 1000;
|
|
17
|
-
const buildFeatureFlagProperties = (featureFlags) => {
|
|
18
|
-
return Object.fromEntries(Object.entries(featureFlags).map(([key, value]) => [`$feature/${key}`, value]));
|
|
19
|
-
};
|
|
20
|
-
const capturePostHogStepEvent = (event, properties) => {
|
|
21
|
-
const payload = JSON.stringify({
|
|
22
|
-
api_key: POSTHOG_PROJECT_API_KEY,
|
|
23
|
-
batch: [
|
|
24
|
-
{
|
|
25
|
-
event,
|
|
26
|
-
properties: Object.assign({ $groups: {
|
|
27
|
-
project: PROJECT_ID,
|
|
28
|
-
}, $insert_id: typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
|
|
29
|
-
? crypto.randomUUID()
|
|
30
|
-
: `${event}_${Date.now()}_${Math.random().toString(16).slice(2)}`, event_source: 'client' }, properties),
|
|
31
|
-
timestamp: new Date().toISOString(),
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
});
|
|
35
|
-
const endpoint = `${POSTHOG_API_HOST}/batch/`;
|
|
36
|
-
if (typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {
|
|
37
|
-
const accepted = navigator.sendBeacon(endpoint, new Blob([payload], { type: 'application/json' }));
|
|
38
|
-
if (accepted) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
void fetch(endpoint, {
|
|
43
|
-
method: 'POST',
|
|
44
|
-
headers: { 'Content-Type': 'application/json' },
|
|
45
|
-
body: payload,
|
|
46
|
-
keepalive: true,
|
|
47
|
-
}).catch(() => {
|
|
48
|
-
// Analytics delivery must never block funnel interaction.
|
|
49
|
-
});
|
|
50
|
-
};
|
|
51
17
|
export function computeRenderSuspended(input) {
|
|
52
18
|
if (input.isPreviewRuntime || input.postHogReady) {
|
|
53
19
|
return false;
|
|
54
20
|
}
|
|
55
21
|
return input.experiments.some((experiment) => experiment.stepId === input.activeStepId);
|
|
56
22
|
}
|
|
57
|
-
export function useFunnelFlowController({ analytics, initialStepId, lockToInitialStep = false, defaultStepId, stepSequence, stepById, stepComponentById, funnelExperiments, getPathForStep, getStepIdFromPath, getSequentialNextStepId, getChoiceTargetsForStep, isFunnelStepId, resolveConfiguredNextStep, resolveRuntimeInitialStepId, }) {
|
|
23
|
+
export function useFunnelFlowController({ analytics, initialStepId, initialAttributes, lockToInitialStep = false, defaultStepId, stepSequence, stepById, stepComponentById, funnelExperiments, getPathForStep, getStepIdFromPath, getSequentialNextStepId, getChoiceTargetsForStep, isFunnelStepId, resolveConfiguredNextStep, resolveRuntimeInitialStepId, }) {
|
|
58
24
|
var _a, _b;
|
|
59
25
|
const [runtimeMode, setRuntimeMode] = useRuntimeMode();
|
|
60
26
|
const [editorModeEnabled, setEditorModeEnabled] = useState(false);
|
|
@@ -93,7 +59,7 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
93
59
|
return resolveFallbackStepId(requestedStepId);
|
|
94
60
|
}, [initialStepId, resolveFallbackStepId, resolveRuntimeInitialStepId]);
|
|
95
61
|
const [activeStepId, setActiveStepId] = useState(safeInitialStepId);
|
|
96
|
-
const [attributes, setAttributes] = useState({});
|
|
62
|
+
const [attributes, setAttributes] = useState(() => (Object.assign({}, (initialAttributes || {}))));
|
|
97
63
|
const [user, setUser] = useState(() => ({
|
|
98
64
|
id: apiService.getOrCreateClientUserId(),
|
|
99
65
|
name: '',
|
|
@@ -357,10 +323,11 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
357
323
|
};
|
|
358
324
|
const stepType = meta.type;
|
|
359
325
|
const startedAt = stepStartedAtByIdRef.current[meta.id] || record.completedAt;
|
|
360
|
-
const durationMs = Math.max(0, new Date(record.completedAt).getTime() - new Date(startedAt).getTime());
|
|
361
326
|
dispatchWindowCustomEvent('funnel:step-completed', record);
|
|
362
327
|
if (!isPreviewRuntime) {
|
|
363
328
|
(_a = analytics === null || analytics === void 0 ? void 0 : analytics.trackStepCompleted) === null || _a === void 0 ? void 0 : _a.call(analytics, {
|
|
329
|
+
userId: currentUserIdRef.current,
|
|
330
|
+
environment: runtimeMode,
|
|
364
331
|
stepId: record.stepId,
|
|
365
332
|
stepName: record.stepName,
|
|
366
333
|
stepType,
|
|
@@ -369,18 +336,6 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
369
336
|
selected: record.choices,
|
|
370
337
|
featureFlags: postHogFeatureFlagsRef.current,
|
|
371
338
|
});
|
|
372
|
-
if (!(analytics === null || analytics === void 0 ? void 0 : analytics.trackStepCompleted)) {
|
|
373
|
-
apiService.trackStepCompleted({
|
|
374
|
-
userId: currentUserIdRef.current,
|
|
375
|
-
stepId: record.stepId,
|
|
376
|
-
stepName: record.stepName,
|
|
377
|
-
stepType,
|
|
378
|
-
startedAt,
|
|
379
|
-
endedAt: record.completedAt,
|
|
380
|
-
selected: record.choices,
|
|
381
|
-
});
|
|
382
|
-
capturePostHogStepEvent('step_completed', Object.assign({ distinct_id: currentUserIdRef.current, funnel_id: FUNNEL_ID || undefined, funnel_version_id: FUNNEL_VERSION_ID || undefined, project_id: PROJECT_ID || undefined, environment: runtimeMode, step_id: record.stepId, step_name: record.stepName, step_type: stepType, started_at: startedAt, ended_at: record.completedAt, duration_ms: Number.isFinite(durationMs) ? durationMs : undefined, selected: record.choices }, buildFeatureFlagProperties(postHogFeatureFlagsRef.current)));
|
|
383
|
-
}
|
|
384
339
|
}
|
|
385
340
|
setUser((prev) => {
|
|
386
341
|
var _a, _b;
|
|
@@ -430,25 +385,19 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
430
385
|
stepStartedAtByIdRef.current[renderedStepId] = startedAt;
|
|
431
386
|
if (!isPreviewRuntime) {
|
|
432
387
|
(_a = analytics === null || analytics === void 0 ? void 0 : analytics.trackStepStarted) === null || _a === void 0 ? void 0 : _a.call(analytics, {
|
|
388
|
+
userId: currentUserIdRef.current,
|
|
389
|
+
environment: runtimeMode,
|
|
433
390
|
stepId: renderedStepId,
|
|
434
391
|
stepName,
|
|
435
392
|
stepType,
|
|
436
393
|
startedAt,
|
|
437
394
|
featureFlags: postHogFeatureFlagsRef.current,
|
|
438
395
|
});
|
|
439
|
-
if (!(analytics === null || analytics === void 0 ? void 0 : analytics.trackStepStarted)) {
|
|
440
|
-
apiService.trackStepStarted({
|
|
441
|
-
userId: currentUserIdRef.current,
|
|
442
|
-
stepId: renderedStepId,
|
|
443
|
-
stepName,
|
|
444
|
-
stepType,
|
|
445
|
-
startedAt,
|
|
446
|
-
});
|
|
447
|
-
capturePostHogStepEvent('step_started', Object.assign({ distinct_id: currentUserIdRef.current, funnel_id: FUNNEL_ID || undefined, funnel_version_id: FUNNEL_VERSION_ID || undefined, project_id: PROJECT_ID || undefined, environment: runtimeMode, step_id: renderedStepId, step_name: stepName, step_type: stepType, started_at: startedAt }, buildFeatureFlagProperties(postHogFeatureFlagsRef.current)));
|
|
448
|
-
}
|
|
449
396
|
if (!firstStepViewedTrackedRef.current && safeActiveStepId === defaultStepId) {
|
|
450
397
|
firstStepViewedTrackedRef.current = true;
|
|
451
398
|
(_b = analytics === null || analytics === void 0 ? void 0 : analytics.trackFunnelStarted) === null || _b === void 0 ? void 0 : _b.call(analytics, {
|
|
399
|
+
userId: currentUserIdRef.current,
|
|
400
|
+
environment: runtimeMode,
|
|
452
401
|
stepId: renderedStepId,
|
|
453
402
|
stepName,
|
|
454
403
|
stepType,
|
|
@@ -456,6 +405,8 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
456
405
|
featureFlags: postHogFeatureFlagsRef.current,
|
|
457
406
|
});
|
|
458
407
|
(_c = analytics === null || analytics === void 0 ? void 0 : analytics.trackFirstStepViewed) === null || _c === void 0 ? void 0 : _c.call(analytics, {
|
|
408
|
+
userId: currentUserIdRef.current,
|
|
409
|
+
environment: runtimeMode,
|
|
459
410
|
stepId: renderedStepId,
|
|
460
411
|
stepName,
|
|
461
412
|
stepType,
|
|
@@ -483,6 +434,8 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
483
434
|
engagedStepIdsRef.current.add(engagedStepId);
|
|
484
435
|
const engagedAt = new Date().toISOString();
|
|
485
436
|
(_a = analytics === null || analytics === void 0 ? void 0 : analytics.trackStepEngaged) === null || _a === void 0 ? void 0 : _a.call(analytics, {
|
|
437
|
+
userId: currentUserIdRef.current,
|
|
438
|
+
environment: runtimeMode,
|
|
486
439
|
stepId: engagedStepId,
|
|
487
440
|
stepName: engagedStepName,
|
|
488
441
|
stepType: engagedStepType,
|
|
@@ -492,22 +445,6 @@ export function useFunnelFlowController({ analytics, initialStepId, lockToInitia
|
|
|
492
445
|
engagementThresholdMs: FIRST_STEP_ENGAGEMENT_THRESHOLD_MS,
|
|
493
446
|
featureFlags: postHogFeatureFlagsRef.current,
|
|
494
447
|
});
|
|
495
|
-
if (!(analytics === null || analytics === void 0 ? void 0 : analytics.trackStepEngaged)) {
|
|
496
|
-
apiService.trackFunnelEvent({
|
|
497
|
-
userId: currentUserIdRef.current,
|
|
498
|
-
eventType: 'step_engaged',
|
|
499
|
-
stepId: engagedStepId,
|
|
500
|
-
stepName: engagedStepName,
|
|
501
|
-
stepType: engagedStepType,
|
|
502
|
-
startedAt: engagedStartedAt,
|
|
503
|
-
endedAt: engagedAt,
|
|
504
|
-
metadata: {
|
|
505
|
-
durationMs: FIRST_STEP_ENGAGEMENT_THRESHOLD_MS,
|
|
506
|
-
engagementThresholdMs: FIRST_STEP_ENGAGEMENT_THRESHOLD_MS,
|
|
507
|
-
},
|
|
508
|
-
});
|
|
509
|
-
capturePostHogStepEvent('step_engaged', Object.assign({ distinct_id: currentUserIdRef.current, funnel_id: FUNNEL_ID || undefined, funnel_version_id: FUNNEL_VERSION_ID || undefined, project_id: PROJECT_ID || undefined, environment: runtimeMode, step_id: engagedStepId, step_name: engagedStepName, step_type: engagedStepType, started_at: engagedStartedAt, ended_at: engagedAt, duration_ms: FIRST_STEP_ENGAGEMENT_THRESHOLD_MS, engagement_threshold_ms: FIRST_STEP_ENGAGEMENT_THRESHOLD_MS }, buildFeatureFlagProperties(postHogFeatureFlagsRef.current)));
|
|
510
|
-
}
|
|
511
448
|
}, FIRST_STEP_ENGAGEMENT_THRESHOLD_MS);
|
|
512
449
|
return () => window.clearTimeout(timer);
|
|
513
450
|
}, [
|
|
@@ -11,26 +11,6 @@ export type AppUser = {
|
|
|
11
11
|
type AppUserInput = Omit<AppUser, 'document'> & {
|
|
12
12
|
document?: Record<string, unknown>;
|
|
13
13
|
};
|
|
14
|
-
export type FunnelEvent = {
|
|
15
|
-
userId: string;
|
|
16
|
-
eventType: string;
|
|
17
|
-
stepId?: string;
|
|
18
|
-
stepName?: string;
|
|
19
|
-
stepType?: string;
|
|
20
|
-
startedAt?: string;
|
|
21
|
-
endedAt?: string;
|
|
22
|
-
selected?: Record<string, unknown>;
|
|
23
|
-
metadata?: Record<string, unknown>;
|
|
24
|
-
};
|
|
25
|
-
export type StepCompletionEvent = {
|
|
26
|
-
userId: string;
|
|
27
|
-
stepId: string;
|
|
28
|
-
stepName: string;
|
|
29
|
-
stepType?: string;
|
|
30
|
-
startedAt: string;
|
|
31
|
-
endedAt: string;
|
|
32
|
-
selected: Record<string, unknown>;
|
|
33
|
-
};
|
|
34
14
|
export type ManageSubscriptionsResponse = {
|
|
35
15
|
user: {
|
|
36
16
|
id: string;
|
|
@@ -100,16 +80,6 @@ declare class ApiService {
|
|
|
100
80
|
userId?: string;
|
|
101
81
|
source?: 'camera' | 'upload';
|
|
102
82
|
}): Promise<TempPhotoUploadResult>;
|
|
103
|
-
private sendEventAsync;
|
|
104
|
-
trackFunnelEvent(event: FunnelEvent): void;
|
|
105
|
-
trackStepStarted(input: {
|
|
106
|
-
userId: string;
|
|
107
|
-
stepId: string;
|
|
108
|
-
stepName: string;
|
|
109
|
-
stepType?: string;
|
|
110
|
-
startedAt: string;
|
|
111
|
-
}): void;
|
|
112
|
-
trackStepCompleted(event: StepCompletionEvent): void;
|
|
113
83
|
getManageSubscriptions(): Promise<ManageSubscriptionsResponse>;
|
|
114
84
|
updateSubscription(input: {
|
|
115
85
|
subscriptionId: string;
|
|
@@ -121,18 +121,6 @@ const persistUserId = (value, funnelId = FUNNEL_ID) => {
|
|
|
121
121
|
}
|
|
122
122
|
return normalized;
|
|
123
123
|
};
|
|
124
|
-
const buildSdkEvent = (event) => {
|
|
125
|
-
return {
|
|
126
|
-
eventType: event.eventType,
|
|
127
|
-
stepId: event.stepId || null,
|
|
128
|
-
stepName: event.stepName || null,
|
|
129
|
-
stepType: event.stepType || null,
|
|
130
|
-
startedAt: event.startedAt || null,
|
|
131
|
-
endedAt: event.endedAt || null,
|
|
132
|
-
selected: event.selected || {},
|
|
133
|
-
metadata: Object.assign({ environment: resolveRuntimeAnalyticsEnvironment() }, (event.metadata || {})),
|
|
134
|
-
};
|
|
135
|
-
};
|
|
136
124
|
const withMergedAttributionDocument = (document, attribution) => {
|
|
137
125
|
const normalizedDocument = asRecord(document);
|
|
138
126
|
if (!attribution) {
|
|
@@ -455,61 +443,6 @@ class ApiService {
|
|
|
455
443
|
uploadedAt,
|
|
456
444
|
};
|
|
457
445
|
}
|
|
458
|
-
sendEventAsync(event) {
|
|
459
|
-
const publishableKey = getFunnelSdkPublishableKey();
|
|
460
|
-
if (!publishableKey) {
|
|
461
|
-
return;
|
|
462
|
-
}
|
|
463
|
-
const payload = JSON.stringify({
|
|
464
|
-
publishableKey,
|
|
465
|
-
funnelId: FUNNEL_ID || undefined,
|
|
466
|
-
funnelVersionId: FUNNEL_VERSION_ID || undefined,
|
|
467
|
-
user_id: event.userId,
|
|
468
|
-
events: [buildSdkEvent(event)],
|
|
469
|
-
});
|
|
470
|
-
const endpoint = buildMainApiUrl('/sdk/public/events');
|
|
471
|
-
if (canUseDom() && typeof navigator.sendBeacon === 'function') {
|
|
472
|
-
const blob = new Blob([payload], { type: 'application/json' });
|
|
473
|
-
const accepted = navigator.sendBeacon(endpoint, blob);
|
|
474
|
-
if (accepted) {
|
|
475
|
-
return;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
void fetch(endpoint, {
|
|
479
|
-
method: 'POST',
|
|
480
|
-
headers: buildSdkHeaders({ 'Content-Type': 'application/json' }),
|
|
481
|
-
body: payload,
|
|
482
|
-
keepalive: true,
|
|
483
|
-
}).catch(() => {
|
|
484
|
-
// Never block UI if analytics delivery fails.
|
|
485
|
-
});
|
|
486
|
-
}
|
|
487
|
-
trackFunnelEvent(event) {
|
|
488
|
-
const userId = persistUserId(event.userId || this.getOrCreateClientUserId(), FUNNEL_ID);
|
|
489
|
-
this.sendEventAsync(Object.assign(Object.assign({}, event), { userId }));
|
|
490
|
-
}
|
|
491
|
-
trackStepStarted(input) {
|
|
492
|
-
this.trackFunnelEvent({
|
|
493
|
-
userId: input.userId,
|
|
494
|
-
eventType: 'step_start',
|
|
495
|
-
stepId: input.stepId,
|
|
496
|
-
stepName: input.stepName,
|
|
497
|
-
stepType: input.stepType,
|
|
498
|
-
startedAt: input.startedAt,
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
trackStepCompleted(event) {
|
|
502
|
-
this.trackFunnelEvent({
|
|
503
|
-
userId: event.userId,
|
|
504
|
-
eventType: 'step_end',
|
|
505
|
-
stepId: event.stepId,
|
|
506
|
-
stepName: event.stepName,
|
|
507
|
-
stepType: event.stepType,
|
|
508
|
-
startedAt: event.startedAt,
|
|
509
|
-
endedAt: event.endedAt,
|
|
510
|
-
selected: event.selected,
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
446
|
async getManageSubscriptions() {
|
|
514
447
|
const userId = this.getSubscriptionManagementUserId();
|
|
515
448
|
const stripeCustomerId = this.getSubscriptionManagementStripeCustomerId();
|