88 lines
2.7 KiB
TypeScript
88 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState, type ReactNode } from "react";
|
|
import { FacebookPixels, GoogleAnalytics, YandexMetrika, PageViewTracker } from "@/components/analytics";
|
|
import { getPixels } from "@/entities/session/actions";
|
|
import { getSourceByPathname } from "@/shared/utils/source";
|
|
|
|
interface PixelsProviderProps {
|
|
children: ReactNode;
|
|
googleAnalyticsId?: string;
|
|
yandexMetrikaId?: string;
|
|
}
|
|
|
|
/**
|
|
* Pixels Provider Component
|
|
*
|
|
* Loads tracking scripts for Facebook Pixels, Google Analytics, and Yandex Metrika.
|
|
*
|
|
* IMPORTANT: This component should be placed in a layout (not in components that re-render on navigation)
|
|
* to avoid duplicate API requests. Currently used in app/[funnelId]/layout.tsx
|
|
*
|
|
* Facebook Pixels are loaded from backend API (cached in localStorage).
|
|
* Google Analytics and Yandex Metrika IDs come from funnel configuration.
|
|
*
|
|
* Flow:
|
|
* 1. Check localStorage for cached FB pixels
|
|
* 2. If not cached, request from backend (errors are handled gracefully)
|
|
* 3. Save to localStorage if pixels received
|
|
* 4. Render GA and YM if IDs provided in funnel config
|
|
*/
|
|
export function PixelsProvider({ children, googleAnalyticsId, yandexMetrikaId }: PixelsProviderProps) {
|
|
const [pixels, setPixels] = useState<string[]>([]);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
const loadPixels = async () => {
|
|
try {
|
|
// Check localStorage first
|
|
const cachedPixels = localStorage.getItem("fb_pixels");
|
|
if (cachedPixels) {
|
|
const parsed = JSON.parse(cachedPixels);
|
|
setPixels(parsed);
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
|
|
// Load from backend
|
|
const locale = "en"; // TODO: Get from context or config
|
|
const source = getSourceByPathname();
|
|
const domain = window.location.hostname;
|
|
|
|
const response = await getPixels({
|
|
domain,
|
|
source,
|
|
locale,
|
|
});
|
|
|
|
const pixelIds = response?.data?.fb || [];
|
|
|
|
// Save to localStorage only if we got pixels
|
|
if (pixelIds.length > 0) {
|
|
localStorage.setItem("fb_pixels", JSON.stringify(pixelIds));
|
|
}
|
|
|
|
setPixels(pixelIds);
|
|
} catch (error) {
|
|
// Silently handle errors - pixels are optional
|
|
console.warn("Facebook pixels not available:", error instanceof Error ? error.message : error);
|
|
setPixels([]);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
loadPixels();
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
{!isLoading && <FacebookPixels pixels={pixels} />}
|
|
<GoogleAnalytics measurementId={googleAnalyticsId} />
|
|
<YandexMetrika counterId={yandexMetrikaId} />
|
|
<PageViewTracker />
|
|
{children}
|
|
</>
|
|
);
|
|
}
|