stripe / stripe-react-native

React Native library for Stripe.
https://stripe.dev/stripe-react-native
MIT License
1.29k stars 263 forks source link

presentPaymentSheet is not showing up #1641

Open razi1997 opened 7 months ago

razi1997 commented 7 months ago

App.js

<StripeProvider publishableKey="key">
    <GestureHandlerRootView style={{ flex: 1 }}>
      <BottomSheetModalProvider>

        <NavigationContainer>
          <Stack.Navigator initialRouteName={Dashboard} screenOptions={{headerShown: false}}>
            <Stack.Screen name="Logo" component={Logo} />
            <Stack.Screen name="RegistrationSuccess" component={RegistrationSuccess} />
            <Stack.Screen name="Intro" component={Intro} />
            <Stack.Screen name="Login" component={Login} />
            <Stack.Screen name="Signup" component={Signup} />
            <Stack.Screen name="ForgetPasssword" component={ForgetPasssword} />
            <Stack.Screen name="OtpVerification" component={OtpVerification} />
            <Stack.Screen name="ChangePassword" component={ChangePassword} />
            <Stack.Screen name="Dashboard" component={Dashboard} />
            <Stack.Screen name="ProductList" component={ProductList} />
          </Stack.Navigator>
        </NavigationContainer>
        <Toast />

      </BottomSheetModalProvider>
    </GestureHandlerRootView>
    </StripeProvider>

ProductList.js

 const { confirmPayment, initPaymentSheet, presentPaymentSheet } = useStripe();

    useEffect(() => {
        fetch('http://172.20.10.2:5000/payments/create-payment-intent')
        .then((res) => {
            return res.json();
        })
        .then(res => {
            setKey(res.client_secret)
            initPaymentSheet({paymentIntentClientSecret: key});
        })
        .catch(e => console.log(e.message));
    }, []);

const handleSheet = () => {
        presentPaymentSheet({
          clientSecret: key,
        });
    };

<View className="flex mx-5">

                <CardField
                    postalCodeEnabled={true}
                    placeholders={{
                        number: '4242 4242 4242 4242',
                    }}
                    cardStyle={{
                        backgroundColor: '#FFFFFF',
                        textColor: '#000000',
                    }}
                    style={{
                        width: '100%',
                        height: 60,
                        marginVertical: 30,
                    }}
                    onCardChange={cardDetails => {
                        console.log('cardDetails', cardDetails);
                    }}
                    onFocus={focusedField => {
                        console.log('focusField', focusedField);
                    }}
                />

            </View>
            <View style={styles.buttonContainer}>
                <Button title="Confirm payment" onPress={handleConfirmation} />
                <Button title="Present sheet" onPress={handleSheet}/>
            </View>

I'm unable to open bottom sheet
I've tried all the possible methods but its not working

seanzhang-stripe commented 7 months ago

Hi @razi1997 Did you see any errors in react-native console? By the way you don't need to specify clientSecret when calling presentPaymentSheet, refer to this doc to view the list of options for presentPaymentSheet.

Also you should just pass res.client_secret directly to initPaymentSheet, calling setKey(res.client_secret) won't have key value updated immediately.

razi1997 commented 7 months ago

Thanks for helping me

I've tried this method and I'm able to presentPaymentSheet

useEffect(() => { fetch('http://172.20.10.2:5000/payments/create-payment-intent') .then((res) => { return res.json(); }) .then(res => { setKey(res.client_secret) const on = initPaymentSheet({ appearance: customAppearance, paymentIntentClientSecret: res.client_secret, googlePay: { merchantCountryCode: 'HU', testEnv: true, // use test environment }, applePay: true, merchantDisplayName: 'Merchant Name' }); on.then((res) => { console.log(res) }) }) .catch(e => console.log(e.message)); }, []);

But now console showing an error 
`{"paymentOption": undefined}`

Could you please elaborate that how can I assign the paymentOption
seanzhang-stripe commented 7 months ago

paymentOption will be returned from presentPaymentSheet if you are using the custom flow (i.e., setting customFlow to true in initPaymentSheet)

razi1997 commented 7 months ago

This is my server side rendering

def createPaymentIntent():

    email = request.args.get('email')
    amount = request.args.get('amount')
    currency = request.args.get('currency')

    try:
        # Try to retrieve the customer based on email
        customer = stripe.Customer.list(email=email, limit=1).data[0]
        print('Customer already exists:')
    except IndexError:
        # Customer doesn't exist, create a new one
        customer = stripe.Customer.create(email=email)
        print('New customer created:')

    ephemeral_key = stripe.EphemeralKey.create(
        customer=customer.id,
        stripe_version='2024-04-10'  
    )

    print('customer id: ', customer['id'])
    print('ephemeral key: ', ephemeral_key['secret'])

    response = stripe.PaymentIntent.create(
        amount=int(amount) * 10,
        currency=currency,
        automatic_payment_methods={"enabled": True},
        setup_future_usage='on_session'
    )

    json = {
        'paymentIntent': response['client_secret'],
        'ephemeralKey': ephemeral_key['secret'],
        'customer': customer['id']
    }
    # print(response)
    return jsonify(json)

and this is my Front-End after updating the customFlow: true

const { confirmPayment, initPaymentSheet, presentPaymentSheet } = useStripe();

    const fetchPaymentSheetParams = async () => {
        const response = await fetch(`http://172.20.10.2:5000/payments/create-payment-intent?email=email@email.com&amount=2000&currency=huf`, {
            headers: {
                'Content-Type': 'application/json'
            },
        })

        const { paymentIntent, ephemeralKey, customer } = await response.json();

        return {
            paymentIntent,
            ephemeralKey,
            customer,
        };
    }
const handleSheet = async () => {

        const {
            paymentIntent,
            ephemeralKey,
            customer,
        } = await fetchPaymentSheetParams();

        const { error }  = await initPaymentSheet({
            merchantDisplayName: "Example, Inc.",
            customerId: customer,
            customerEphemeralKeySecret: ephemeralKey,
            paymentIntentClientSecret: paymentIntent,
            customFlow: true,
            defaultBillingDetails: {
              name: 'Jane Doe',
              country: 'HU'
            }
        });
        if (!error) {
            const { error, paymentOption } = presentPaymentSheet({
                clientSecret: paymentIntent,
            });
            console.log(paymentOption)
        }

    };

But still paymentOption is undefined nor I'm getting save card for future use option

seanzhang-stripe commented 7 months ago

If you set setup_future_usage on a PaymentIntent, the PaymentSheet will hide the 'Save this card for future use' checkbox and always saves. (ref)

About the undefined paymentOption, can you run the example code in your project and see if you still get the undefined paymentOption ?