import React, {useContext, useEffect, useMemo, useState} from 'react'; import { promotedProductListener, purchaseErrorListener, purchaseUpdatedListener, transactionListener, } from '../eventEmitter'; import {IapIos, initConnection} from '../iap'; import type {PurchaseError} from '../purchaseError'; import type { Product, ProductPurchase, Purchase, Subscription, SubscriptionPurchase, } from '../types'; import type {TransactionEvent, TransactionSk2} from '../types/appleSk2'; type IAPContextType = { connected: boolean; products: Product[]; promotedProductsIOS: Product[]; subscriptions: Subscription[]; purchaseHistory: Purchase[]; availablePurchases: Purchase[]; currentPurchase?: Purchase; currentTransaction?: TransactionSk2; currentPurchaseError?: PurchaseError; initConnectionError?: Error; setConnected: (connected: boolean) => void; setProducts: (products: Product[]) => void; setSubscriptions: (subscriptions: Subscription[]) => void; setPurchaseHistory: (purchaseHistory: Purchase[]) => void; setAvailablePurchases: (availablePurchases: Purchase[]) => void; setCurrentPurchase: (currentPurchase: Purchase | undefined) => void; setCurrentPurchaseError: ( currentPurchaseError: PurchaseError | undefined, ) => void; }; // @ts-ignore const IAPContext = React.createContext(null); export function useIAPContext(): IAPContextType { const ctx = useContext(IAPContext); if (!ctx) { throw new Error('You need wrap your app with withIAPContext HOC'); } return ctx; } export function withIAPContext(Component: React.ComponentType) { return function WrapperComponent(props: T) { const [connected, setConnected] = useState(false); const [products, setProducts] = useState([]); const [promotedProductsIOS, setPromotedProductsIOS] = useState( [], ); const [subscriptions, setSubscriptions] = useState([]); const [purchaseHistory, setPurchaseHistory] = useState([]); const [availablePurchases, setAvailablePurchases] = useState( [], ); const [currentPurchase, setCurrentPurchase] = useState(); const [currentTransaction, setCurrentTransaction] = useState(); const [currentPurchaseError, setCurrentPurchaseError] = useState(); const [initConnectionError, setInitConnectionError] = useState(); const context = useMemo( () => ({ connected, products, subscriptions, promotedProductsIOS, purchaseHistory, availablePurchases, currentPurchase, currentTransaction, currentPurchaseError, initConnectionError, setConnected, setProducts, setSubscriptions, setPurchaseHistory, setAvailablePurchases, setCurrentPurchase, setCurrentPurchaseError, }), [ connected, products, subscriptions, promotedProductsIOS, purchaseHistory, availablePurchases, currentPurchase, currentTransaction, currentPurchaseError, initConnectionError, setConnected, setProducts, setSubscriptions, setPurchaseHistory, setAvailablePurchases, setCurrentPurchase, setCurrentPurchaseError, ], ); useEffect(() => { initConnection() .then((value) => { setInitConnectionError(undefined); setConnected(value); }) .catch(setInitConnectionError); }, []); useEffect(() => { if (!connected) { return; } const purchaseUpdateSubscription = purchaseUpdatedListener( async (purchase: ProductPurchase | SubscriptionPurchase) => { setCurrentPurchaseError(undefined); setCurrentPurchase(purchase); }, ); const transactionUpdateSubscription = transactionListener( async (transactionOrError: TransactionEvent) => { setCurrentPurchaseError(transactionOrError?.error); setCurrentTransaction(transactionOrError?.transaction); }, ); const purchaseErrorSubscription = purchaseErrorListener( (error: PurchaseError) => { setCurrentPurchase(undefined); setCurrentPurchaseError(error); }, ); const promotedProductSubscription = promotedProductListener(async () => { const product = await IapIos.getPromotedProductIOS(); setPromotedProductsIOS((prevProducts) => [ ...prevProducts, ...(product ? [product] : []), ]); }); return () => { purchaseUpdateSubscription.remove(); purchaseErrorSubscription.remove(); promotedProductSubscription?.remove(); transactionUpdateSubscription?.remove(); }; }, [connected]); return ( // @ts-ignore {/* @ts-ignore */} ); }; }