import { ThemedText } from '@/components/ThemedText'; import { useIAP } from 'expo-iap'; import React, { useCallback, useEffect, useState } from 'react'; import { Alert, InteractionManager, Platform, View } from 'react-native'; // Define your product SKUs const bulbPackSkus = ['dev.hyo.martie.10bulbs', 'dev.hyo.martie.30bulbs']; const subscriptionSkus = ['dev.hyo.martie.premium']; export default function PurchaseScreen() { const { connected, products, subscriptions, currentPurchase, currentPurchaseError, requestProducts, requestPurchase, finishTransaction, validateReceipt, } = useIAP(); const [isLoading, setIsLoading] = useState(false); const [isReady, setIsReady] = useState(false); // Initialize products when IAP connection is established useEffect(() => { if (!connected) return; const initializeIAP = async () => { try { // Get both products and subscriptions await requestProducts({ skus: bulbPackSkus, type: 'inapp' }); await requestProducts({ skus: subscriptionSkus, type: 'subs' }); setIsReady(true); } catch (error) { console.error('Error initializing IAP:', error); } }; initializeIAP(); }, [connected, requestProducts]); // Validate receipt helper const handleValidateReceipt = useCallback( async (sku: string, purchase: any) => { try { if (Platform.OS === 'ios') { return await validateReceipt(sku); } else if (Platform.OS === 'android') { const purchaseToken = purchase.purchaseTokenAndroid; const packageName = purchase.packageNameAndroid || 'your.package.name'; const isSub = subscriptionSkus.includes(sku); return await validateReceipt(sku, { packageName, productToken: purchaseToken, isSub, }); } return { isValid: true }; // Default for unsupported platforms } catch (error) { console.error('Receipt validation failed:', error); return { isValid: false }; } }, [validateReceipt], ); // Handle successful purchases useEffect(() => { if (currentPurchase) { handlePurchaseUpdate(currentPurchase); } }, [currentPurchase]); // Handle purchase errors useEffect(() => { if (currentPurchaseError) { setIsLoading(false); // Don't show error for user cancellation if (currentPurchaseError.code === 'E_USER_CANCELLED') { return; } Alert.alert( 'Purchase Error', 'Failed to complete purchase. Please try again.', ); console.error('Purchase error:', currentPurchaseError); } }, [currentPurchaseError]); const handlePurchaseUpdate = async (purchase: any) => { try { setIsLoading(true); console.log('Processing purchase:', purchase); const productId = purchase.id; // Validate receipt on your server const validationResult = await handleValidateReceipt(productId, purchase); if (validationResult.isValid) { // Determine if this is a consumable product const isConsumable = bulbPackSkus.includes(productId); // Finish the transaction await finishTransaction({ purchase, isConsumable, // Set to true for consumable products }); // Record purchase in your database await recordPurchaseInDatabase(purchase, productId); // Update local state (e.g., add bulbs, enable premium features) await updateLocalState(productId); // Show success message showSuccessMessage(productId); } else { Alert.alert( 'Validation Error', 'Purchase could not be validated. Please contact support.', ); } } catch (error) { console.error('Error handling purchase:', error); Alert.alert('Error', 'Failed to process purchase.'); } finally { setIsLoading(false); } }; // Request purchase for products const handlePurchaseBulbs = async (productId: string) => { if (!connected) { Alert.alert( 'Not Connected', 'Store connection unavailable. Please try again later.', ); return; } try { setIsLoading(true); // Platform-specific purchase request (v2.7.0+) await requestPurchase({ request: { ios: { sku: productId, andDangerouslyFinishTransactionAutomaticallyIOS: false, }, android: { skus: [productId], }, }, }); } catch (error) { setIsLoading(false); console.error('Purchase request failed:', error); } }; // Request purchase for subscriptions const handlePurchaseSubscription = async (subscriptionId: string) => { if (!connected) { Alert.alert( 'Not Connected', 'Store connection unavailable. Please try again later.', ); return; } try { setIsLoading(true); // Find subscription to get offer details const subscription = subscriptions.find((s) => s.id === subscriptionId); const subscriptionOffers = subscription?.subscriptionOfferDetails?.map( (offer) => ({ sku: subscriptionId, offerToken: offer.offerToken, }), ) || [{ sku: subscriptionId, offerToken: '' }]; // Platform-specific subscription request (v2.7.0+) await requestPurchase({ request: { ios: { sku: subscriptionId, }, android: { skus: [subscriptionId], subscriptionOffers, }, }, type: 'subs', }); } catch (error) { setIsLoading(false); console.error('Subscription request failed:', error); } }; const recordPurchaseInDatabase = async (purchase: any, productId: string) => { // Implement your database recording logic here console.log('Recording purchase in database:', { purchase, productId }); }; const updateLocalState = async (productId: string) => { // Update your local app state based on the purchase if (bulbPackSkus.includes(productId)) { // Add bulbs to user's account const bulbCount = productId.includes('10bulbs') ? 10 : 30; console.log(`Adding ${bulbCount} bulbs to user account`); } else if (subscriptionSkus.includes(productId)) { // Enable premium features console.log('Enabling premium features'); } }; const showSuccessMessage = (productId: string) => { InteractionManager.runAfterInteractions(() => { if (bulbPackSkus.includes(productId)) { const bulbCount = productId.includes('10bulbs') ? 10 : 30; Alert.alert( 'Thank You!', `${bulbCount} bulbs have been added to your account.`, ); } else if (subscriptionSkus.includes(productId)) { Alert.alert( 'Thank You!', 'Premium subscription activated successfully.', ); } }); }; return ( {/* Your purchase UI components */} Connection Status: {connected ? 'Connected' : 'Disconnected'} Products Ready: {isReady ? 'Yes' : 'No'} {/* Add your purchase buttons and UI here */} ); }