1. Marketing Layout: speed up rendering by retrieving user session from cookies instead of using server side request 2. Use "redirecting" state when signing in to keep displaying a loading state while Next.js redirects to home page 3. Use "useCallback" to prevent double tracking when switching pages 4. Add links pre-fetching in marketing navigation 5. Add new pending state to MFA verification form 6. Pre-fetch sign-in/sign-up pages 7. Fix i18n when using regional languages 8. currency formatter should default to the region if it exists 9. Update packages
105 lines
2.7 KiB
TypeScript
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]);
|
|
}
|