From 02bfbb11125d1ffae749265a3467b2ec296b2e05 Mon Sep 17 00:00:00 2001 From: "dev.daminik00" Date: Fri, 31 Oct 2025 19:47:15 +0100 Subject: [PATCH] add yandex metrika improve --- ANALYTICS_IMPLEMENTATION.md | 123 +++++++++++++++ src/app/[locale]/layout.tsx | 42 +++--- src/components/analytics/PageViewTracker.tsx | 54 +++++++ .../analytics/YandexMetrika/YandexMetrika.tsx | 87 ++++------- .../analytics/YandexMetrika/index.ts | 2 +- src/components/analytics/index.ts | 2 + src/providers/analytics-provider.tsx | 24 +++ src/services/analytics/analyticsService.ts | 140 ++++++++++++++++++ src/services/analytics/index.ts | 1 + src/shared/constants/analytics.ts | 1 + src/types/index.ts | 4 +- 11 files changed, 402 insertions(+), 78 deletions(-) create mode 100644 ANALYTICS_IMPLEMENTATION.md create mode 100644 src/components/analytics/PageViewTracker.tsx create mode 100644 src/components/analytics/index.ts create mode 100644 src/providers/analytics-provider.tsx create mode 100644 src/services/analytics/analyticsService.ts create mode 100644 src/services/analytics/index.ts create mode 100644 src/shared/constants/analytics.ts diff --git a/ANALYTICS_IMPLEMENTATION.md b/ANALYTICS_IMPLEMENTATION.md new file mode 100644 index 0000000..46d71b2 --- /dev/null +++ b/ANALYTICS_IMPLEMENTATION.md @@ -0,0 +1,123 @@ +# Analytics System Implementation + +## Обзор + +В проект `witlab-app` была добавлена система аналитики на основе Yandex Metrika по аналогии с `witlab-funnel`: + +- **Yandex Metrika** - отслеживание просмотров страниц и событий +- **PageViewTracker** - автоматическая отслежка переходов между страницами +- **AnalyticsService** - управление параметрами пользователя и событиями + +## Структура файлов + +``` +src/ +├── components/analytics/ +│ ├── PageViewTracker.tsx # Отслеживание переходов +│ ├── YandexMetrika/ +│ │ ├── YandexMetrika.tsx # Компонент Яндекс Метрики +│ │ └── index.ts +│ └── index.ts # Экспорты аналитики +├── providers/ +│ └── analytics-provider.tsx # Провайдер аналитики +├── services/analytics/ +│ ├── analyticsService.ts # Сервис аналитики +│ └── index.ts +└── shared/constants/ + └── analytics.ts # Константы ID счетчиков +``` + +## Конфигурация + +### Статичные константы + +```typescript +// src/shared/constants/analytics.ts +export const YANDEX_METRIKA_ID = "103412914"; +``` + +## Использование + +### Автоматическая отслежка страниц + +Система автоматически отслеживает все переходы между страницами через `PageViewTracker`. + +### Параметры пользователя + +При инициализации система автоматически загружает данные пользователя через `/users/me` и устанавливает параметры в Yandex Metrika: + +- `user_id` - ID пользователя +- `email` - email пользователя +- `locale` - язык пользователя +- `timezone` - часовой пояс +- `profile_name`, `profile_gender`, `profile_age`, `profile_sign` - данные профиля +- `partner_gender`, `partner_age`, `partner_sign` - данные партнера +- `country`, `region`, `city` - геолокация + +### Отслеживание событий + +```typescript +import { analyticsService } from "@/services/analytics"; + +// Отправить событие в Yandex Metrika +analyticsService.trackEvent("button_click", { + button_name: "subscribe_now", + screen: "retaining" +}); +``` + +### Доступ к данным пользователя + +```typescript +import { analyticsService } from "@/services/analytics"; + +if (analyticsService.isReady()) { + const user = analyticsService.getUser(); + console.log("Current user:", user); +} +``` + +## Логирование + +Система предоставляет детальное логирование в консоли: + +``` +✅ [YM] Page View Event Sent +✅ [Analytics] Service initialized with user data +✅ [YM] User parameters set +``` + +## Интеграция в layout + +Компоненты аналитики добавлены в `src/app/[locale]/layout.tsx`: + +```tsx + + + {/* ... */} + + {/* ... */} + +``` + +## Отличия от witlab-funnel + +1. **Только Yandex Metrika** - без Google Analytics +2. **Статичный ID** - Яндекс Метрика использует статичный ID вместо динамического из воронки +3. **Параметры пользователя** - Автоматическая загрузка и установка параметров из `/me` +4. **Унифицированный сервис** - Единый `AnalyticsService` для управления + +## Проверка работы + +1. Откройте консоль разработчика в браузере +2. Перейдите между страницами приложения +3. Вы увидите сообщения об отправке событий в YM +4. Проверьте наличие cookies `_ym_uid` + +## Совместимость + +- ✅ TypeScript +- ✅ ESLint (без ошибок, только предупреждения о существующих `any`) +- ✅ Next.js 15 +- ✅ Server-side rendering +- ✅ Динамические маршруты diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx index f9b67b4..fda543d 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/[locale]/layout.tsx @@ -9,10 +9,11 @@ import { hasLocale, NextIntlClientProvider } from "next-intl"; import { getMessages } from "next-intl/server"; import clsx from "clsx"; -import YandexMetrika from "@/components/analytics/YandexMetrika"; +import { PageViewTracker,YandexMetrika } from "@/components/analytics"; import { loadChatsList } from "@/entities/chats/loaders"; import { loadUser, loadUserId } from "@/entities/user/loaders"; import { routing } from "@/i18n/routing"; +import { AnalyticsProvider } from "@/providers/analytics-provider"; import { AppUiStoreProvider } from "@/providers/app-ui-store-provider"; import { AudioProvider } from "@/providers/audio-provider"; import { ChatsInitializationProvider } from "@/providers/chats-initialization-provider"; @@ -68,24 +69,29 @@ export default async function RootLayout({ return ( + {/* Analytics Components */} - - - - - - - - - {children} - - - - - - - - + + + + + + + + + + + + {children} + + + + + + + + + ); diff --git a/src/components/analytics/PageViewTracker.tsx b/src/components/analytics/PageViewTracker.tsx new file mode 100644 index 0000000..d8770ef --- /dev/null +++ b/src/components/analytics/PageViewTracker.tsx @@ -0,0 +1,54 @@ +"use client"; + +import { useEffect } from "react"; +import { usePathname, useSearchParams } from "next/navigation"; + +/** + * Wait for Yandex Metrika to be loaded + * Retry mechanism with timeout to handle async script loading + */ +async function waitForYandexMetrika(maxAttempts = 10, delayMs = 100): Promise { + for (let i = 0; i < maxAttempts; i++) { + if (typeof window !== "undefined" && + typeof window.ym === "function" && + window.__YM_COUNTER_ID__) { + return true; + } + await new Promise(resolve => setTimeout(resolve, delayMs)); + } + return false; +} + +/** + * Page View Tracker Component + * + * Tracks page views in Yandex Metrika + * when route changes occur (client-side navigation). + * + * Must be included in the app layout or root component. + */ +export function PageViewTracker() { + const pathname = usePathname(); + const searchParams = useSearchParams(); + + useEffect(() => { + const url = pathname + (searchParams?.toString() ? `?${searchParams.toString()}` : ""); + + // Track page view in Yandex Metrika (with retry logic) + const trackYandexMetrika = async () => { + const isYmAvailable = await waitForYandexMetrika(); + + if (isYmAvailable && typeof window.ym === "function") { + const counterId = window.__YM_COUNTER_ID__; + if (counterId) { + window.ym(counterId, "hit", url); + } + } + }; + + // Execute YM tracking + trackYandexMetrika(); + }, [pathname, searchParams]); + + return null; +} diff --git a/src/components/analytics/YandexMetrika/YandexMetrika.tsx b/src/components/analytics/YandexMetrika/YandexMetrika.tsx index 0b4cdcb..0b54592 100644 --- a/src/components/analytics/YandexMetrika/YandexMetrika.tsx +++ b/src/components/analytics/YandexMetrika/YandexMetrika.tsx @@ -1,79 +1,52 @@ "use client"; -import { useEffect } from "react"; import Script from "next/script"; -const YANDEX_METRIKA_ID = 103412914; - -export default function YandexMetrika() { - useEffect(() => { - // Initialize Yandex.Metrika after script loads - const initializeYandexMetrika = () => { - if (typeof window.ym === "function") { - try { - window.ym(YANDEX_METRIKA_ID, "init", { - webvisor: true, - clickmap: true, - accurateTrackBounce: true, - trackLinks: true, - }); - } catch { - // Silently handle initialization errors - } - } - }; - - // Check if ym is already available or wait for it - if (typeof window.ym === "function") { - initializeYandexMetrika(); - } else { - // Wait for script to load - const checkYm = setInterval(() => { - if (typeof window.ym === "function") { - initializeYandexMetrika(); - clearInterval(checkYm); - } - }, 100); - - // Cleanup interval after 10 seconds - setTimeout(() => { - clearInterval(checkYm); - }, 10000); - - return () => clearInterval(checkYm); - } - }, []); +import { YANDEX_METRIKA_ID } from "@/shared/constants/analytics"; +/** + * Yandex Metrika Integration Component + * + * Loads Yandex Metrika tracking script dynamically using static counter ID. + * + * Initializes with: clickmap, trackLinks, accurateTrackBounce, webvisor. + * Page views are tracked by PageViewTracker component on route changes. + */ +export function YandexMetrika() { return ( <> - {/* Yandex.Metrika counter */}