|
|
@@ -16,9 +16,10 @@ import { StripePluginOptions } from './types';
|
|
|
* ## Requirements
|
|
|
*
|
|
|
* 1. You will need to create a Stripe account and get your secret key in the dashboard.
|
|
|
- * 2. Create a webhook endpoint in the Stripe dashboard which listens to the `payment_intent.succeeded` and
|
|
|
- * `payment_intent.payment_failed` events. The URL should be `https://my-shop.com/payments/stripe`, where
|
|
|
- * `my-shop.com` is the host of your storefront application.
|
|
|
+ * 2. Create a webhook endpoint in the Stripe dashboard (Developers -> Webhooks, "Add an endpoint") which listens to the `payment_intent.succeeded`
|
|
|
+ * and `payment_intent.payment_failed` events. The URL should be `https://my-shop.com/payments/stripe`, where
|
|
|
+ * `my-shop.com` is the host of your storefront application. *Note:* for local development, you'll need to use
|
|
|
+ * the Stripe CLI to test your webhook locally. See the _local development_ section below.
|
|
|
* 3. Get the signing secret for the newly created webhook.
|
|
|
* 4. Install the Payments plugin and the Stripe Node library:
|
|
|
*
|
|
|
@@ -63,18 +64,95 @@ import { StripePluginOptions } from './types';
|
|
|
*
|
|
|
* The high-level workflow is:
|
|
|
* 1. Create a "payment intent" on the server by executing the `createStripePaymentIntent` mutation which is exposed by this plugin.
|
|
|
- * 2. Use the returned client secret to instantiate the Stripe Payment Element.
|
|
|
+ * 2. Use the returned client secret to instantiate the Stripe Payment Element:
|
|
|
+ * ```TypeScript
|
|
|
+ * import { Elements } from '\@stripe/react-stripe-js';
|
|
|
+ * import { loadStripe, Stripe } from '\@stripe/stripe-js';
|
|
|
+ * import { CheckoutForm } from './CheckoutForm';
|
|
|
+ *
|
|
|
+ * const stripePromise = getStripe('pk_test_....wr83u');
|
|
|
+ *
|
|
|
+ * type StripePaymentsProps = {
|
|
|
+ * clientSecret: string;
|
|
|
+ * orderCode: string;
|
|
|
+ * }
|
|
|
+ *
|
|
|
+ * export function StripePayments({ clientSecret, orderCode }: StripePaymentsProps) {
|
|
|
+ * const options = {
|
|
|
+ * // passing the client secret obtained from the server
|
|
|
+ * clientSecret,
|
|
|
+ * }
|
|
|
+ * return (
|
|
|
+ * <Elements stripe={stripePromise} options={options}>
|
|
|
+ * <CheckoutForm orderCode={orderCode} />
|
|
|
+ * </Elements>
|
|
|
+ * );
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ * ```TypeScript
|
|
|
+ * // CheckoutForm.tsx
|
|
|
+ * import { useStripe, useElements, PaymentElement } from '@stripe/react-stripe-js';
|
|
|
+ * import { FormEvent } from 'react';
|
|
|
+ *
|
|
|
+ * export const CheckoutForm = ({ orderCode }: { orderCode: string }) => {
|
|
|
+ * const stripe = useStripe();
|
|
|
+ * const elements = useElements();
|
|
|
+ *
|
|
|
+ * const handleSubmit = async (event: FormEvent) => {
|
|
|
+ * // We don't want to let default form submission happen here,
|
|
|
+ * // which would refresh the page.
|
|
|
+ * event.preventDefault();
|
|
|
+ *
|
|
|
+ * if (!stripe || !elements) {
|
|
|
+ * // Stripe.js has not yet loaded.
|
|
|
+ * // Make sure to disable form submission until Stripe.js has loaded.
|
|
|
+ * return;
|
|
|
+ * }
|
|
|
+ *
|
|
|
+ * const result = await stripe.confirmPayment({
|
|
|
+ * //`Elements` instance that was used to create the Payment Element
|
|
|
+ * elements,
|
|
|
+ * confirmParams: {
|
|
|
+ * return_url: location.origin + `/checkout/confirmation/${orderCode}`,
|
|
|
+ * },
|
|
|
+ * });
|
|
|
+ *
|
|
|
+ * if (result.error) {
|
|
|
+ * // Show error to your customer (for example, payment details incomplete)
|
|
|
+ * console.log(result.error.message);
|
|
|
+ * } else {
|
|
|
+ * // 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`.
|
|
|
+ * }
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * return (
|
|
|
+ * <form onSubmit={handleSubmit}>
|
|
|
+ * <PaymentElement />
|
|
|
+ * <button disabled={!stripe}>Submit</button>
|
|
|
+ * </form>
|
|
|
+ * );
|
|
|
+ * };
|
|
|
+ * ```
|
|
|
* 3. Once the form is submitted and Stripe processes the payment, the webhook takes care of updating the order without additional action
|
|
|
- * in the storefront.
|
|
|
+ * in the storefront. As in the code above, the customer will be redirected to `/checkout/confirmation/${orderCode}`.
|
|
|
*
|
|
|
- * ## Local development
|
|
|
+ * {{% alert "primary" %}}
|
|
|
+ * A full working storefront example of the Stripe integration can be found in the
|
|
|
+ * [Remix Starter repo](https://github.com/vendure-ecommerce/storefront-remix-starter/tree/master/app/components/checkout/stripe)
|
|
|
+ * {{% /alert %}}
|
|
|
*
|
|
|
- * Use something like [localtunnel](https://github.com/localtunnel/localtunnel) to test on localhost.
|
|
|
+ * ## Local development
|
|
|
*
|
|
|
- * ```bash
|
|
|
- * npx localtunnel --port 3000 --subdomain my-shop-local-dev
|
|
|
- * > your url is: https://my-shop-local-dev.loca.lt
|
|
|
- * ```
|
|
|
+ * 1. Download & install the Stripe CLI: https://stripe.com/docs/stripe-cli
|
|
|
+ * 2. From your Stripe dashboard, go to Developers -> Webhooks and click "Add an endpoint" and follow the instructions
|
|
|
+ * under "Test in a local environment".
|
|
|
+ * 3. The Stripe CLI command will look like
|
|
|
+ * ```shell
|
|
|
+ * stripe listen --forward-to localhost:3000/payments/stripe
|
|
|
+ * ```
|
|
|
+ * 4. The Stripe CLI will create a webhook signing secret you can then use in your config of the StripePlugin.
|
|
|
*
|
|
|
* @docsCategory payments-plugin
|
|
|
* @docsPage StripePlugin
|