add ym data
This commit is contained in:
parent
ea381ea399
commit
fcd3e0da3f
@ -72,7 +72,10 @@ export default async function FunnelLayout({
|
||||
}
|
||||
|
||||
return (
|
||||
<UnleashSessionProvider funnelId={funnelId}>
|
||||
<UnleashSessionProvider
|
||||
funnelId={funnelId}
|
||||
googleAnalyticsId={funnel.meta.googleAnalyticsId}
|
||||
>
|
||||
<PixelsProvider
|
||||
googleAnalyticsId={funnel.meta.googleAnalyticsId}
|
||||
yandexMetrikaId={funnel.meta.yandexMetrikaId}
|
||||
|
||||
@ -17,6 +17,7 @@ import { getZodiacSign } from "@/lib/funnel/zodiac";
|
||||
import { useSession } from "@/hooks/session/useSession";
|
||||
import { buildSessionDataFromScreen } from "@/lib/funnel/registrationHelpers";
|
||||
import { useUnleashContext } from "@/lib/funnel/unleash";
|
||||
import { metricService } from "@/services/analytics/metricService";
|
||||
|
||||
// Функция для оценки длины пути пользователя на основе текущих ответов
|
||||
function estimatePathLength(
|
||||
@ -67,6 +68,7 @@ export function FunnelRuntime({ funnel, initialScreenId }: FunnelRuntimeProps) {
|
||||
const router = useRouter();
|
||||
const { createSession, updateSession } = useSession({
|
||||
funnelId: funnel.meta.id,
|
||||
googleAnalyticsId: funnel.meta.googleAnalyticsId,
|
||||
});
|
||||
const { answers, registerScreen, setAnswers, history } = useFunnelRuntime(
|
||||
funnel.meta.id
|
||||
@ -161,6 +163,19 @@ export function FunnelRuntime({ funnel, initialScreenId }: FunnelRuntimeProps) {
|
||||
answers[currentScreen.id]
|
||||
);
|
||||
|
||||
// ✅ Отправляем данные в userParams (параметры посетителя)
|
||||
// Используем ту же структуру что и для сессии (через registrationFieldKey)
|
||||
if (Object.keys(sessionData).length > 0) {
|
||||
metricService.userParams(sessionData);
|
||||
}
|
||||
|
||||
// ✅ Отправляем выбор пользователя в params (параметры визита)
|
||||
if (currentScreen.template === "list" && answers[currentScreen.id].length > 0) {
|
||||
metricService.sendVisitContext({
|
||||
[`answer_${currentScreen.id}`]: answers[currentScreen.id].join(','),
|
||||
});
|
||||
}
|
||||
|
||||
// Для date экранов с registrationFieldKey НЕ отправляем answers
|
||||
const shouldSkipAnswers =
|
||||
currentScreen.template === "date" &&
|
||||
@ -266,6 +281,16 @@ export function FunnelRuntime({ funnel, initialScreenId }: FunnelRuntimeProps) {
|
||||
if (shouldAutoAdvance) {
|
||||
// Собираем данные для сессии
|
||||
const sessionData = buildSessionDataFromScreen(currentScreen, ids);
|
||||
|
||||
// ✅ Отправляем данные в userParams (параметры посетителя)
|
||||
metricService.sendSessionDataToMetrics(sessionData);
|
||||
|
||||
// ✅ Отправляем выбор пользователя в params (параметры визита)
|
||||
if (currentScreen.template === "list" && ids.length > 0) {
|
||||
metricService.sendVisitContext({
|
||||
[`answer_${currentScreen.id}`]: ids.join(','),
|
||||
});
|
||||
}
|
||||
|
||||
updateSession({
|
||||
answers: {
|
||||
|
||||
@ -55,6 +55,7 @@ export function EmailTemplate({
|
||||
|
||||
const { authorization, isLoading, error } = useAuth({
|
||||
funnelId: funnel?.meta?.id ?? "preview",
|
||||
googleAnalyticsId: funnel?.meta?.googleAnalyticsId,
|
||||
registrationData,
|
||||
});
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import React, { createContext, useContext, useState } from "react";
|
||||
import { metricService } from "@/services/analytics/metricService";
|
||||
|
||||
interface TrialVariantSelectionContextValue {
|
||||
selectedVariantId: string | null;
|
||||
@ -31,6 +32,11 @@ export function TrialVariantSelectionProvider({
|
||||
if (typeof window !== 'undefined') {
|
||||
if (id) {
|
||||
sessionStorage.setItem(STORAGE_KEY, id);
|
||||
|
||||
// ✅ Отправляем выбранный продукт в параметры визита
|
||||
metricService.sendVisitContext({
|
||||
selectedProductId: id,
|
||||
});
|
||||
} else {
|
||||
sessionStorage.removeItem(STORAGE_KEY);
|
||||
}
|
||||
|
||||
@ -8,12 +8,14 @@ import { filterNullKeysOfObject } from "@/shared/utils/filter-object";
|
||||
import { createAuthorization } from "@/entities/user/actions";
|
||||
import { setAuthTokenToCookie } from "@/entities/user/serverActions";
|
||||
import analyticsService, { AnalyticsEvent, AnalyticsPlatform } from "@/services/analytics/analyticsService";
|
||||
import { metricService } from "@/services/analytics/metricService";
|
||||
|
||||
// TODO
|
||||
const locale = "en";
|
||||
|
||||
interface IUseAuthProps {
|
||||
funnelId: string;
|
||||
googleAnalyticsId?: string;
|
||||
/**
|
||||
* Дополнительные данные для регистрации пользователя.
|
||||
* Будут объединены с базовым payload при авторизации.
|
||||
@ -22,8 +24,8 @@ interface IUseAuthProps {
|
||||
registrationData?: Record<string, any>;
|
||||
}
|
||||
|
||||
export const useAuth = ({ funnelId, registrationData }: IUseAuthProps) => {
|
||||
const { updateSession } = useSession({ funnelId });
|
||||
export const useAuth = ({ funnelId, googleAnalyticsId, registrationData }: IUseAuthProps) => {
|
||||
const { updateSession } = useSession({ funnelId, googleAnalyticsId });
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@ -108,6 +110,19 @@ export const useAuth = ({ funnelId, registrationData }: IUseAuthProps) => {
|
||||
source: funnelId,
|
||||
UserID: userId,
|
||||
});
|
||||
|
||||
// ✅ Отправляем UserID и email в userParams (параметры посетителя)
|
||||
metricService.setUserID(userId);
|
||||
metricService.userParams({
|
||||
UserID: userId,
|
||||
email,
|
||||
});
|
||||
|
||||
// ✅ Отправляем email и userId в params (параметры визита)
|
||||
metricService.sendVisitContext({
|
||||
email,
|
||||
userId,
|
||||
});
|
||||
}
|
||||
|
||||
await setAuthTokenToCookie(token);
|
||||
|
||||
@ -10,15 +10,17 @@ import { getClientTimezone } from "@/shared/utils/locales";
|
||||
import { parseQueryParams } from "@/shared/utils/url";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { setSessionIdToCookie } from "@/entities/session/serverActions";
|
||||
import { metricService } from "@/services/analytics/metricService";
|
||||
|
||||
// TODO
|
||||
const locale = "en";
|
||||
|
||||
interface IUseSessionProps {
|
||||
funnelId: string;
|
||||
googleAnalyticsId?: string;
|
||||
}
|
||||
|
||||
export const useSession = ({ funnelId }: IUseSessionProps) => {
|
||||
export const useSession = ({ funnelId, googleAnalyticsId }: IUseSessionProps) => {
|
||||
const localStorageKey = `${funnelId}_sessionId`;
|
||||
const sessionId =
|
||||
typeof window === "undefined" ? "" : localStorage.getItem(localStorageKey);
|
||||
@ -70,6 +72,19 @@ export const useSession = ({ funnelId }: IUseSessionProps) => {
|
||||
sessionFromServer?.status === "success"
|
||||
) {
|
||||
await setSessionId(sessionFromServer.sessionId);
|
||||
|
||||
// ✅ Отправляем sessionId в userParams (параметры посетителя)
|
||||
metricService.userParams({
|
||||
sessionId: sessionFromServer.sessionId,
|
||||
});
|
||||
|
||||
// ✅ Отправляем контекст визита в params (параметры визита)
|
||||
metricService.sendVisitContext({
|
||||
sessionId: sessionFromServer.sessionId,
|
||||
funnelId,
|
||||
gaId: googleAnalyticsId,
|
||||
});
|
||||
|
||||
return sessionFromServer;
|
||||
}
|
||||
console.error(
|
||||
@ -89,7 +104,7 @@ export const useSession = ({ funnelId }: IUseSessionProps) => {
|
||||
sessionId: "",
|
||||
};
|
||||
}
|
||||
}, [sessionId, timezone, setSessionId, funnelId]);
|
||||
}, [sessionId, timezone, setSessionId, funnelId, googleAnalyticsId]);
|
||||
|
||||
const updateSession = useCallback(
|
||||
async (data: IUpdateSessionRequest["data"]) => {
|
||||
|
||||
@ -7,6 +7,7 @@ import { useSession } from "@/hooks/session/useSession";
|
||||
interface UnleashSessionProviderProps {
|
||||
children: ReactNode;
|
||||
funnelId: string;
|
||||
googleAnalyticsId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -15,10 +16,11 @@ interface UnleashSessionProviderProps {
|
||||
export function UnleashSessionProvider({
|
||||
children,
|
||||
funnelId,
|
||||
googleAnalyticsId,
|
||||
}: UnleashSessionProviderProps) {
|
||||
const [sessionId, setSessionId] = useState<string | null>(null);
|
||||
const [isReady, setIsReady] = useState(false);
|
||||
const { createSession } = useSession({ funnelId });
|
||||
const { createSession } = useSession({ funnelId, googleAnalyticsId });
|
||||
|
||||
useEffect(() => {
|
||||
const initSession = async () => {
|
||||
|
||||
@ -65,7 +65,9 @@ export function useUnleashAnalytics() {
|
||||
console.warn("⚠️ [Google Analytics] Not available - gtag function not found");
|
||||
}
|
||||
|
||||
// ✅ 2. Отправляем в Яндекс Метрику через params (параметры визита)
|
||||
// ✅ 2. Отправляем в Яндекс Метрику через params (параметры ВИЗИТА)
|
||||
// ВАЖНО: AB тесты - это параметры ВИЗИТА (params), а не посетителя (userParams)
|
||||
// Идентично aura-webapp: используем прямой вызов window.ym()
|
||||
const ymAvailable = typeof window !== "undefined" && typeof window.ym !== "undefined";
|
||||
const counterId = typeof window !== "undefined" ? window.__YM_COUNTER_ID__ : undefined;
|
||||
|
||||
@ -74,7 +76,6 @@ export function useUnleashAnalytics() {
|
||||
// ym() накопит вызов в очереди если скрипт еще не загрузился
|
||||
window.ym(counterId, 'params', {
|
||||
[`ab_test_${impressionEvent.featureName}`]: impressionEvent.variant,
|
||||
ab_test_app: impressionEvent.context.appName || "witlab-funnel",
|
||||
});
|
||||
console.log("✅ [Yandex Metrika] AB test params sent:", {
|
||||
counterId,
|
||||
|
||||
338
src/services/analytics/metricService.ts
Normal file
338
src/services/analytics/metricService.ts
Normal file
@ -0,0 +1,338 @@
|
||||
/**
|
||||
* Metric Service для Яндекс Метрики и Google Analytics
|
||||
*
|
||||
* Паттерн идентичен aura-webapp/src/services/metric/metricService.ts
|
||||
*
|
||||
* Основные методы:
|
||||
* - setUserID: установить ID пользователя (для YM и GA)
|
||||
* - userParams: отправить параметры ПОСЕТИТЕЛЯ (sessionId, email, age, gender и т.д.)
|
||||
* - params: отправить параметры ВИЗИТА (AB тест варианты, источник и т.д.)
|
||||
* - reachGoal: достижение цели
|
||||
*/
|
||||
|
||||
/**
|
||||
* Параметры посетителя (постоянные характеристики)
|
||||
* Передаются через window.ym(counterId, "userParams", {...})
|
||||
*
|
||||
* Эти данные привязываются к ClientID и распространяются
|
||||
* на всю историю визитов пользователя
|
||||
*/
|
||||
interface IUserParams {
|
||||
UserID?: string | number;
|
||||
sessionId?: string;
|
||||
email?: string;
|
||||
gender?: string;
|
||||
age?: number;
|
||||
partnerGender?: string;
|
||||
partnerAge?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Параметры визита (временные данные о визите)
|
||||
* Передаются через window.ym(counterId, "params", {...})
|
||||
*
|
||||
* Эти данные привязываются к конкретному визиту
|
||||
*/
|
||||
interface IVisitParams {
|
||||
email?: string;
|
||||
userId?: string | number;
|
||||
sessionId?: string;
|
||||
gaId?: string; // Google Analytics Measurement ID (e.g., G-XXXXXXXXXX)
|
||||
gaClientId?: string; // Google Analytics Client ID from _ga cookie
|
||||
ymClientId?: string; // Yandex Metrika Client ID from _ym_uid cookie
|
||||
funnelId?: string;
|
||||
selectedProductId?: string;
|
||||
[key: string]: string | number | boolean | undefined;
|
||||
}
|
||||
|
||||
const checkIsAvailableYandexMetric = (): boolean => {
|
||||
if (typeof window === 'undefined') return false;
|
||||
|
||||
if (typeof window.ym === 'undefined' || !window.__YM_COUNTER_ID__) {
|
||||
console.warn('[MetricService] Yandex Metrika not initialized');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const checkIsAvailableGoogleAnalytics = (): boolean => {
|
||||
if (typeof window === 'undefined') return false;
|
||||
|
||||
if (typeof window.gtag === 'undefined') {
|
||||
console.warn('[MetricService] Google Analytics not initialized');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Установить ID пользователя
|
||||
* Вызывается после авторизации
|
||||
*/
|
||||
const setUserID = (userId: string | number): void => {
|
||||
console.log('[MetricService] setUserID:', userId);
|
||||
|
||||
// Yandex Metrika
|
||||
if (checkIsAvailableYandexMetric() && window.__YM_COUNTER_ID__) {
|
||||
window.ym(window.__YM_COUNTER_ID__, 'setUserID', String(userId));
|
||||
console.log('✅ [Yandex Metrika] setUserID:', userId);
|
||||
}
|
||||
|
||||
// Google Analytics
|
||||
if (checkIsAvailableGoogleAnalytics()) {
|
||||
window.gtag('config', 'GA_MEASUREMENT_ID', {
|
||||
user_id: String(userId),
|
||||
});
|
||||
console.log('✅ [Google Analytics] setUserID:', userId);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Отправить параметры ПОСЕТИТЕЛЯ
|
||||
*
|
||||
* Эти параметры привязываются к ClientID и распространяются
|
||||
* на всю историю визитов пользователя
|
||||
*
|
||||
* Примеры:
|
||||
* - userParams({ sessionId: 'abc123' }) - при создании сессии
|
||||
* - userParams({ email: 'user@example.com', UserID: 123 }) - после авторизации
|
||||
* - userParams({ gender: 'female', age: 25 }) - после ввода данных
|
||||
*/
|
||||
const userParams = (parameters: Partial<IUserParams>): void => {
|
||||
console.log('[MetricService] userParams:', parameters);
|
||||
|
||||
// Yandex Metrika
|
||||
if (checkIsAvailableYandexMetric() && window.__YM_COUNTER_ID__) {
|
||||
window.ym(window.__YM_COUNTER_ID__, 'userParams', parameters);
|
||||
console.log('✅ [Yandex Metrika] userParams sent:', parameters);
|
||||
}
|
||||
|
||||
// Google Analytics
|
||||
if (checkIsAvailableGoogleAnalytics()) {
|
||||
window.gtag('config', 'GA_MEASUREMENT_ID', {
|
||||
send_page_view: false,
|
||||
...parameters,
|
||||
});
|
||||
console.log('✅ [Google Analytics] config sent:', parameters);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Отправить параметры ВИЗИТА
|
||||
*
|
||||
* Эти параметры привязываются к конкретному визиту
|
||||
*
|
||||
* Примеры:
|
||||
* - params({ ab_test_button: 'v1' }) - AB тест вариант
|
||||
* - params({ source: 'facebook' }) - источник трафика
|
||||
*/
|
||||
const params = (parameters: IVisitParams): void => {
|
||||
console.log('[MetricService] params:', parameters);
|
||||
|
||||
// Yandex Metrika
|
||||
if (checkIsAvailableYandexMetric() && window.__YM_COUNTER_ID__) {
|
||||
window.ym(window.__YM_COUNTER_ID__, 'params', parameters);
|
||||
console.log('✅ [Yandex Metrika] params sent:', parameters);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Достижение цели
|
||||
*/
|
||||
const reachGoal = (goal: string, params?: Record<string, unknown>): void => {
|
||||
console.log('[MetricService] reachGoal:', goal, params);
|
||||
|
||||
// Yandex Metrika
|
||||
if (checkIsAvailableYandexMetric() && window.__YM_COUNTER_ID__) {
|
||||
window.ym(window.__YM_COUNTER_ID__, 'reachGoal', goal, params);
|
||||
console.log('✅ [Yandex Metrika] reachGoal sent:', goal);
|
||||
}
|
||||
|
||||
// Google Analytics
|
||||
if (checkIsAvailableGoogleAnalytics()) {
|
||||
window.gtag('event', goal, params);
|
||||
console.log('✅ [Google Analytics] event sent:', goal);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Извлекает данные для метрики из session data
|
||||
* Отправляет только релевантные поля: gender, age, partnerGender, partnerAge
|
||||
*/
|
||||
const sendSessionDataToMetrics = (sessionData: Record<string, unknown>): void => {
|
||||
const metrics: Partial<IUserParams> = {};
|
||||
|
||||
// Извлекаем gender (может быть в profile.gender или просто gender)
|
||||
if (typeof sessionData.gender === 'string') {
|
||||
metrics.gender = sessionData.gender;
|
||||
} else if (sessionData.profile && typeof sessionData.profile === 'object') {
|
||||
const profile = sessionData.profile as Record<string, unknown>;
|
||||
if (typeof profile.gender === 'string') {
|
||||
metrics.gender = profile.gender;
|
||||
}
|
||||
if (typeof profile.partnerGender === 'string') {
|
||||
metrics.partnerGender = profile.partnerGender;
|
||||
}
|
||||
}
|
||||
|
||||
// Извлекаем partner gender (может быть в partner.gender или partnerGender)
|
||||
if (typeof sessionData.partnerGender === 'string') {
|
||||
metrics.partnerGender = sessionData.partnerGender;
|
||||
} else if (sessionData.partner && typeof sessionData.partner === 'object') {
|
||||
const partner = sessionData.partner as Record<string, unknown>;
|
||||
if (typeof partner.gender === 'string') {
|
||||
metrics.partnerGender = partner.gender;
|
||||
}
|
||||
}
|
||||
|
||||
// Вычисляем age из birthdate если есть
|
||||
if (typeof sessionData.birthdate === 'string') {
|
||||
const age = calculateAge(sessionData.birthdate);
|
||||
if (age) metrics.age = age;
|
||||
} else if (sessionData.profile && typeof sessionData.profile === 'object') {
|
||||
const profile = sessionData.profile as Record<string, unknown>;
|
||||
if (typeof profile.birthdate === 'string') {
|
||||
const age = calculateAge(profile.birthdate);
|
||||
if (age) metrics.age = age;
|
||||
}
|
||||
}
|
||||
|
||||
// Вычисляем partner age если есть
|
||||
if (typeof sessionData.partnerBirthdate === 'string') {
|
||||
const age = calculateAge(sessionData.partnerBirthdate);
|
||||
if (age) metrics.partnerAge = age;
|
||||
} else if (sessionData.partner && typeof sessionData.partner === 'object') {
|
||||
const partner = sessionData.partner as Record<string, unknown>;
|
||||
if (typeof partner.birthdate === 'string') {
|
||||
const age = calculateAge(partner.birthdate);
|
||||
if (age) metrics.partnerAge = age;
|
||||
}
|
||||
}
|
||||
|
||||
// Отправляем только если есть данные
|
||||
if (Object.keys(metrics).length > 0) {
|
||||
userParams(metrics);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Вычисляет возраст из даты рождения
|
||||
* @param birthdate - дата в формате YYYY-MM-DD HH:mm
|
||||
*/
|
||||
const calculateAge = (birthdate: string): number | undefined => {
|
||||
try {
|
||||
const date = new Date(birthdate);
|
||||
if (isNaN(date.getTime())) return undefined;
|
||||
|
||||
const today = new Date();
|
||||
let age = today.getFullYear() - date.getFullYear();
|
||||
const monthDiff = today.getMonth() - date.getMonth();
|
||||
|
||||
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < date.getDate())) {
|
||||
age--;
|
||||
}
|
||||
|
||||
return age > 0 && age < 150 ? age : undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Извлекает Google Analytics Client ID из куки _ga
|
||||
* Формат куки: GA1.1.XXXXXXXXXX.YYYYYYYYYY
|
||||
* Возвращает: XXXXXXXXXX.YYYYYYYYYY
|
||||
*/
|
||||
const getGoogleAnalyticsClientId = (): string | undefined => {
|
||||
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
const gaCookie = document.cookie
|
||||
.split('; ')
|
||||
.find(row => row.startsWith('_ga='));
|
||||
|
||||
if (!gaCookie) return undefined;
|
||||
|
||||
const cookieValue = gaCookie.split('=')[1];
|
||||
// Формат: GA1.1.XXXXXXXXXX.YYYYYYYYYY
|
||||
// Извлекаем последние две части
|
||||
const parts = cookieValue.split('.');
|
||||
if (parts.length >= 3) {
|
||||
return parts.slice(2).join('.');
|
||||
}
|
||||
|
||||
return undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Извлекает Yandex Metrika Client ID из куки _ym_uid
|
||||
* Возвращает значение напрямую
|
||||
*/
|
||||
const getYandexMetrikaClientId = (): string | undefined => {
|
||||
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
const ymCookie = document.cookie
|
||||
.split('; ')
|
||||
.find(row => row.startsWith('_ym_uid='));
|
||||
|
||||
if (!ymCookie) return undefined;
|
||||
|
||||
return ymCookie.split('=')[1];
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Отправляет контекст визита в Яндекс Метрику
|
||||
* Это параметры визита (params), а не посетителя (userParams)
|
||||
*
|
||||
* Вызывается при:
|
||||
* - Создании сессии (sessionId, funnelId, gaId, gaClientId)
|
||||
* - Авторизации (email, userId)
|
||||
* - Выборе продукта на экране оплаты (selectedProductId)
|
||||
*/
|
||||
const sendVisitContext = (context: Partial<IVisitParams>): void => {
|
||||
// Автоматически добавляем GA Client ID и YM Client ID если их нет в контексте
|
||||
const gaClientId = context.gaClientId || getGoogleAnalyticsClientId();
|
||||
const ymClientId = context.ymClientId || getYandexMetrikaClientId();
|
||||
|
||||
const contextWithClientIds = {
|
||||
...context,
|
||||
...(gaClientId ? { gaClientId } : {}),
|
||||
...(ymClientId ? { ymClientId } : {}),
|
||||
};
|
||||
|
||||
console.log('[MetricService] sendVisitContext:', contextWithClientIds);
|
||||
|
||||
// Фильтруем undefined значения
|
||||
const filteredContext = Object.entries(contextWithClientIds).reduce((acc, [key, value]) => {
|
||||
if (value !== undefined) {
|
||||
acc[key] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {} as IVisitParams);
|
||||
|
||||
if (Object.keys(filteredContext).length > 0) {
|
||||
params(filteredContext);
|
||||
}
|
||||
};
|
||||
|
||||
export const metricService = {
|
||||
setUserID,
|
||||
userParams,
|
||||
params,
|
||||
reachGoal,
|
||||
sendSessionDataToMetrics,
|
||||
sendVisitContext,
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user