import { endConnection, initConnection, purchaseErrorListener, purchaseUpdatedListener, transactionUpdatedIos, getProducts, getAvailablePurchases, getPurchaseHistory, getSubscriptions, } from './'; import {useCallback, useEffect, useState} from 'react'; import { Product, ProductPurchase, Purchase, PurchaseError, PurchaseResult, SubscriptionProduct, SubscriptionPurchase, } from './ExpoIap.types'; import {TransactionEvent} from './modules/ios'; import {TransactionSk2} from './types/ExpoIapIos.types'; import {Subscription} from 'expo-modules-core'; type IAP_STATUS = { connected: boolean; products: Product[]; promotedProductsIOS: TransactionSk2[]; subscriptions: SubscriptionProduct[]; purchaseHistories: ProductPurchase[]; availablePurchases: ProductPurchase[]; currentPurchase?: ProductPurchase; currentPurchaseError?: PurchaseError; finishTransaction: ({ purchase, isConsumable, developerPayloadAndroid, }: { purchase: Purchase; isConsumable?: boolean; developerPayloadAndroid?: string; }) => Promise; getAvailablePurchases: () => Promise; getPurchaseHistories: () => Promise; getProducts: (skus: string[]) => Promise; getSubscriptions: (skus: string[]) => Promise; }; let purchaseUpdateSubscription: Subscription; let purchaseErrorSubscription: Subscription; let promotedProductsSubscription: Subscription; export function useIAP(): IAP_STATUS { const [connected, setConnected] = useState(false); const [products, setProducts] = useState([]); const [promotedProductsIOS, setPromotedProductsIOS] = useState< TransactionSk2[] >([]); const [subscriptions, setSubscriptions] = useState([]); const [purchaseHistories, setPurchaseHistories] = useState( [], ); const [availablePurchases, setAvailablePurchases] = useState< ProductPurchase[] >([]); const [currentPurchase, setCurrentPurchase] = useState(); const [currentPurchaseError, setCurrentPurchaseError] = useState(); const requestProducts = useCallback(async (skus: string[]): Promise => { setProducts(await getProducts(skus)); }, []); const requestSubscriptions = useCallback( async (skus: string[]): Promise => { setSubscriptions(await getSubscriptions(skus)); }, [], ); const requestAvailablePurchases = useCallback(async (): Promise => { setAvailablePurchases(await getAvailablePurchases()); }, []); const requestPurchaseHistories = useCallback(async (): Promise => { setPurchaseHistories(await getPurchaseHistory()); }, []); const finishTransaction = useCallback( async ({ purchase, isConsumable, developerPayloadAndroid, }: { purchase: ProductPurchase; isConsumable?: boolean; developerPayloadAndroid?: string; }): Promise => { try { return await finishTransaction({ purchase, isConsumable, developerPayloadAndroid, }); } catch (err) { throw err; } finally { if (purchase.productId === currentPurchase?.productId) { setCurrentPurchase(undefined); } if (purchase.productId === currentPurchaseError?.productId) { setCurrentPurchaseError(undefined); } } }, [ currentPurchase?.productId, currentPurchaseError?.productId, setCurrentPurchase, setCurrentPurchaseError, ], ); const initIapWithSubscriptions = useCallback(async (): Promise => { const result = await initConnection(); setConnected(result); if (result) { purchaseUpdateSubscription = purchaseUpdatedListener( async (purchase: Purchase | SubscriptionPurchase) => { setCurrentPurchaseError(undefined); setCurrentPurchase(purchase); }, ); purchaseErrorSubscription = purchaseErrorListener( (error: PurchaseError) => { setCurrentPurchase(undefined); setCurrentPurchaseError(error); }, ); promotedProductsSubscription = transactionUpdatedIos( (event: TransactionEvent) => { setPromotedProductsIOS((prevProducts) => event.transaction ? [...prevProducts, event.transaction] : prevProducts, ); }, ); } }, []); useEffect(() => { initIapWithSubscriptions(); return (): void => { if (purchaseUpdateSubscription) purchaseUpdateSubscription.remove(); if (purchaseErrorSubscription) purchaseErrorSubscription.remove(); if (promotedProductsSubscription) promotedProductsSubscription.remove(); endConnection(); setConnected(false); }; }, [initIapWithSubscriptions]); return { connected, products, promotedProductsIOS, subscriptions, purchaseHistories, finishTransaction, availablePurchases, currentPurchase, currentPurchaseError, getProducts: requestProducts, getSubscriptions: requestSubscriptions, getAvailablePurchases: requestAvailablePurchases, getPurchaseHistories: requestPurchaseHistories, }; }