Ons Jannet
Ons Jannet

Reputation: 367

Stripe Integration with React Native

I have to integrate Stripe with my React Native Application this phone application is a phone version of a desktop application where stripe is already being integrated and works fine so the backend is already been implemented. I wanted to use the context i used i nthe react js application however the useElementwas not available in stripe/stripe-react-native however after some reasearch i figured it didn't matter if i used the @stripe/stripe-js library my problem now is i keep getting the error: Could not find Elements context; You need to wrap the part of your app that calls useElements() in an <Elements> provider. However i already wrapped the form in an provider this is my checkoutForm.js:

import { useNavigation } from '@react-navigation/native';

import 
  React, 
  { useState, 
  useEffect, useRef } 
from 'react'

import { 
    View, 
    Text, 
    SafeAreaView, 
    StatusBar, 
    StyleSheet, 
    TouchableOpacity, 
    ScrollView, 
    Image,
    Pressable , 
    TextInput, 
    Alert} 
from 'react-native';

import Icon from '../components'
import { COLORS } from '../constants';
import { useStateContext } from '../context/StateContext';
import { ProductCarousel } from '../../components';
import { useElements, Elements} from "@stripe/react-stripe-js"
import { CardField, useConfirmPayment, useStripe,  } from '@stripe/stripe-react-native';
import { Button } from 'react-native-elements';


const CheckoutForm = () => {

  const navigation = useNavigation();
  const [isDeliveryAddressOpen, setIsDeliveryAddressOpen] = useState(false);
  const [isContactNumberOpen, setIsContactNumberOpen] = useState(false);
  const [isDeliveryInstructionsOpen, setIsDeliveryInstructionsOpen] = useState(false);
  const [isCartItemsOpen, setIsCartItemsOpen] = useState(false);  
  const [isPaymentInfoOpen, setIsPaymentInfoOpen] = useState(false);
  //const { confirmPayment, loading } = useConfirmPayment();

  const [success, setSuccess ] = useState(false)
  const stripe = useStripe()
  const elements = useElements()
  const cardElement = useRef(null);

  const {  totalPrice,  cartItems } = useStateContext();

  const [fullName, setFullName] = useState('');
  const [email, setEmail] = useState('');
  const [address, setAddress] = useState('');
  const [address2, setAddress2] = useState('');  
  const [state, setState] = useState('');
  const [city, setCity] = useState('');
  const [zipCode, setZipCode] = useState('');
  const [primaryNumber, setPrimaryNumber] = useState('');
  const [SecondaryNumber, setSecondaryNumber] = useState('');
  const [DeliveryInstructions, setDeliveryInstructions] = useState('');   

  const [isProcessing, setIsProcessing] = useState(false);
  const [isError, setIsError] = useState(false);
  //const [cardDetails, setCardDetails] = useState('')


  

  const toggleDeliveryAddress = () => {
    setIsDeliveryAddressOpen(!isDeliveryAddressOpen);
  };

  const toggleContactNumber = () => {
    setIsContactNumberOpen(!isContactNumberOpen);
  };

  const toggleDeliveryInstructions = () => {
    setIsDeliveryInstructionsOpen(!isDeliveryInstructionsOpen);
  };

  const toggleCartItems = () => {
    setIsCartItemsOpen(!isCartItemsOpen);
  };

  const togglePaymentInfo = () => {
    setIsPaymentInfoOpen(!isPaymentInfoOpen);
  };


 //const navigate = useNavigate();
  const carts = { 
    status: 'pending', 
    items: (cartItems), 
    address, 
    fullName, 
    zipCode, 
    state,
    city,
    DeliveryInstructions, 
    primaryNumber, 
    SecondaryNumber, 
    totalPrice
  }

  const handleCheckout = async () => {
    
    const response = await fetch('/create_cart', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(carts),
    });

    if(response.statusCode === 500) return;
    // eslint-disable-next-line
    const data = await response.json();
    console.log('presseddddd', data)
  }  

 /*========================================================*/

 const handleSubmit = async () => {
       
    const {error, paymentMethod} = await stripe.createPaymentMethod({
        type: "card",
        card: elements.getElement(CardField),
        billing_details: {
            name: fullName,
            phone: primaryNumber,
            email: email,
            address: {
              city: city,
              line1: address,
              state: state,
              postal_code: zipCode
            }
          },
    })

    if(!error) {
        try {
            const {id} = paymentMethod
            
            const carts = { 
              id, 
              amount: totalPrice, 
              confirm: true, 
              currency: 'CAD'
            }

            setIsProcessing(true);
            
            const response = await fetch('/create-payment-intent', {
                method: 'POST',
                headers: {
                'Content-Type': 'application/json',
                },
                body: JSON.stringify(carts),
            });


            if(response.status === 200) {
                console.log(response.status)
                console.log("Successful payment")
                setSuccess(true)
            }

            const data = await response.json();

            if(response.status >= 400) {
              console.log(response.status)
              console.log(data.error.split(':').pop())
              setIsError(data.error)
          }

        } catch (error) {
            console.log("Error", error)
        }
    } else {
        console.log(error.message)

    }

    setIsProcessing(false)

    
    //navigate('/');
  }



  return (
    <View style={styles.container}>
        <View style={styles.insideContainer}>         
        <TouchableOpacity style={styles.titleContainer} onPress={togglePaymentInfo}>
            <Text style={styles.title}>Payment Info</Text>
            {!isPaymentInfoOpen ? 
            <Icon icon ='add-outline' color='#000' size={20}/>
            : <Icon icon ='remove-outline' color='#000' size={20}/> 
            }
        </TouchableOpacity>
        {isPaymentInfoOpen && (
            <View style={styles.containercollapsed}>
                <View style={{width: '98%'}}>
                <CardField
                    ref={cardElement}
                    postalCodeEnabled={false}
                    placeholders={{
                    number: '4242 4242 4242 4242',
                    }}
                    cardStyle={{
                    backgroundColor: '#FFFFFF',
                    textColor: '#000000',
                    borderColor: COLORS.lightGray2,
                    borderWidth: 1,
                    borderRadius: 4
                    }}
                    style={{
                    width: '100%',
                    height: 50,
                            
                    }}
                    onCardChange={(cardDetails) => {
                    }}
                    onFocus={(focusedField) => {
                    }}
                />
                </View>                
            </View>
        )}
        </View>   

        <View style={styles.PaybuttonView}>
        <Button
          title="Pay"
          onPress={ () => handleSubmit()}
          /*disabled={loading}
          loading={loading}*/
          />
          {/*<Pressable style={styles.Paybutton} onPress={() => {handleCheckout(); handlePayPress()} }>
            <Text style={{textAlign: 'center', fontSize: 20, color: '#FFFF', textTransform: 'uppercase'}}>Checkout</Text>
              </Pressable>*/}
        </View>           

  </View>
  )
}

export default CheckoutForm

this is my StripeForm.js :

import React from 'react'
import {Elements} from "@stripe/react-stripe-js"
import CheckoutForm from './CheckoutForm';
import { loadStripe } from "@stripe/stripe-js"

const stripePromise = loadStripe(i removed the key but this is the key's place);

export const StipeForm = () => {
    return (
        <Elements stripe={stripePromise}>
            <CheckoutForm />
        </Elements>
    ) 
}

Upvotes: 0

Views: 1550

Answers (2)

Oskar Mast
Oskar Mast

Reputation: 1

I have already experience in this issue.

import {Elements} from "@stripe/react-stripe-js"

This is available only for React version. React Native doesn't support this.

Upvotes: 0

bismarck
bismarck

Reputation: 732

To initialize Stripe to be used with the Stripe React Native SDK you need to use either StripeProvider or initStripe. See the docs here. You can't use the React Stripe.JS library initialize Stripe for the React Native SDK.

Upvotes: 1

Related Questions