@kirz/react-native-toolkit
Version: 
Toolkit to speed up React Native development
108 lines • 4.22 kB
JavaScript
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState, useRef } from 'react';
import { PluginsBundleContext } from './PluginsBundleContext';
import { Subscription } from '../plugins/types';
import { waitUntil } from '../utils/promise/waitUntil';
export const InAppPurchaseContext = /*#__PURE__*/createContext({});
export function InAppPurchaseProvider(_ref) {
  let {
    children
  } = _ref;
  const [isInitialized, setIsInitialized] = useState(false);
  const {
    bundle
  } = useContext(PluginsBundleContext);
  const iapPurchasePlugin = useMemo(() => {
    return bundle.getByFeature('InAppPurchase');
  }, [bundle]);
  const [activeSubscription, setActiveSubscription] = useState(null);
  const [hasPremiumAccess, setHasPremiumAccess] = useState(false);
  const lastUserDataFetchTimestamp = useRef(new Date().valueOf());
  const fetchUserData = useCallback(async () => {
    if (!iapPurchasePlugin) {
      throw new Error('IAP is not initialized');
    }
    const results = await Promise.all([iapPurchasePlugin.receiptValidator.hasPremiumAccess(), iapPurchasePlugin.receiptValidator.getActiveSubscription()]);
    setHasPremiumAccess(results[0]);
    const subscriptionInstance = results[1] && new Subscription(iapPurchasePlugin.subscriptions.find(x => {
      var _results$;
      return x.productId === ((_results$ = results[1]) === null || _results$ === void 0 ? void 0 : _results$.productId);
    }));
    setActiveSubscription(subscriptionInstance && results[1] ? {
      ...subscriptionInstance,
      ...results[1],
      formatPrice(options) {
        return subscriptionInstance.formatPrice(options);
      }
    } : null);
    setIsInitialized(true);
    lastUserDataFetchTimestamp.current = new Date().valueOf();
    return results[0];
  }, [iapPurchasePlugin]);
  const restorePurchases = useCallback(async () => {
    if (!iapPurchasePlugin) {
      throw new Error('IAP is not initialized');
    }
    await iapPurchasePlugin.receiptValidator.restorePurchases();
    return fetchUserData();
  }, [iapPurchasePlugin]);
  const purchaseProduct = useCallback(async productId => {
    if (!iapPurchasePlugin) {
      throw new Error('IAP plugin not found');
    }
    try {
      const purchase = await iapPurchasePlugin.purchaseProduct(productId);
      return purchase;
    } catch (err) {
      const error = err;
      if (error.isCancelled) {
        return null;
      }
      throw new Error(error.message);
    }
  }, [iapPurchasePlugin]);
  const purchasePremium = useCallback(async productId => {
    const purchase = await purchaseProduct(productId);
    if (!purchase) {
      return null;
    }
    await waitUntil(async () => {
      await iapPurchasePlugin.receiptValidator.restorePurchases();
      return await fetchUserData();
    });
    await iapPurchasePlugin.refetchProducts();
    return purchase;
  }, [purchaseProduct, iapPurchasePlugin]);
  const premiumAccess = useCallback(func => {
    return async function () {
      let isAllowed = hasPremiumAccess;
      if (new Date().valueOf() - lastUserDataFetchTimestamp.current > 1000 * 60 * 60) {
        isAllowed = await restorePurchases();
      }
      if (!isAllowed) {
        throw new Error('Premium access required');
      }
      return func(...arguments);
    };
  }, [hasPremiumAccess, fetchUserData, restorePurchases]);
  const contextData = useMemo(() => ({
    isInitialized,
    hasPremiumAccess,
    activeSubscription,
    products: (iapPurchasePlugin === null || iapPurchasePlugin === void 0 ? void 0 : iapPurchasePlugin.products) ?? [],
    subscriptions: (iapPurchasePlugin === null || iapPurchasePlugin === void 0 ? void 0 : iapPurchasePlugin.subscriptions) ?? [],
    restorePurchases,
    purchaseProduct,
    purchasePremium,
    premiumAccess
  }), [isInitialized, iapPurchasePlugin, hasPremiumAccess, activeSubscription, restorePurchases, purchaseProduct, purchasePremium, premiumAccess]);
  useEffect(() => {
    if (!iapPurchasePlugin) {
      return;
    }
    fetchUserData();
  }, [iapPurchasePlugin]);
  return /*#__PURE__*/React.createElement(InAppPurchaseContext.Provider, {
    value: contextData
  }, children);
}
//# sourceMappingURL=InAppPurchaseContext.js.map