w-funnel/src/components/providers/PixelsProvider.tsx
2025-10-08 01:55:37 +02:00

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}
</>
);
}