当客户端密码更改时重新渲染 Stripe 元素

问题描述 投票:0回答:1

我正在尝试创建一个购物车页面,其中客户/客户可以编辑/删除购物车项目(购物车中的项目)。因此,当他们编辑/删除购物车中的商品时,总体会发生变化。

目前,如果我将商品添加到购物车并进入购物车页面,支付网关将显示总额(假设为 100 美元)。然后我编辑购物车商品(价格增加/减少,假设现在价格为 50 美元)。现在,如果我按“立即付款”,支付网关将向我收取 100 美元,而不是 50 美元。

我想获取 Stripe 支付网关来更改交易中的购物车总额。

下面的代码是来自PaymentGateway.jsx的代码

import React, { useEffect, useState } from "react";
import CheckoutForm from "./CheckoutForm";
import { loadStripe } from "@stripe/stripe-js";
import axios from "axios";
import { Elements } from "@stripe/react-stripe-js";

const PaymentGateway = ({ cart, handleCart, handleValidation }) => {
    //set cart total and watch for changes in the variable to rerender component
    const [cartTotal, setCartTotal] = useState(cart.total);

    // Stripe functions
    const [stripePromise, setStripePromise] = useState(() =>
        loadStripe('stripe public key' )
    );
    const [clientSecret, setClientSecret] = useState("");
    const appearance = {
        theme: "flat",
    };
    let options = {
        clientSecret: clientSecret,
        appearance: appearance,
    };
    useEffect(() => {
        if (cartTotal > 0) {
            console.log(cartTotal);
            axios
                .post("/api/stripe/create-payment-intent", {
                    total: cartTotal,
                })
                .then((data) => setClientSecret(() => data.data?.clientSecret));
        }
    }, [cartTotal]);

    useEffect(() => {
        setCartTotal(cart.total);
    }, [cart.total]);

    return (
        <div>
            <>
                <div className="cartPage-containerRight-title">
                    Payment Information
                </div>
                {clientSecret && (
                    <>
                        <Elements stripe={stripePromise} options={options}>
                            <CheckoutForm
                                handleCart={handleCart}
                                handleValidation={handleValidation}
                            />
                        </Elements>
                    </>
                )}
            </>
        </div>
    );
};

export default PaymentGateway;

下面的代码来自CheckoutForm.jsx

import React, { useEffect, useState } from "react";
import {
    useStripe,
    useElements,
    PaymentElement,
    LinkAuthenticationElement,
} from "@stripe/react-stripe-js";

const CheckoutForm = ({ handleCart, handleValidation }) => {
    const stripe = useStripe();

    const elements = useElements();
    const [message, setMessage] = useState("");
    const [isLoading, setIsLoading] = useState(false);

    useEffect(() => {
        if (!stripe) {
            return;
        }

        const clientSecret = new URLSearchParams(window.location.search).get(
            "payment_intent_client_secret"
        );

        if (!clientSecret) {
            return;
        }

        stripe.retrievePaymentIntent(clientSecret).then(({ paymentIntent }) => {
            switch (paymentIntent.status) {
                case "succeeded":
                    setMessage("Payment succeeded!");
                    break;
                case "processing":
                    setMessage("Your payment is processing.");
                    break;
                case "requires_payment_method":
                    setMessage(
                        "Your payment was not successful, please try again."
                    );
                    break;
                default:
                    setMessage("Something went wrong.");
                    break;
            }
        });
    }, [stripe]);

    const handleSubmit = async (event) => {
        event.preventDefault();
        if (handleValidation()) {
            // We don't want to let default form submission happen here,
            // which would refresh the page.

            if (!stripe || !elements) {
                // Stripe.js hasn't yet loaded.
                // Make sure to disable form submission until Stripe.js has loaded.
                return;
            }

            setIsLoading(true);

            const { error } = await stripe.confirmPayment({
                //`Elements` instance that was used to create the Payment Element
                elements,
                confirmParams: {
                    return_url: "http://localhost:3000",
                },
                redirect: "if_required",
            });

            if (error) {
                // This point will only be reached if there is an immediate error when
                // confirming the payment. Show error to your customer (for example, payment
                // details incomplete)
                setMessage(error.message);
                setIsLoading(false);
            } else {
                handleCart();
                // Your customer will be redirected to your `return_url`. For some payment
                // methods like iDEAL, your customer will be redirected to an intermediate
                // site first to authorize the payment, then redirected to the `return_url`.
            }
        }
    };
    const paymentElementOptions = {
        layout: "tabs",
    };

    return (
        <form onSubmit={handleSubmit} className="cartCheckout-paymentDetails">
            <PaymentElement options={paymentElementOptions} />
            <div className="cartCheckout-button-container">
                <button
                    disabled={isLoading && !stripe && !elements}
                    id="submit"
                    className="cartCheckout-button"
                >
                    <span id="button-text">
                        {isLoading ? (
                            <div className="spinner" id="spinner"></div>
                        ) : (
                            "Pay now"
                        )}
                    </span>
                </button>
            </div>
            {message && (
                <div
                    id="payment-message"
                    style={{ color: "red", textAlign: "center" }}
                >
                    {message}
                </div>
            )}
        </form>
    );
};

export default CheckoutForm;

这是支付网关的代码块。我想每次 clientSecret 更改时重新渲染 Stripe Payment Element。 或者我想要一种方法让支付网关仅收取购物车中的最终金额而不是额外费用。

javascript node.js reactjs stripe-payments payment-gateway
1个回答
0
投票

一旦指定,您就无法在不重新挂载的情况下更改传递给 Elements 的

client_secrete

当购物车商品发生变化时,您应该考虑更新 PaymentIntent 的金额(从后端发送更新请求),并调用 elements.fetchUpdates() 以反映 Payment Element 中的更新。

© www.soinside.com 2019 - 2024. All rights reserved.