Files
medreport_mrb2b/components/analytics-provider.tsx
2025-06-08 16:18:30 +03:00

105 lines
2.7 KiB
TypeScript

'use client';
import { useCallback, useEffect } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';
import { analytics } from '@kit/analytics';
import {
AppEvent,
AppEventType,
ConsumerProvidedEventTypes,
useAppEvents,
} from '@kit/shared/events';
import { isBrowser } from '@kit/shared/utils';
type AnalyticsMapping<
T extends ConsumerProvidedEventTypes = NonNullable<unknown>,
> = {
[K in AppEventType<T>]?: (event: AppEvent<T, K>) => unknown;
};
/**
* Hook to subscribe to app events and map them to analytics actions
* @param mapping
*/
function useAnalyticsMapping<T extends ConsumerProvidedEventTypes>(
mapping: AnalyticsMapping<T>,
) {
const appEvents = useAppEvents<T>();
useEffect(() => {
const subscriptions = Object.entries(mapping).map(
([eventType, handler]) => {
appEvents.on(eventType as AppEventType<T>, handler);
return () => appEvents.off(eventType as AppEventType<T>, handler);
},
);
return () => {
subscriptions.forEach((unsubscribe) => unsubscribe());
};
}, [appEvents, mapping]);
}
/**
* Define a mapping of app events to analytics actions
* Add new mappings here to track new events in the analytics service from app events
*/
const analyticsMapping: AnalyticsMapping = {
'user.signedIn': (event) => {
const { userId, ...traits } = event.payload;
if (userId) {
return analytics.identify(userId, traits);
}
},
'user.signedUp': (event) => {
return analytics.trackEvent(event.type, event.payload);
},
'checkout.started': (event) => {
return analytics.trackEvent(event.type, event.payload);
},
'user.updated': (event) => {
return analytics.trackEvent(event.type, event.payload);
},
};
function AnalyticsProviderBrowser(props: React.PropsWithChildren) {
// Subscribe to app events and map them to analytics actions
useAnalyticsMapping(analyticsMapping);
// Report page views to the analytics service
useReportPageView(useCallback((url) => analytics.trackPageView(url), []));
// Render children
return props.children;
}
/**
* Provider for the analytics service
*/
export function AnalyticsProvider(props: React.PropsWithChildren) {
if (!isBrowser()) {
return props.children;
}
return <AnalyticsProviderBrowser>{props.children}</AnalyticsProviderBrowser>;
}
/**
* Hook to report page views to the analytics service
* @param reportAnalyticsFn
*/
function useReportPageView(reportAnalyticsFn: (url: string) => unknown) {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
const url = [pathname, searchParams.toString()].filter(Boolean).join('?');
reportAnalyticsFn(url);
}, [pathname, reportAnalyticsFn, searchParams]);
}