Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Paypal React / Next JS buttons not updating after changing products quantities in cart

I'm encountering an issue with the React PayPal Buttons integration. When I change the quantity of products directly in the cart, the products are updating in the local storage and in the cart, but the changes are not reflected in the PaypalButtons component props createOrder and onApprove. As a result, the total amount in the PayPal standard checkout is incorrect, and can't put the right quantity of products in my database.

Here's the relevant code :

'use client'

import { PayPalButtons, PayPalScriptProvider } from '@paypal/react-paypal-js'
import { createPaypalOrder, handlePaypalCheckout } from '../../_actions/paypal'
import { useRouter } from 'next/navigation'
import { useContext } from 'react'
import { CartContext } from '@/app/_context/CartContext'
import { toast } from '../ui/use-toast'
import { useSession } from 'next-auth/react'
export default function PaypalButton({ total, uniqueProducts }) {
  console.log('🚀 ~ PaypalButton ~ uniqueProducts:', uniqueProducts)
  console.log('🚀 ~ total:', total)
  const { data: session } = useSession()
  console.log('🚀 ~ session:', session?.user.email)
  const { setShowCart } = useContext(CartContext)

  const router = useRouter()

  const captureOrder = async (orderId) => {
    try {
      const res = await fetch('/api/paypal/capture', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ orderId: orderId }),
      })

      const orderCapture = await res.json()

      if (orderCapture.status == 200) {
        const orderId = await createPaypalOrder(
          uniqueProducts,
          orderCapture.response.result,
          total,
          session?.user.email,
        )
        setShowCart(false)
        router.push(`/order/success?order_id=${orderId}`)
      }
    } catch (error) {
      toast({
        title: 'Invalid payment',
        variant: 'destructive',
      })
      console.log('🚀 ~ captureOrder ~ error:', error)
    }
  }

  const createOrderAction = async () => {
    try {
      console.log(total)
      console.log(uniqueProducts)

      const res = await fetch('/api/paypal', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ total: total }),
      })
      const order = await res.json()
      if (order.id) return order.id
      else {
        const errorDetail = order?.details?.[0]
        const errorMessage = errorDetail
          ? `${errorDetail.issue} ${errorDetail.description} (${orderData.debug_id})`
          : JSON.stringify(orderData)

        throw new Error(errorMessage)
      }
    } catch (error) {
      console.log('🚀 ~ createOrderAction ~ error:', error)
      console.error(error)
    }
  }

  return (
    <div>
      <PayPalScriptProvider
        options={{
          clientId:
            'test',
          disableFunding: 'card',
          currency: 'EUR',
        }}
      >
        <PayPalButtons
          style={{
            color: 'gold',
            disableMaxWidth: 'true',
          }}
          createOrder={async (data, actions) => {
            const orderId = createOrderAction()
            return orderId
          }}
          onApprove={async (data, actions) => {
            const orderCapture = await captureOrder(data.orderID)
            if (orderCapture) return true
          }}
          onCancel={(data) => {}}
          onError={(err) => {
            console.log('🚀 ~ err:', err)
            console.error('PayPal Checkout onError', err)
          }}
        />
      </PayPalScriptProvider>
    </div>
  )
}

The console log in createOrder and onApprove always display the old uniqueProducts and total before I changed the quantity

I've attempted to pass the updated product items in the request body when creating the order, but I couldn't retrieve them when capturing the order. I've also tried to retrieve the updated products directly in the local storage and the total using useRef just before fetching the backend, it was working in the createOrderAction but not the captureOrder which is the crucial one to send data to my database.

like image 285
alexbyte Avatar asked Dec 22 '25 06:12

alexbyte


1 Answers

You can use forceReRender props in the PaypalButtons component and the cart will update accordingly

  <PayPalButtons
      forceReRender={[uniqueProducts]}
      style={{
        color: 'gold',
        disableMaxWidth: 'true',
      }}
      createOrder={async (data, actions) => {
        const orderId = createOrderAction()
        return orderId
      }}
      onApprove={async (data, actions) => {
        const orderCapture = await captureOrder(data.orderID)
        if (orderCapture) return true
      }}
      onCancel={(data) => {}}
      onError={(err) => {
        console.log('🚀 ~ err:', err)
        console.error('PayPal Checkout onError', err)
      }}
    />

Here is an example with this props in the official documentation https://paypal.github.io/react-paypal-js/?path=/docs/example-paypalbuttons--default

like image 174
samidare Avatar answered Dec 24 '25 00:12

samidare



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!