Search code examples
javascriptreactjsfunctionstripe-paymentspayment

Processing Stripe payment in react


I am successfully able to process Stripe payments in react using the following:

const processPayment = async () => {
        const url = '/.netlify/functions/charge-card';
        const newItems = items.map(({ id, quantity }) => ({
            id,
            quantity,
        }));

        const stripe = await loadStripe(publishableKey);
        const { data } = await axios.post(url, { items: newItems });
        await stripe.redirectToCheckout({ sessionId: data.id });
    };

This is the only method that will work for me

exports.handler = async (event, context) => {
    const { items } = JSON.parse(event.body);
    const allItems = await getProducts();

    const cartWithProducts = items.map(({ id, quantity }) => {
        const item = allItems.find(p => p.id === id);
        return {
            ...item,
            quantity,
        };
    });

    const lineItems = cartWithProducts.map(product => ({
        price_data: {
            currency: 'usd',
            product_data: {
                name: product.name,
            },
            unit_amount: product.price,
        },
        quantity: product.quantity,
    }));

    const session = await stripe.checkout.sessions.create({
        payment_method_types: ['card'],
        line_items: lineItems,
        mode: 'payment',
        success_url: `${process.env.URL}/success`,
        cancel_url: `${process.env.URL}/cancelled`,
    });

    console.log(lineItems);

    return {
        statusCode: 200,
        body: JSON.stringify({
            id: session.id,
        }),
    };

However, I don't want to use await stripe.redirectToCheckout({ sessionId: data.id }); because I don't want to be redirected to Stripe's site. I want to do something like this:

return (
        <StripeCheckout
            label={'Pay Now'}
            name={'CRWN Clothing Ltd.'}
            billingAddress
            shippingAddress
            image={'https://svgshare.com/i/CUz.svg'}
            description={`Your total is $${price}`}
            amount={priceForStripe}
            panelLabel={'Pay Now'}
            token={processPayment}
            stripeKey={publishableKey}
            
        />

This shows the popup and allows me to enter all the info and submit the payment however nothing actually happens. I don't know if it has something to do with the sessionId and data.id. Is there another function I can use instead of stripe.redirectToCheckout that would process the info?


Solution

  • OK I got it to work. Here is my processPayment:

    const processPayment = token => {
            const url = '/.netlify/functions/charge-card';
            const options = {
                method: 'POST',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json;charset=UTF-8',
                },
                body: JSON.stringify({
                    amount: priceForStripe,
                    token,
                }),
            };
            fetch(url, options)
                .then(response => {
                    alert('Payment Successful');
                }).catch(error => {
                console.log('Payment error:', error);
                alert('There was in issue with your payment. Please make sure you use the provided credit card.');
            });
        };
    

    My StripeCheckoutButton:

    <StripeCheckout
                label={'Pay Now'}
                name={'CRWN Clothing Ltd.'}
                billingAddress
                shippingAddress
                image={'https://svgshare.com/i/CUz.svg'}
                description={`Your total is $${price}`}
                amount={priceForStripe}
                panelLabel={'Pay Now'}
                token={processPayment}
                stripeKey={publishableKey}
            />
    

    I really didn't need access to the items just the total price so I changed my exports.handler to:

    exports.handler = async (event, context) => {
        const data = JSON.parse(event.body);
        const body = {
            source: data.token.id,
            amount: data.amount,
            currency: 'usd',
        };
    
        await stripe.charges.create(body, (stripeErr, stripeRes) => {
            if (stripeErr) {
                return {
                    statusCode: 500,
                    body: stripeErr,
                };
            } else {
                return {
                    statusCode: 200,
                    body: stripeRes,
                };
            }
        });
    };
    

    Now everything works. I can use the popup from stripe and not be redirected and the payments process completely on stripes end.