UNPKG

@flagship.io/react-sdk

Version:
157 lines (156 loc) 6.21 kB
'use client'; import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime"; import { useState, useRef, useEffect } from 'react'; import Flagship, { DecisionMode, FSSdkStatus } from '@flagship.io/js-sdk'; import { FlagshipContext, initStat } from './FlagshipContext'; import { INTERNAL_EVENTS } from './internalType'; import { version as SDK_VERSION } from './sdkVersion'; import { useNonInitialEffect, logError, extractFlagsMap } from './utils'; export function FlagshipProvider({ children, envId, apiKey, decisionMode = DecisionMode.DECISION_API, visitorData, loadingComponent, onSdkStatusChanged, onBucketingUpdated, initialCampaigns, initialFlagsData, fetchFlagsOnBucketingUpdated, hitDeduplicationTime = 2, fetchNow = true, language = 1, sdkVersion = SDK_VERSION, onFlagsStatusChanged, shouldSaveInstance, ...props }) { const flags = extractFlagsMap(initialFlagsData, initialCampaigns); const [state, setState] = useState({ ...initStat, flags, hasVisitorData: !!visitorData }); const [lastModified, setLastModified] = useState(); const stateRef = useRef(); stateRef.current = state; const visitorDataRef = useRef(visitorData); // #region functions const onBucketingLastModified = (lastUpdate) => { if (onBucketingUpdated) { onBucketingUpdated(lastUpdate); } setLastModified(lastUpdate); }; const statusChanged = (status) => { if (onSdkStatusChanged) { onSdkStatusChanged(status); } switch (status) { case FSSdkStatus.SDK_PANIC: case FSSdkStatus.SDK_INITIALIZED: createVisitor(); break; case FSSdkStatus.SDK_NOT_INITIALIZED: setState((prev) => ({ ...prev, config: Flagship.getConfig(), isInitializing: false })); break; } }; const initSdk = () => { Flagship.start(envId, apiKey, { // eslint-disable-next-line @typescript-eslint/no-explicit-any decisionMode: decisionMode, fetchNow, onSdkStatusChanged: statusChanged, onBucketingUpdated: onBucketingLastModified, hitDeduplicationTime, language, sdkVersion, ...props }); }; function initializeState(param) { setState((currentState) => ({ ...currentState, visitor: param.fsVisitor, config: Flagship.getConfig(), isInitializing: false, hasVisitorData: !!visitorData })); } // eslint-disable-next-line @typescript-eslint/no-explicit-any const onVisitorReady = (fsVisitor, error) => { if (error) { logError(Flagship.getConfig(), error.message || error, 'onReady'); } initializeState({ fsVisitor }); }; const createVisitor = () => { if (!visitorDataRef.current) { return; } const fsVisitor = Flagship.newVisitor({ visitorId: visitorDataRef.current.id, context: visitorDataRef.current.context, isAuthenticated: visitorDataRef.current.isAuthenticated, hasConsented: visitorDataRef.current.hasConsented, initialCampaigns, initialFlagsData, onFlagsStatusChanged, shouldSaveInstance }); fsVisitor?.on('ready', (error) => { onVisitorReady(fsVisitor, error); }); if (!fetchNow) { initializeState({ fsVisitor }); } }; function updateVisitor() { if (!visitorDataRef.current || Flagship.getStatus() !== FSSdkStatus.SDK_INITIALIZED) { return; } if (!state.visitor || (state.visitor.visitorId !== visitorDataRef.current.id && (!visitorDataRef.current.isAuthenticated || (visitorDataRef.current.isAuthenticated && state.visitor.anonymousId)))) { state.visitor?.cleanup(); createVisitor(); return; } if (visitorDataRef.current.hasConsented !== state.visitor.hasConsented) { state.visitor.setConsent(visitorDataRef.current.hasConsented ?? true); } // eslint-disable-next-line @typescript-eslint/no-explicit-any state.visitor.updateContext(visitorDataRef.current.context); if (!state.visitor.anonymousId && visitorDataRef.current.isAuthenticated) { state.visitor.authenticate(visitorDataRef.current.id); } if (state.visitor.anonymousId && !visitorDataRef.current.isAuthenticated) { state.visitor.unauthenticate(); } state.visitor.fetchFlags(); } // #endregion useNonInitialEffect(() => { if (fetchFlagsOnBucketingUpdated) { state.visitor?.fetchFlags(); } }, [lastModified]); useNonInitialEffect(() => { visitorDataRef.current = visitorData; updateVisitor(); }, [JSON.stringify(visitorData)]); useEffect(() => { initSdk(); }, [envId, apiKey, decisionMode]); const handleDisplay = () => { const isFirstInit = !state.visitor; if (state.isInitializing && loadingComponent && isFirstInit && fetchNow) { return _jsx(_Fragment, { children: loadingComponent }); } return _jsx(_Fragment, { children: children }); }; useEffect(() => { window?.addEventListener?.(INTERNAL_EVENTS.FsTriggerRendering, onVariationsForced); return () => window?.removeEventListener?.(INTERNAL_EVENTS.FsTriggerRendering, onVariationsForced); }, [state.config?.isQAModeEnabled]); const onVariationsForced = (e) => { const { detail } = e; if (detail.forcedReFetchFlags) { stateRef.current?.visitor?.fetchFlags(); } else { setState(state => ({ ...state, toggleForcedVariations: !state.toggleForcedVariations })); } }; return (_jsx(FlagshipContext.Provider, { value: { state, setState }, children: handleDisplay() })); }