TheMagoo73/flagsmith-react

View on GitHub
src/flagsmith-provider.js

Summary

Maintainability
A
0 mins
Test Coverage
import React from "react";
import { useCallback, useEffect, useReducer, useRef } from "react";
import PropTypes from "prop-types";

import FlagsmithContext from "./flagsmith-context";
import { reducer } from "./reducer";

import { useEventEmitter } from "./use-event-emitter";

import reactFlagsmith from "flagsmith";

const FlagsmithProvider = ({
  api,
  environmentId,
  children,
  asyncStorage,
  cacheFlags,
  defaultFlags,
  preventFetch,
  flagsmith = reactFlagsmith,
}) => {
  const [state, dispatch] = useReducer(reducer, {
    isLoading: true,
    isError: false,
    isIdentified: false,
    isListening: false,
  });
  const { emit, useSubscription } = useEventEmitter();

  const handleChange = useCallback((e) => emit(e), [emit]);

  const isInitialised = useRef(false)

  useEffect(() => {
    (async () => {
      if(isInitialised.current) return;
      isInitialised.current = true;
      try {
        await flagsmith.init({
          api,
          environmentID: environmentId,
          onChange: handleChange,
          asyncStorage,
          cacheFlags,
          defaultFlags,
          preventFetch,
        });
        dispatch({ type: "INITIALISED" });
      } catch {
        console.log("Failed");
        dispatch({ type: "ERRORED" });
      }
    })();
  }, [
    environmentId,
    handleChange,
    flagsmith,
    asyncStorage,
    cacheFlags,
    defaultFlags,
    preventFetch,
    api,
    isInitialised
  ]);

  const identify = useCallback(
    async (identity, traits) => {
      let result = undefined;
      try {
        traits ?
          result = await flagsmith.identify(identity, traits) :
          result = await flagsmith.identify(identity);
        dispatch({ type: "IDENTIFIED" });
      } catch {
        dispatch({ type: "UNIDENTIFIED" });
      }
      return result;
    },
    [flagsmith]
  );

  const logout = useCallback(async () => {
    let result;
    try {
      result = await flagsmith.logout();
    } finally {
      dispatch({ type: "UNIDENTIFIED" });
    }
    return result;
  }, [flagsmith]);

  const startListening = useCallback(
    (interval = 1000) => {
      flagsmith.startListening(interval);
      dispatch({ type: "START_LISTENING" });
    },
    [flagsmith]
  );

  const stopListening = useCallback(() => {
    flagsmith.stopListening();
    dispatch({ type: "STOP_LISTENING" });
  }, [flagsmith]);

  const hasFeature = useCallback(
    (key) => {
      return flagsmith.hasFeature(key);
    },
    [flagsmith]
  );

  const getValue = useCallback(
    (key) => {
      return flagsmith.getValue(key);
    },
    [flagsmith]
  );

  const getFlags = useCallback(async () => {
    return await flagsmith.getFlags();
  }, [flagsmith]);
  
  const getAllFlags = useCallback(
    () => {
      return flagsmith.getAllFlags();
    },
    [flagsmith]
  );

  const getTrait = useCallback(
    (key) => {
      return flagsmith.getTrait(key);
    },
    [flagsmith]
  );

  const setTrait = useCallback(
    async (key, value) => {
      return flagsmith.setTrait(key, value);
    },
    [flagsmith]
  );

  const incrementTrait = useCallback(
    async (key, incrementBy) => {
      return flagsmith.incrementTrait(key, incrementBy);
    },
    [flagsmith]
  );

  const setTraits = useCallback(
    async (traits) => {
      return flagsmith.setTraits(traits);
    },
    [flagsmith]
  );

  return (
    <FlagsmithContext.Provider
      value={{
        ...state,
        api,
        identify,
        hasFeature,
        getValue,
        subscribe: useSubscription,
        logout,
        startListening,
        stopListening,
        getFlags,
        getAllFlags,
        getTrait,
        setTrait,
        setTraits,
        incrementTrait,
      }}
    >
      {children}
    </FlagsmithContext.Provider>
  );
};

FlagsmithProvider.propTypes = {
  children: PropTypes.any,
  environmentId: PropTypes.string.isRequired,
  flagsmith: PropTypes.object,
  asyncStorage: PropTypes.object,
  cacheFlags: PropTypes.bool,
  defaultFlags: PropTypes.object,
  preventFetch: PropTypes.bool,
  api: PropTypes.string,
};

export default FlagsmithProvider;