@scaleway/use-analytics
Version:
A small hook to handle events analytics
125 lines (124 loc) • 3.81 kB
JavaScript
import { jsx } from "react/jsx-runtime";
import { RudderAnalytics } from "@rudderstack/analytics-js";
import { useState, useEffect, useMemo, createContext, useContext } from "react";
import { useDeepCompareEffectNoCheck } from "use-deep-compare-effect";
import { pluginsSDKBaseURL, destSDKBaseURL } from "../constants.js";
import { defaultLoadOptions, defaultConsentOptions } from "./constants.js";
import { userMigrationsTraits } from "./segments/userMigrationsTraits.js";
const AnalyticsContext = createContext(
void 0
);
function useAnalytics() {
const context = useContext(
// @ts-expect-error Here we force cast the generic onto the useContext because the context is a
// global variable and cannot be generic
AnalyticsContext
);
if (context === void 0) {
throw new Error("useAnalytics must be used within a AnalyticsProvider");
}
return context;
}
function AnalyticsProvider({
children,
settings,
loadOptions,
shouldRenderOnlyWhenReady = false,
needConsent = true,
onError,
onEventError,
allowedConsents,
deniedConsents,
events,
onLoaded,
timeout
}) {
const [isAnalyticsReady, setIsAnalyticsReady] = useState(false);
const [internalAnalytics, setAnalytics] = useState(
void 0
);
useEffect(() => {
let timer;
if (!isAnalyticsReady && !internalAnalytics && timeout) {
if (shouldRenderOnlyWhenReady) {
timer = setTimeout(() => setIsAnalyticsReady(true), timeout);
onError?.(new Error("Analytics Setup Timeout"));
}
}
return () => {
clearTimeout(timer);
};
}, [
isAnalyticsReady,
internalAnalytics,
setIsAnalyticsReady,
shouldRenderOnlyWhenReady,
timeout,
onError
]);
const shouldLoad = useMemo(() => {
if (needConsent) {
return false;
}
return !!settings?.writeKey;
}, [settings?.writeKey, needConsent]);
useDeepCompareEffectNoCheck(() => {
if (shouldLoad && settings) {
const analytics = new RudderAnalytics();
analytics.load(settings.writeKey, settings.cdnURL, {
...defaultLoadOptions,
configUrl: settings.cdnURL,
destSDKBaseURL: destSDKBaseURL(settings.cdnURL),
pluginsSDKBaseURL: pluginsSDKBaseURL(settings.cdnURL),
onLoaded: (rudderAnalytics) => {
userMigrationsTraits(rudderAnalytics);
rudderAnalytics.consent({
...defaultConsentOptions,
consentManagement: {
enabled: true,
allowedConsentIds: allowedConsents,
deniedConsentIds: deniedConsents
}
});
onLoaded(rudderAnalytics);
setIsAnalyticsReady(true);
},
...loadOptions
});
analytics.ready(() => {
setAnalytics(analytics);
setIsAnalyticsReady(true);
});
}
}, [settings, loadOptions, shouldLoad]);
const value = useMemo(() => {
const curiedEvents = Object.entries(events).reduce(
(acc, [eventName, eventFn]) => ({
...acc,
[eventName]: eventFn(internalAnalytics, onEventError)
}),
{}
);
return {
analytics: internalAnalytics,
events: curiedEvents,
isAnalyticsReady
};
}, [events, internalAnalytics, isAnalyticsReady, onEventError]);
const shouldRender = !shouldRenderOnlyWhenReady || isAnalyticsReady && !needConsent;
useDeepCompareEffectNoCheck(() => {
internalAnalytics?.consent({
consentManagement: {
enabled: true,
allowedConsentIds: allowedConsents,
deniedConsentIds: deniedConsents
}
});
}, [allowedConsents, deniedConsents]);
return /* @__PURE__ */ jsx(AnalyticsContext.Provider, { value, children: shouldRender ? children : null });
}
export {
AnalyticsProvider,
AnalyticsProvider as default,
useAnalytics
};