admin管理员组

文章数量:1399935

I'm trying to create an E-merce website with JavaScript, React, and Stripe.

For the life of me I can't figure out how to include a billing and shipping address in my checkout. I've tried to find an answer online but cant find a working solution I can adapt. Maybe the answer is obvious except to me.

I appreciate any help! I've posted me code below. Thank you.

import React, { useState, useEffect } from "react";
import CheckoutProduct from "./CheckoutProduct";
import "./Payment.css";
import { useStateValue } from "./StateProvider";
import { Link, useHistory } from "react-router-dom";
import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js";
import CurrencyFormat from "react-currency-format";
import { getBasketTotal } from "./reducer";
import axios from "./axios";
import { db } from "./firebase";

function Payment() {
  const [{ basket, user }, dispatch] = useStateValue();
  const history = useHistory();

  const stripe = useStripe();
  const elements = useElements();

  const [succeeded, setSucceeded] = useState(false);
  const [processing, setProcessing] = useState("");
  const [error, setError] = useState(null);
  const [disabled, setDisabled] = useState(true);
  const [clientSecret, setClientSecret] = useState(true);

  useEffect(() => {
    const getClientSecret = async () => {
      const response = await axios({
        method: "post",
        url: `/payments/create?total=${getBasketTotal(basket) * 100}`,
      });
      setClientSecret(response.data.clientSecret);
    };

    getClientSecret();
  }, [basket]);

  console.log("THE SECRET IS >>>", clientSecret);

  const handleSubmit = async (event) => {
    event.preventDefault();
    setProcessing(true);

    const payload = await stripe
      .confirmCardPayment(clientSecret, {
        payment_method: {
          card: elements.getElement(CardElement),
        },
      })
      .then(({ paymentIntent }) => {
        db.collection("users")
          .doc(user?.uid)
          .collection("orders")
          .doc(paymentIntent.id)
          .set({
            basket: basket,
            amount: paymentIntent.amount,
            created: paymentIntent.created,
          });

        setSucceeded(true);
        setError(null);
        setProcessing(false);

        dispatch({
          type: "EMPTY_BASKET",
        });

        history.replace("/orders");
      });
  };

  const handleChange = (event) => {
    setDisabled(event.empty);
    setError(event.error ? event.error.message : "");
  };

  return (
    <div className="payment">
      <div className="payment__container">
        <h1>
          Checkout (<Link to="/checkout">{basket?.length} items</Link>)
        </h1>
        <div className="payment__section">
          <div className="payment__title">
            <h3>Delivery Address</h3>
          </div>
          <div className="payment__address">
            <p>{user?.email}</p>
          </div>
        </div>
        <div className="payment__section">
          <div className="payment__title">
            <h3>Review Items and Delivery</h3>
          </div>
          <div className="payment__items">
            {basket.map((item) => (
              <CheckoutProduct
                id={item.id}
                title={item.title}
                image={item.image}
                price={item.price}
                rating={item.rating}
              />
            ))}
          </div>
        </div>
        <div className="payment__section">
          <div className="payment__title">
            <h3>Payment Method</h3>
          </div>
          <div className="payment__details">
            <form onSubmit={handleSubmit}>
              <CardElement onChange={handleChange} />
              <div className="payment__priceContainer">
                <CurrencyFormat
                  renderText={(value) => (
                    <>
                      <h3>Order Total: {value}</h3>
                    </>
                  )}
                  decimalScale={2}
                  value={getBasketTotal(basket)}
                  displayType={"text"}
                  thousandSeparator={true}
                  prefix={"$"}
                />
                <button disabled={processing || disabled || succeeded}>
                  <span>{processing ? <p>Processing</p> : "Buy Now"}</span>
                </button>
              </div>
              {error && <div>{error}</div>}
            </form>
          </div>
        </div>
      </div>
    </div>
  );
}

export default Payment;

I'm trying to create an E-merce website with JavaScript, React, and Stripe.

For the life of me I can't figure out how to include a billing and shipping address in my checkout. I've tried to find an answer online but cant find a working solution I can adapt. Maybe the answer is obvious except to me.

I appreciate any help! I've posted me code below. Thank you.

import React, { useState, useEffect } from "react";
import CheckoutProduct from "./CheckoutProduct";
import "./Payment.css";
import { useStateValue } from "./StateProvider";
import { Link, useHistory } from "react-router-dom";
import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js";
import CurrencyFormat from "react-currency-format";
import { getBasketTotal } from "./reducer";
import axios from "./axios";
import { db } from "./firebase";

function Payment() {
  const [{ basket, user }, dispatch] = useStateValue();
  const history = useHistory();

  const stripe = useStripe();
  const elements = useElements();

  const [succeeded, setSucceeded] = useState(false);
  const [processing, setProcessing] = useState("");
  const [error, setError] = useState(null);
  const [disabled, setDisabled] = useState(true);
  const [clientSecret, setClientSecret] = useState(true);

  useEffect(() => {
    const getClientSecret = async () => {
      const response = await axios({
        method: "post",
        url: `/payments/create?total=${getBasketTotal(basket) * 100}`,
      });
      setClientSecret(response.data.clientSecret);
    };

    getClientSecret();
  }, [basket]);

  console.log("THE SECRET IS >>>", clientSecret);

  const handleSubmit = async (event) => {
    event.preventDefault();
    setProcessing(true);

    const payload = await stripe
      .confirmCardPayment(clientSecret, {
        payment_method: {
          card: elements.getElement(CardElement),
        },
      })
      .then(({ paymentIntent }) => {
        db.collection("users")
          .doc(user?.uid)
          .collection("orders")
          .doc(paymentIntent.id)
          .set({
            basket: basket,
            amount: paymentIntent.amount,
            created: paymentIntent.created,
          });

        setSucceeded(true);
        setError(null);
        setProcessing(false);

        dispatch({
          type: "EMPTY_BASKET",
        });

        history.replace("/orders");
      });
  };

  const handleChange = (event) => {
    setDisabled(event.empty);
    setError(event.error ? event.error.message : "");
  };

  return (
    <div className="payment">
      <div className="payment__container">
        <h1>
          Checkout (<Link to="/checkout">{basket?.length} items</Link>)
        </h1>
        <div className="payment__section">
          <div className="payment__title">
            <h3>Delivery Address</h3>
          </div>
          <div className="payment__address">
            <p>{user?.email}</p>
          </div>
        </div>
        <div className="payment__section">
          <div className="payment__title">
            <h3>Review Items and Delivery</h3>
          </div>
          <div className="payment__items">
            {basket.map((item) => (
              <CheckoutProduct
                id={item.id}
                title={item.title}
                image={item.image}
                price={item.price}
                rating={item.rating}
              />
            ))}
          </div>
        </div>
        <div className="payment__section">
          <div className="payment__title">
            <h3>Payment Method</h3>
          </div>
          <div className="payment__details">
            <form onSubmit={handleSubmit}>
              <CardElement onChange={handleChange} />
              <div className="payment__priceContainer">
                <CurrencyFormat
                  renderText={(value) => (
                    <>
                      <h3>Order Total: {value}</h3>
                    </>
                  )}
                  decimalScale={2}
                  value={getBasketTotal(basket)}
                  displayType={"text"}
                  thousandSeparator={true}
                  prefix={"$"}
                />
                <button disabled={processing || disabled || succeeded}>
                  <span>{processing ? <p>Processing</p> : "Buy Now"}</span>
                </button>
              </div>
              {error && <div>{error}</div>}
            </form>
          </div>
        </div>
      </div>
    </div>
  );
}

export default Payment;
Share Improve this question edited May 24, 2023 at 16:39 Super Kai - Kazuya Ito 1 asked Sep 8, 2021 at 17:39 heretolearnheretolearn 831 silver badge10 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 4

Stripe allows you collect shipping address for item(s) delivery by adding shipping_address_collection when you create a Checkout session.

According to stripe:

You must also specify which countries to allow shipping to by configuring the allowed countries property with an array of two-letter ISO country codes. These countries appear in the Country dropdown in the Shipping Address form on Checkout.

const session = await stripe.checkout.sessions.create({
//other details
shipping_address_collection: {
allowed_countries: ['US', 'CA'],
},

});

Check stripe documentation for more detail https://stripe./docs/payments/checkout/shipping

Stripe doesn't have an element to collect billing details directly but it's something you can build yourself in your form. Assuming you collect the relevant fields, you would pass the information at the time you call confirmCardPayment as documented here by passing the billing_details parameter:

const payload = await stripe
  .confirmCardPayment(clientSecret, {
    payment_method: {
      card: elements.getElement(CardElement),
      billing_details: {
        name: 'Jenny Rosen',
        address: {
          line1: '1 Main street',
          city: 'San Francisco',
          postal_code: '90210',
          state: 'CA',
          country: 'US',
        },
      },
    },
  });

Similarly, you can pass the shipping details in the same call in the shipping parameter

const payload = await stripe
  .confirmCardPayment(clientSecret, {
    payment_method: {
      card: elements.getElement(CardElement),
    },
    shipping: {
      name: 'Jenny Shipping',
      address: {
        line1: '1 Main street',
        city: 'San Francisco',
        postal_code: '90210',
        state: 'CA',
        country: 'US',
      },
    },
  });

You can bine both in one call.

if using reactjs, you can require billing address like this

        billing_address_collection: 'required'

You can use shipping_address_collection as shown below:

const session = await stripe.checkout.sessions.create({
  ...
  shipping_address_collection: {
    allowed_countries: ['US', 'CA'],
  },
  ...
});

Also, you can use payment_intent_data.shipping to pass a shipping address to Shipping section in Payments on Stripe Dashboard as shown below. *This doesn't pass a shipping address to Stripe Checkout but does pass to Shipping section in Payments on Stripe Dashboard and you cannot use both shipping_address_collection and payment_intent_data.shipping at the same time otherwise there is an error:

const session = await stripe.checkout.sessions.create({
  ...
  payment_intent_data: {
    shipping: {
      name: 'John Smith',
      address: {
        country: 'USA',
        state: 'California',
        city: 'San Francisco',
        line1: '58 Middle Point Rd',
        line2: '',
        postal_code: '94124'
      }
    }
  },
  /*
  shipping_address_collection: {
    allowed_countries: ['US', 'CA'],
  },
  */
  ...
});

本文标签: javascriptHow to add shipping and delivery addresses with StripeStack Overflow