Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

currentPurchase from useIAP() is undefined #2806

Open
abhishek28072 opened this issue Jul 24, 2024 · 2 comments
Open

currentPurchase from useIAP() is undefined #2806

abhishek28072 opened this issue Jul 24, 2024 · 2 comments

Comments

@abhishek28072
Copy link

Please use the Discussion board if you want to get some help. Please use issues to report bugs.

Description

I want that on Successful payment , i should be able to make a post request to an api called createPayment (in function checkCurrentPurchase that is being triggered by update listener)
to store data in backend, but somehow it is not happening, not getting called

Expected Behavior

Screenshots

import React, { useEffect, useState } from "react";
import {
ScrollView,
StyleSheet,
Text,
View,
Platform,
TouchableOpacity,
SafeAreaView,
ActivityIndicator,
Alert,
} from "react-native";
import { createPayment, createUserSubscription } from '../../apis';
// import { ITUNES_SHARED_SECRET } from "@env";
import {
PurchaseError,

purchaseErrorListener,

purchaseUpdatedListener,

requestSubscription,
useIAP,
validateReceiptIos,

} from "react-native-iap";
import Constants from 'expo-constants';
import { logReadable } from "utils/utils";
import BillingCycleTile from "components/BillingCycleTile";
import { addDays, format } from "date-fns";
import { Icon } from "@ui-kitten/components";
import { updateSubscription } from "store/slices/userSlice";
import { useAppDispatch } from "store/store";

const getITunesSharedSecret = () => {
if (Constants.expoConfig && Constants.expoConfig.extra) {
return Constants.expoConfig.extra.itunesSharedSecret;
}
throw new Error('iTunes shared secret is not defined in the configuration.');
};

const errorLog = ({ message, error }) => {
console.error("An error happened", message, error);
};

const ITUNES_SHARED_SECRET = getITunesSharedSecret();

console.log(ITUNES_SHARED_SECRET)
const isIos = Platform.OS === "ios";
const allSkus = ["gs_vijay_1m", "gs_udaan_1m", "gs_tarakki_1m"];

function getLastDateIn30DayInterval(numMonths) {
const currentDate = new Date();
const lastDate = addDays(currentDate, numMonths * 30);

const getDaySuffix = (day) => {
    if (day >= 11 && day <= 13) {
        return 'th';
    }
    switch (day % 10) {
        case 1: return 'st';
        case 2: return 'nd';
        case 3: return 'rd';
        default: return 'th';
    }
};


const formattedDate = format(lastDate, `do MMM yyyy`).replace(/(\d+)(st|nd|rd|th)/, '$1');

return formattedDate;

}

export const Subscriptions = ({ navigation, route }) => {

const {
    connected,
    subscriptions, //returns subscriptions for this app.
    getSubscriptions, //Gets available subsctiptions for this app.
    currentPurchase, //current purchase for the tranasction
    finishTransaction,
    purchaseHistory, //return the purchase history of the user on the device (sandbox user in dev)
    getPurchaseHistory, //gets users purchase history
} = useIAP();
const dispatch = useAppDispatch();

const [userSubscription, setUserSubscription] = useState(null);
const [isSubscriptionPending, setIsSubscriptionPending] = useState(true);
const { subscriptionsDetails } = route?.params;
const { upgrade, downgrade } = route?.params;
// logReadable("here", subscriptionsDetails.id)

const [selectedMonths, setSelectedMonths] = useState(0);

const filterSkusByCategory = (category) => {
    switch (category) {
        case "Vijay":
            return allSkus.filter(sku => sku.startsWith("gs_vijay_"));
        case "Udaan":
            return allSkus.filter(sku => sku.startsWith("gs_udaan_"));
        case "Tarakki":
            return allSkus.filter(sku => sku.startsWith("gs_tarakki_"));
        default:
            return [];
    }
};

const subscriptionSkus = filterSkusByCategory(subscriptionsDetails?.plan);
// console.log("subscriptions[selectedMonths]", subscriptions[selectedMonths])


const [loading, setLoading] = useState(false);

const handleSelect = (months) => {
    setSelectedMonths(months);
};
const handleGetPurchaseHistory = async () => {
    try {
        await getPurchaseHistory();
    } catch (error) {
        errorLog({ message: "handleGetPurchaseHistory", error });
    }
};

useEffect(() => {
    handleGetPurchaseHistory();
}, [connected]);

const handleGetSubscriptions = async () => {
    try {
        await getSubscriptions({ skus: subscriptionSkus });
    } catch (error) {
        errorLog({ message: "handleGetSubscriptions", error });
    }
};

useEffect(() => {
    handleGetSubscriptions();
}, [connected]);


const initiateSubscription = () => {
    const subscription = subscriptions[selectedMonths]

    const basePrice = Number((subscription?.price * 100 / 118).toFixed(0));
    const taxPrice = Number((basePrice * 18 / 100).toFixed(0));
    const price = {
        basePrice: basePrice,
        discountPrice: 0,
        taxPrice: taxPrice,
        totalPrice: Number(subscription?.price)
    };
    // console.log("here--->", basePrice, taxPrice, price.totalPrice)

    setIsSubscriptionPending(true);

    createUserSubscription({
        subscription_plan_id: subscriptionsDetails?.id,//subscription details we got from routes.params
        platform_os: 'ios',
        ios_product_id: subscription?.productId,//data that has to be mapped with billing cycle id
        base_price: price?.basePrice,//not required for 'ios'
        tax_price: price?.taxPrice,//not required for 'ios'
        total_price: price?.totalPrice,
        status: 'PENDING',
    }, (data) => {
        setUserSubscription(data);
        console.log("userSubscription", userSubscription)
        setIsSubscriptionPending(false);

        handleBuySubscription(subscription?.productId);

    }, (error) => {
        setIsSubscriptionPending(false);
        setLoading(false)
        console.log(error)
        // Alert.alert("Subscription Error", "Failed to create subscription.", error);
    });
};


const handleBuySubscription = async (productId) => {
    console.log("cp2", currentPurchase, productId)
    try {
        await requestSubscription({
            sku: productId,
        });
        setLoading(false);
    } catch (error) {
        Alert.alert('error in handle buy subscription')
        setLoading(false);
        if (error instanceof PurchaseError) {
            errorLog({ message: `[${error.code}]: ${error.message}`, error });
        } else {
            errorLog({ message: "handleBuySubscription", error });
        }
    }







};
const checkCurrentPurchase = async (purchase) => {
    console.log("yes")

    if (purchase) {
        try {
            console.log("status", status)

            const receipt = purchase?.transactionReceipt;


            const isTestEnvironment = __DEV__;

            //send receipt body to apple server to validete
            const appleReceiptResponse = await validateReceiptIos(
                {
                    "receipt-data": receipt,
                    password: ITUNES_SHARED_SECRET,
                },
                isTestEnvironment,
            );

            //if receipt is valid

            const subscription = subscriptions[selectedMonths];

            const basePrice = Number((subscription?.price * 100 / 118).toFixed(0));
            const taxPrice = Number((basePrice * 18 / 100).toFixed(0));

            const price = {
                basePrice: basePrice,
                discountPrice: 0,
                taxPrice: taxPrice,
                totalPrice: Number(subscription?.price)
            };


            console.log("receipt", receipt)
            if (userSubscription) {
                try {
                    await createPayment({
                        user_subscription_id: userSubscription?.id,
                        platform_os: 'ios',
                        ios_product_id: subscription?.productId,
                        base_price: price.basePrice,
                        discount_price: price.discountPrice,
                        tax_price: price.taxPrice,//not required id ios
                        total_price: price.totalPrice,
                        transaction_id: purchase?.transactionReceipt,
                        status: 'SUCCESS',
                        gateway_response: {
                            receipt: receipt,
                            purchaseHistory,
                            formatted_receipt: appleReceiptResponse
                        }
                    },
                        (data) => {

                            dispatch(updateSubscription(data));

                            navigation.navigate("PlansDetails");
                            Alert.alert("Congratulations, You Are Subscribed to", subscriptionsDetails?.plan)
                        },
                        (errorMessage) => {
                            Alert.alert('Error', errorMessage);
                            // Alert.alert('transaction_id:', currentPurchase?.transactionReceipt);

                        }
                    );
                } catch (error) {
                    createPayment({
                        user_subscription_id: userSubscription?.id,
                        base_price: price?.basePrice,
                        platform_os: 'ios',
                        ios_product_id: subscription?.productId,
                        discount_price: price?.discountPrice,
                        tax_price: price?.taxPrice,
                        total_price: price?.totalPrice,
                        transaction_id: null,
                        status: 'FAILED',
                        gateway_response: error,
                    }, function () { }, function (error) {
                        console.log("Error", error)
                    });
                    console.error('Error in createPayment:', error);
                    // Alert.alert('Error', 'An error occurred while processing the payment.');

                } finally {
                    setLoading(false);
                }
            }




            const { status } = appleReceiptResponse;
            if (status) {
                Alert.alert(
                    "Navigation Alert",
                    "Do you want to navigate to the homepage?",
                    [
                        {
                            text: "Cancel",
                            style: "cancel"
                        },
                        {
                            text: "OK",
                            onPress: () => navigation.navigate("PlansDetails")
                        }
                    ]
                );
            }

            return;


        } catch (error) {
            console.log("error", error);
        }
    }





};
useEffect(() => {

    checkCurrentPurchase(currentPurchase);
}, [currentPurchase, finishTransaction]);

useEffect(() => {
    console.log("we r called")
    const purchaseUpdateSubscription = purchaseUpdatedListener(async (purchase) => {
        await finishTransaction(purchase);
        checkCurrentPurchase(purchase);
    });

    const purchaseErrorSubscription = purchaseErrorListener((error) => {
        console.warn('purchaseErrorListener', error);
        Alert.alert('Purchase Error', error.message);
    });

    return () => {
        purchaseUpdateSubscription.remove();
        purchaseErrorSubscription.remove();
    };
}, []);

return (
    <SafeAreaView style={{ flex: 1 }}>
        <ScrollView>
            <View style={{ padding: 16, gap: 12 }}>
                <Text
                    style={{
                        fontSize: 28,
                        textAlign: "center",
                        color: "black",
                        fontWeight: "bold",
                    }}
                >
                    Subscribe!
                </Text>
                {/* <Text style={styles.listItem}>
                    Subscribe to get the features unlocked.
                </Text> */}
                <Text
                    style={
                        (styles.listItem,
                        {
                            fontWeight: "500",
                            textAlign: "center",
                            marginTop: 10,
                            fontSize: 18,
                        })
                    }
                >Subscribe Now to Enjoy All Features!</Text>
                {subscriptions.length === 0 || subscriptions[selectedMonths] === undefined ? (
                    <ActivityIndicator size="large" color="#0000ff" />
                ) : (
                    <View style={{ marginTop: 10 }}>
                        {subscriptions.map((subscription, index) => {
                            const owned = purchaseHistory.find(
                                (s) => s?.productId === subscription.productId
                            );
                            const price = Number(subscription?.price);

                            return (
                                <BillingCycleTile
                                    key={index}
                                    months={subscription?.subscriptionPeriodNumberIOS}
                                    price={subscription?.price}
                                    nextPayment={getLastDateIn30DayInterval(subscription?.subscriptionPeriodNumberIOS)}
                                    isSelected={selectedMonths === index}
                                    onPress={() => handleSelect(index)}
                                />
                            );
                        })}
                    </View>
                )}

                {loading && <ActivityIndicator size="large" />}
                {!subscriptions && <ActivityIndicator size="large" />}
                {!loading && subscriptions &&
                    <TouchableOpacity
                        style={styles.button}
                        onPress={() => {
                            setLoading(true);
                            // console.log(subscriptions[selectedMonths]?.productId)
                            initiateSubscription();
                        }}
                    >
                        <Text style={styles.buttonText}>Next</Text>
                        <Icon
                            name="arrow-ios-forward-outline"
                            style={{ width: 25, height: 25 }}
                            fill='white'
                        />
                    </TouchableOpacity>
                }
            </View>
        </ScrollView>
    </SafeAreaView>
);

};

const styles = StyleSheet.create({
container: {
marginBottom: 20,
},
listItem: {
fontSize: 16,
paddingLeft: 8,
paddingBottom: 3,
textAlign: "center",
color: "black",
},
box: {
margin: 10,
marginBottom: 5,
padding: 10,
backgroundColor: "white",
borderRadius: 7,
shadowColor: "rgba(0, 0, 0, 0.45)",
shadowOffset: { height: 16, width: 0 },
shadowOpacity: 0.1,
shadowRadius: 12,
},
button: {
alignItems: "center",
justifyContent: 'center',
backgroundColor: '#6C5BCD',
borderRadius: 8,
flexDirection: 'row',
padding: 12,
},
buttonText: {
fontSize: 16,
fontWeight: "bold",
color: "white",
textTransform: "uppercase",
},
specialTag: {
color: "white",
backgroundColor: "crimson",
width: 125,
padding: 4,
fontWeight: "bold",
fontSize: 12,
borderRadius: 7,
marginBottom: 2,
},
});

Environment:

  • react-native-iap:
  • react-native:
  • Platforms (iOS, Android, emulator, simulator, device):

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Press '...'
  3. Error '...' is shown

[Optional] Additional Context

@cagdaseksi
Copy link

useEffect(() => {

checkCurrentPurchase(currentPurchase);

}, [currentPurchase, finishTransaction]);


useEffect(() => {

if(currentPurchase){
checkCurrentPurchase(currentPurchase);
}

}, [currentPurchase, finishTransaction]);

You should try to put it in an if block.

@husseinakbari
Copy link

I also got undefined initially, but after a few minutes, currentPurchase updated and had the correct value.
I'm using sandbox email for testing the purchase subscription.

react-native-iap: 12.15.2
react-native: 0.74.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants