From 8f218daf16959f6c8aa6f1d0262aeb124bd4214b Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Tue, 30 Nov 2021 17:22:47 +0100 Subject: [PATCH] docs(payments-plugin): Add inline documentation for Braintree plugin Relates to #1087 --- .../payments-plugin/src/braintree/README.md | 46 +---- .../src/braintree/braintree-plugin.ts | 26 --- ...payment-method.ts => braintree.handler.ts} | 2 +- .../src/braintree/braintree.plugin.ts | 193 ++++++++++++++++++ .../src/braintree/braintree.resolver.ts | 2 +- .../payments-plugin/src/braintree/index.ts | 4 +- .../payments-plugin/src/braintree/types.ts | 2 +- 7 files changed, 201 insertions(+), 74 deletions(-) delete mode 100644 packages/payments-plugin/src/braintree/braintree-plugin.ts rename packages/payments-plugin/src/braintree/{braintree-payment-method.ts => braintree.handler.ts} (99%) create mode 100644 packages/payments-plugin/src/braintree/braintree.plugin.ts diff --git a/packages/payments-plugin/src/braintree/README.md b/packages/payments-plugin/src/braintree/README.md index 3fbda1f0a3..b6d8997576 100644 --- a/packages/payments-plugin/src/braintree/README.md +++ b/packages/payments-plugin/src/braintree/README.md @@ -1,46 +1,6 @@ -# Braintree plugin +# Braintree payment plugin -This plugin enables payments to be processed by [Braintree](https://www.braintreepayments.com/), a popular payment provider. +This plugin enables payments to be processed by [Braintree](https://www.braintreepayments.com/). -## Requirements +For documentation, see https://www.vendure.io/docs/typescript-api/payments-plugin/braintree-plugin -1. You will need to create a Braintree sandbox account as outlined in https://developers.braintreepayments.com/start/overview. -2. Then install `braintree` and `@types/braintree` from npm. This plugin was written with `v3.0.0` of the Braintree lib. - -## Setup - -1. Add the plugin to your VendureConfig `plugins` array. -2. In the admin UI, fill in the `merchantId`, `publicKey` & `privateKey` from your Braintree sandbox account. - -## Usage - -The plugin is designed to work with the [Braintree drop-in UI](https://developers.braintreepayments.com/guides/drop-in/overview/javascript/v3). - -In your storefront, you'll have some code like this to submit the payment: - -```TypeScript -async function submitPayment() { - const paymentResult = await this.dropin.requestPaymentMethod(); - myGraphQlClient.mutation(gql` - mutation { - addPaymentToOrder(input: $input) { - id - state - payments { - id - amount - errorMessage - method - state - transactionId - createdAt - } - } - }`, { - input: { - method: 'braintree', - metadata: paymentResult, - }, - }); -} -``` diff --git a/packages/payments-plugin/src/braintree/braintree-plugin.ts b/packages/payments-plugin/src/braintree/braintree-plugin.ts deleted file mode 100644 index dcee266566..0000000000 --- a/packages/payments-plugin/src/braintree/braintree-plugin.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { PluginCommonModule, VendurePlugin } from '@vendure/core'; -import { gql } from 'apollo-server-core'; - -import { braintreePaymentMethodHandler } from './braintree-payment-method'; -import { BraintreeResolver } from './braintree.resolver'; - -/** - * This plugin implements the Braintree (https://www.braintreepayments.com/) payment provider. - */ -@VendurePlugin({ - imports: [PluginCommonModule], - providers: [], - configuration: config => { - config.paymentOptions.paymentMethodHandlers.push(braintreePaymentMethodHandler); - return config; - }, - shopApiExtensions: { - schema: gql` - extend type Query { - generateBraintreeClientToken(orderId: ID!): String! - } - `, - resolvers: [BraintreeResolver], - }, -}) -export class BraintreePlugin {} diff --git a/packages/payments-plugin/src/braintree/braintree-payment-method.ts b/packages/payments-plugin/src/braintree/braintree.handler.ts similarity index 99% rename from packages/payments-plugin/src/braintree/braintree-payment-method.ts rename to packages/payments-plugin/src/braintree/braintree.handler.ts index 9e889f0d67..6eea5148b7 100644 --- a/packages/payments-plugin/src/braintree/braintree-payment-method.ts +++ b/packages/payments-plugin/src/braintree/braintree.handler.ts @@ -9,7 +9,7 @@ import { loggerCtx } from './constants'; */ export const braintreePaymentMethodHandler = new PaymentMethodHandler({ code: 'braintree', - description: [{ languageCode: LanguageCode.en, value: 'Braintree' }], + description: [{ languageCode: LanguageCode.en, value: 'Braintree payments' }], args: { merchantId: { type: 'string', label: [{ languageCode: LanguageCode.en, value: 'Merchant ID' }] }, publicKey: { type: 'string', label: [{ languageCode: LanguageCode.en, value: 'Private Key' }] }, diff --git a/packages/payments-plugin/src/braintree/braintree.plugin.ts b/packages/payments-plugin/src/braintree/braintree.plugin.ts new file mode 100644 index 0000000000..124cac5f02 --- /dev/null +++ b/packages/payments-plugin/src/braintree/braintree.plugin.ts @@ -0,0 +1,193 @@ +import { PluginCommonModule, VendurePlugin } from '@vendure/core'; +import { gql } from 'apollo-server-core'; + +import { braintreePaymentMethodHandler } from './braintree.handler'; +import { BraintreeResolver } from './braintree.resolver'; + +/** + * @description + * This plugin enables payments to be processed by [Braintree](https://www.braintreepayments.com/), a popular payment provider. + * + * ## Requirements + * + * 1. You will need to create a Braintree sandbox account as outlined in https://developers.braintreepayments.com/start/overview. + * 2. Then install `braintree` and `@types/braintree` from npm. This plugin was written with `v3.x` of the Braintree lib. + * ```shell + * yarn add \@vendure/payments-plugin braintree + * yarn add -D \@types/braintree + * ``` + * or + * ```shell + * npm install \@vendure/payments-plugin braintree + * npm install -D \@types/braintree + * ``` + * + * ## Setup + * + * 1. Add the plugin to your VendureConfig `plugins` array: + * ```TypeScript + * import { BraintreePlugin } from '\@vendure/payments-plugin/package/braintree'; + * + * // ... + * + * plugins: [ + * BraintreePlugin, + * ] + * ``` + * 2. Create a new PaymentMethod in the Admin UI, and select "Braintree payments" as the handler. + * 2. Fill in the `Merchant ID`, `Public Key` & `Private Key` from your Braintree sandbox account. + * + * ## Storefront usage + * + * The plugin is designed to work with the [Braintree drop-in UI](https://developers.braintreepayments.com/guides/drop-in/overview/javascript/v3). + * This is a library provided by Braintree which will handle the payment UI for you. You can install it in your storefront project + * with: + * + * ```shell + * yarn add braintree-web-drop-in + * # or + * npm install braintree-web-drop-in + * ``` + * + * The high-level workflow is: + * 1. Generate a "client token" on the server by executing the `generateBraintreeClientToken` mutation which is exposed by this plugin. + * 2. Use this client token to instantiate the Braintree Dropin UI. + * 3. Listen for the `"paymentMethodRequestable"` event which emitted by the Dropin. + * 4. Use the Dropin's `requestPaymentMethod()` method to get the required payment metadata. + * 5. Pass that metadata to the `addPaymentToOrder` mutation. + * + * Here is an example of how your storefront code will look. Note that this example is attempting to + * be framework-agnostic, so you'll need to adapt it to fit to your framework of choice. + * + * ```TypeScript + * // The Braintree Dropin instance + * let dropin: import('braintree-web-drop-in').Dropin; + * + * // Used to show/hide a "submit" button, which would be bound to the + * // `submitPayment()` method below. + * let showSubmitButton = false; + * + * // Used to display a "processing..." spinner + * let processing = false; + * + * // + * // This method would be invoked when the payment screen is mounted/created. + * // + * async function renderDropin(order: Order, clientToken: string) { + * // Lazy load braintree dropin because it has a reference + * // to `window` which breaks SSR + * dropin = await import('braintree-web-drop-in').then((module) => + * module.default.create({ + * authorization: clientToken, + * // This assumes a div in your view with the corresponding ID + * container: '#dropin-container', + * card: { + * cardholderName: { + * required: true, + * }, + * overrides: {}, + * }, + * // Additional config is passed here depending on + * // which payment methods you have enabled in your + * // Braintree account. + * paypal: { + * flow: 'checkout', + * amount: order.totalWithTax, + * currency: 'GBP', + * }, + * }), + * ); + * + * dropin.on('paymentMethodRequestable', (payload) => { + * if (payload.type === 'CreditCard') { + * showSubmitButton = true; + * } + * if (payload.type === 'PayPalAccount') { + * this.submitPayment(); + * } + * }); + * + * dropin.on('noPaymentMethodRequestable', () => { + * // Display an error + * }); + * } + * + * async function generateClientToken(orderId: string) { + * const { generateBraintreeClientToken } = await graphQlClient.query(gql` + * query GenerateBraintreeClientToken($orderId: ID!) { + * generateBraintreeClientToken(orderId: $orderId) + * } + * `, { orderId }); + * return generateBraintreeClientToken; + * } + * + * async submitPayment() { + * if (!dropin.isPaymentMethodRequestable()) { + * return; + * } + * showSubmitButton = false; + * processing = true; + * + * const paymentResult = await dropin.requestPaymentMethod(); + * + * const { addPaymentToOrder } = await graphQlClient.query(gql` + * mutation AddPayment($input: PaymentInput!) { + * addPaymentToOrder(input: $input) { + * ... on Order { + * id + * payments { + * id + * amount + * errorMessage + * method + * state + * transactionId + * createdAt + * } + * } + * ... on ErrorResult { + * errorCode + * message + * } + * } + * }`, { + * input: { + * method: 'braintree', // The code of you Braintree PaymentMethod + * metadata: paymentResult, + * }, + * }, + * ); + * + * switch (addPaymentToOrder?.__typename) { + * case 'Order': + * // Adding payment succeeded! + * break; + * case 'OrderStateTransitionError': + * case 'OrderPaymentStateError': + * case 'PaymentDeclinedError': + * case 'PaymentFailedError': + * // Display an error to the customer + * dropin.clearSelectedPaymentMethod(); + * } + * } + * ``` + * @docsCategory payments-plugin + * @docsPage BraintreePlugin + */ +@VendurePlugin({ + imports: [PluginCommonModule], + providers: [], + configuration: config => { + config.paymentOptions.paymentMethodHandlers.push(braintreePaymentMethodHandler); + return config; + }, + shopApiExtensions: { + schema: gql` + extend type Query { + generateBraintreeClientToken(orderId: ID!): String! + } + `, + resolvers: [BraintreeResolver], + }, +}) +export class BraintreePlugin {} diff --git a/packages/payments-plugin/src/braintree/braintree.resolver.ts b/packages/payments-plugin/src/braintree/braintree.resolver.ts index ae9a4b1bfa..4fa6ec875e 100644 --- a/packages/payments-plugin/src/braintree/braintree.resolver.ts +++ b/packages/payments-plugin/src/braintree/braintree.resolver.ts @@ -11,7 +11,7 @@ import { } from '@vendure/core'; import { getGateway } from './braintree-common'; -import { braintreePaymentMethodHandler } from './braintree-payment-method'; +import { braintreePaymentMethodHandler } from './braintree.handler'; import { loggerCtx } from './constants'; import { PaymentMethodArgsHash } from './types'; diff --git a/packages/payments-plugin/src/braintree/index.ts b/packages/payments-plugin/src/braintree/index.ts index 9bcc137c5d..de7d5b7d56 100644 --- a/packages/payments-plugin/src/braintree/index.ts +++ b/packages/payments-plugin/src/braintree/index.ts @@ -1,4 +1,4 @@ -export * from './braintree-plugin'; -export * from './braintree-payment-method'; +export * from './braintree.plugin'; +export * from './braintree.handler'; export * from './braintree.resolver'; export * from './braintree-common'; diff --git a/packages/payments-plugin/src/braintree/types.ts b/packages/payments-plugin/src/braintree/types.ts index e56f2d8301..16ccb2d03b 100644 --- a/packages/payments-plugin/src/braintree/types.ts +++ b/packages/payments-plugin/src/braintree/types.ts @@ -1,5 +1,5 @@ import { ConfigArgValues } from '@vendure/core/dist/common/configurable-operation'; -import { braintreePaymentMethodHandler } from './braintree-payment-method'; +import { braintreePaymentMethodHandler } from './braintree.handler'; export type PaymentMethodArgsHash = ConfigArgValues;