# `@primer-io/checkout-vue`

Using the [Primer](https://primer.io) SDK for Vue 2.x, you can quickly and easily create a checkout page for your site to securely collect card information and offer a multitude of alternative payment methods to your customers through one simple integration.

This wrapper is based on [`@primer-io/checkout-web@1.2.0-beta.36`](https://www.npmjs.com/package/@primer-io/checkout-web/v/1.2.0-beta.36).

# Get Started!

Check out our guides on how to get started with Primer [here](https://primer.io/docs/guides/quick-start-guide).

This Vue wrapper renders Primer's [Universal Checkout](https://primer.io/docs/guides/checkout/#universal-checkout) using the configuration provided as props.

## Installation

With npm:

```
npm i -s @primer-io/checkout-vue
```

With yarn:

```
yarn add @primer-io/checkout-vue
```

## Example

```vue
<template>
  <div>
    <PrimerCheckout
      v-if="clientToken"
      :client-token="clientToken"
      :tokenize-success-status="tokenizeSuccessStatus"
      @tokenize-success="onTokenizeSuccess"
    />
  </div>
</template>

<script>
import {PrimerCheckout} from '@primer-io/checkout-vue'

export default {
  name: 'App',
  components: {PrimerCheckout},
  data() {
    return {
      clientToken: 'abcd-1234',
      tokenizeSuccessStatus: null
    }
  },

  methods: {
    async onTokenizeSuccess(tokenData) {
      this.tokenizeSuccessStatus = null
      try {
        await doSale(tokenData) // Call your server with the token to trigger the sale
      } catch (error) {
        this.tokenizeSuccessStatus = error // Display an error message
        return
      }
      this.tokenizeSuccessStatus = true // Finish the payment flow: you can now display a success message
    }
  }
}
</script>
```

## Handle tokenization

Once the payment method tokenization has been successfully achieved, the `onTokenizeSuccess` callback of the Universal Checkout is called. This function is expected to return a Promise to let you call your server with the token data. During this time, the Universal Checkout displays a loading indicator: resolve the Promise to stop the loading indicator, or reject it to show an error message.

This Vue wrapper let you resolve/reject the Promise using one of the following 4 different methods. Some of them are considered "anti-pattern" with Vue, but we are not here to judge what's a pattern or what is not, so choose the one that best fits your needs and architecture.

### Listen to `@tokenize-success` and use the props `tokenize-success-status`

This is the most Vue-like pattern, but also the most verbose. Use this pattern if you handle your API calls using an external state management system such as Vuex.

Listen to the event `tokenize-success`, and pass `tokenize-success-status` props to trigger a resolution (if `tokenize-success-status` is `true`) or rejection (if `tokenize-success-status` is an `Error`) of the Promise.

```vue
<template>
  <div class="app">
    <div class="checkout">
      <primer-checkout
        :client-token="clientToken"
        :tokenize-success-status="tokenizeSuccessStatus"
        @tokenize-success="onTokenizeSuccess"
      />
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      clientToken: 'abcd-1234,
    }
  },

  computed: {
    tokenizeSuccessStatus() {
      return this.$store.state.tokenizeSuccessStatus;
    }
  },

  methods: {
    onTokenizeSuccess(tokenData) {
      this.$store.dispatch('doSale', tokenData);
    },
  }
}
</script>
```

### Listen to `@tokenize-success` and use its `next` argument

Listen to the event `tokenize-success`. It will be called with the token data, and a callback function `next`. Call `next()` to resolve the Promise, or `next(error)` to reject it.

```vue
<template>
  <div class="app">
    <div class="checkout">
      <primer-checkout
        :client-token="clientToken"
        @tokenize-success="onTokenizeSuccess"
      />
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      clientToken: 'abcd-1234,
    }
  },

  methods: {
    async onTokenizeSuccess(tokenData, next) {
      try {
        await doSale(tokenData); // Call your server with the token
      } catch (e) {
        return next(e);
      }
      return next();
    },
  }
}
</script>
```

### Pass `onTokenizeSuccess` as a props

You can directly pass `onTokenizeSuccess` as a function props.

```vue
<template>
  <div class="app">
    <div class="checkout">
      <primer-checkout
        :client-token="clientToken"
        :tokenize-success="onTokenizeSuccess"
      />
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      clientToken: 'abcd-1234,
    }
  },

  methods: {
    async onTokenizeSuccess(tokenData) {
      await doSale(tokenData); // Call your server with the token
    },
  }
}
</script>
```

### Call `Checkout.resolveOnTokenizeSuccess(error?)`

This Vue wrapper also provide an imperative way of resolving the `onTokenizeSuccess` Promise. Call `resolveOnTokenizeSuccess(error?)` with `error` being `undefined` to resolve the Promise, or with `error` being of type `Error` to reject the Promise.

```vue
<template>
  <div class="app">
    <div class="checkout">
      <primer-checkout
        ref="checkout"
        :client-token="clientToken"
        @tokenize-success="onTokenizeSuccess"
      />
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      clientToken: 'abcd-1234,
    }
  },

  methods: {
    async onTokenizeSuccess(tokenData) {
      try {
        await doSale(tokenData);
      } catch (e) {
        return this.$refs.checkout.resolveOnTokenizeSuccess(e);
      }

      return this.$refs.checkout.resolveOnTokenizeSuccess();
    },
  }
}
</script>
```

# API Reference

## Props

| Props                     | Type                                         | Required | Description                                                                                |
| ------------------------- | -------------------------------------------- | -------- | ------------------------------------------------------------------------------------------ |
| `clientToken`             | `String`                                     | `true`   | Client Your server-generated client token                                                  |
| `thirdPartyScriptTimeout` | `Number`                                     | `false`  | Maximum time in milliseconds to wait for third party scripts to load [default=10000]       |
| `locale`                  | `String`                                     | `false`  | Override the locale. By default translations will be provided for the browser's locale.    |
| `customerId`              | `String`                                     | `false`  |                                                                                            |
| `countryCode`             | `String`                                     | `false`  | Your alpha2 country code. [required for Google Pay, Apple Pay and PayPal]                  |
| `purchaseInfo`            | `PurchaseInfo`                               | `false`  | Additional information about the purchase. [required for Google Pay, Apple Pay and PayPal] |
| `threeDSecure`            | `ThreeDSecureVerifyOptions`                  | `false`  | 3DS options. These must be provided if you want to perform SCA                             |
| `card`                    | `Card`                                       | `false`  |                                                                                            |
| `paypal`                  | `Object`                                     | `false`  |                                                                                            |
| `googlePay`               | `Object`                                     | `false`  |                                                                                            |
| `applePay`                | `Object`                                     | `false`  |                                                                                            |
| `directDebit`             | `Object`                                     | `false`  |                                                                                            |
| `submitButton`            | `Object`                                     | `false`  |                                                                                            |
| `tokenizeSuccess`         | `(token: PaymentMethodToken): Promise<void>` | `false`  | Function props used for `onTokenizeSuccess`                                                |
| `tokenizeSuccessStatus`   | `Boolean | Error`                            | `false`  | Status of `onTokenizeSuccess`                                                              |

```typescript
type PurchaseInfo {
  totalAmount: {
    value: number | string
    currency: string
  }
}
```

```typescript
type Transitions {
  // a number of milliseconds or specify different durations for 'enter' and 'exit'
  duration?: number | { enter: number, exit: number };
  // Callbacks for when a view is transitioning in or out
  onEntering?: (node: Node) => void;
  onEntered?: (node: Node) => void;
  onExiting?: (node: Node) => void;
  onExited?: (node: Node) => void;
};
```

```typescript
type PaymentMethodToken {
  // The token used to authorize transactions
  token: string;
  // The type of payment method which this token represents
  paymentMethodType: 'PAYMENT_CARD' | 'GOOGLE_PAY' | 'APPLE_PAY' | 'PAYPAL';
  // Additional data about the payment method
  paymentMethodData: object;
}
```

```TypeScript
type SubmitButton {
  visible?: boolean; // Set to false if you don't want to display the default submit button
}
```

## Event

| Event                            | Arguments                                       | Description                                                                                                                                                                                                                   |
| -------------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `loading`                        | `isLoading: Boolean`                            | Emitted with `true` while the checkout is being loaded, mounted and displayed. During this period, a loading indicator is displayed. Once the checkout is ready to be used, the `loading` event will be emitted with `false`. |
| `loading-error`                  | `error: Error`                                  | Emitted when an error if the checkout failed to load.                                                                                                                                                                         |
| `tokenize-start`                 |                                                 | Emitted when tokenization begins                                                                                                                                                                                              |
| `tokenize-success`               | `tokenData: PaymentMethodToken, next: Function` | Forwarded from `onTokenizeSuccess`. Use `next` to resolve or reject the Promise.                                                                                                                                              |
| `tokenize-error`                 | `message: string`                               | Emitted when tokenization fails. See the error message for more information                                                                                                                                                   |
| `three-d-secure-challenge-start` |                                                 | Emitted when the 3DS challenge starts                                                                                                                                                                                         |
| `three-d-secure-challenge-end`   |                                                 | Emitter when the 3DS challenge ends                                                                                                                                                                                           |

## Methods

| Method                                     | Description                                                                                                 |
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `isWaitingForOnTokenizeSuccess(): Boolean` | Return `true` if the wrapper is waiting for a resolution or rejection of the Promise of `onTokenizeSuccess` |
| `resolveOnTokenizeSuccess(error: Error?)`  | Resolve or reject the Promise of `onTokenizeSuccess`.                                                       |

## Data

| Data       | Description                       |
| ---------- | --------------------------------- |
| `primer`   | Instance of the `Primer` object.  |
| `checkout` | Instance of the `Checkout` object |
