npm package: @rebilly/framepay-vue
Description: Official Vue wrapper for Rebilly FramePay
Author: Rebilly
Latest version: 12.92.1

# framepay-vue

> Vue components for FramePay.js

Supported: 
- framepay-vue < 3.0.0 supports Vue 2.4+
- framepay-vue >= 3.0.0 supports Vue 3

This is the repo for the official Vue.js wrapper for Rebilly's [FramePay](https://www.rebilly.com/docs/dev-docs/framepay/). This package provides a flexible set of methods and components to allow drop-in support of FramePay in any Vue project.

## Table of Contents
- [framepay-vue](#framepay-vue)
  - [Table of Contents](#table-of-contents)
  - [FramePay Documentation](#framepay-documentation)
  - [Demos](#demos)
  - [Installation](#installation)
  - [Getting Started](#getting-started)
    - [Initialization](#initialization)
      - [At startup](#at-startup)
      - [On a component (rebilly-form, rebilly-card etc)](#on-a-component-rebilly-form-rebilly-card-etc)
      - [Lazy loading Framepay files](#lazy-loading-framepay-files)
    - [Usage](#usage)
      - [Google Pay and Apple Pay](#google-pay-and-apple-pay)
      - [With rebilly-form](#with-rebilly-form)
      - [With rebilly-form and custom submit logic](#with-rebilly-form-and-custom-submit-logic)
      - [With rebilly-token](#with-rebilly-token)
      - [Handle token manually](#handle-token-manually)
  - [Advanced Options](#advanced-options)
    - [Multiple Payment Methods](#multiple-payment-methods)
      - [v-if](#v-if)
      - [v-show](#v-show)
    - [Styling](#styling)
      - [Built in Styling](#built-in-styling)
      - [Custom Styling](#custom-styling)
    - [Events](#events)
      - [`rebilly-form`](#rebilly-form)
      - [on payment method components](#on-payment-method-components)
    - [Validation](#validation)
    - [Element IDs](#element-ids)
  - [Available Components and Methods](#available-components-and-methods)
    - [Methods](#methods)
      - [`createToken` Proxy Method](#createtoken-proxy-method)
      - [The `Rebilly` Object](#the-rebilly-object)
    - [Components](#components)
      - [`RebillyForm`](#rebillyform)
      - [`RebillyToken`](#rebillytoken)
      - [Payment Method Components](#payment-method-components)
        - [Combined Credit Card field](#combined-credit-card-field)
        - [Separate Credit Card fields](#separate-credit-card-fields)
        - [Separate Bank Account fields](#separate-bank-account-fields)
        - [IBAN (International Bank Account Number) field](#iban-international-bank-account-number-field)
        - [Props](#props)
  - [Further Reading](#further-reading)

## FramePay Documentation

For more information on FramePay see its [official documentation](https://www.rebilly.com/docs/developer-docs/framepay/).

## Demos
- [Basic card example](https://codesandbox.io/s/framepay-vue-basic-card-example-ydr7s)


## Installation
**Step 1:**

Install using [Yarn](https://yarnpkg.com/en/):
```
yarn add @rebilly/framepay-vue
```

Or using NPM:
```
npm install @rebilly/framepay-vue --save
```

**Step 2:**
Add the plugin to Vue:

```javascript
// main.js
import FramePay from '@rebilly/framepay-vue';

app.use(FramePay);
```
`app.use()` also accepts an optional argument for initialization options. See [Initialization](#initialization) below.

## Getting Started

### Initialization

Initialization can be done at startup, or directly on a payment component. To initialize `FramePay` you will need a publishable key from [Rebilly](https://app.rebilly.com/api-keys/add). We recommend starting with a sandbox key.

See here for all initialization options: https://www.rebilly.com/docs/dev-docs/framepay-configuration-reference

#### At startup

```javascript
//main.js
import FramePay from '@rebilly/framepay-vue';

const configuration = {
    publishableKey: 'pk_sandbox_1234567890',
};
app.use(FramePay, configuration);
```

#### On a component (rebilly-form, rebilly-card etc)

Add the `publishableKey` on only the first component in the template.

```html
<rebilly-form :configuration="{ publishableKey: 'pk_sandbox_1234567890' }">
	<input data-rebilly="firstName">
	<input data-rebilly="lastName">
	<rebilly-card></rebilly-card>
</rebilly-form> 
```

*NOTE:* Do not include the `publishableKey` on a component if you have already passed it via the config object when calling `app.use(Framepay, config)`.

#### Lazy loading Framepay files

The Framepay script files will be loaded as soon as `app.use(Framepay)` is called. This does not necessarily need to be done when the app loads, and can instead be done inside the Vue component which actually uses Framepay. In the following example, the Framepay script will not be fetched until the `created()` hook is called. 

The script will only be loaded the first time `created()` is called, so you can safely call `created()` multiple times without worrying about duplicates.

```html
<template>
    <rebilly-form>
        <input data-rebilly="firstName">
        <input data-rebilly="lastName">
        <rebilly-card></rebilly-card>
    </rebilly-form> 
</template>

<script>
    import FramePay, {
        RebillyForm,
        RebillyCard,
    } from '@rebilly/framepay-vue';

    export default {
        components: {
            RebillyForm,
            RebillyCard,
        },
        created() {
            const config = {
                publishableKey: 'pk_sandbox_1234567890',
                // etc
            };
            app.use(FramePay, config);
        },
    };
</script>
```

### Usage

`framepay-vue` offers three sets of payment method components:

- `RebillyCard` automatically mounts the combined credit card payment method
- `RebillyCardCvv`, `RebillycardExpiration`, and `RebillyCardNumber` mount three separate components for collecting credit info
- `RebillyBankAccountNumber`, `RebillyBankAccountType`, and `RebillyBankRoutingNumber` mount the `ach` (bank account) payment method
- `RebillyGooglePay` and `RebillyApplePay` mount Google Pay and Apple Pay respectively. These two methods are different from the rest, as they require additional inputs and emit the payment token with a separate event.

Two more components are also offered for convenience: 

- `RebillyForm` wraps a regular HTML `form`. It automatically detects payment method components and performs token creation/injection when the form is submitted. It is the simplest way to get started with `framepay-vue`.
- `RebillyToken` can be added to any standard form, and when present will automatically receive the token created by `createToken()`. You do not need to use `RebillyToken` if you are using `RebillyForm` already. 

#### Google Pay and Apple Pay
`RebillyGooglePay` and `RebillyApplePay` are used like so:
```html
<rebilly-apple-pay
    @token-ready="handleToken"
/>
```

whereas:
* `@token-ready` is an event emitted once the payment token has been generated and its payload contains the token object.

#### With rebilly-form

The default behavior of `RebillyForm` is to intercept the regular submit event, execute `Rebilly.createToken()`, and then submit the form with the newly created token attached. Any inputs that include `data-rebilly` attribute with the appropriate value will be sent to `Rebilly.createToken()`.

```html
<rebilly-form @error="" @token-ready="" :extraData="{}">
	<input data-rebilly="firstName">
	<input data-rebilly="lastName">
	<rebilly-card></rebilly-card>
</rebilly-form>

<script>
import { RebillyForm, RebillyCard } from '@rebilly/framepay-vue';

export default {
    components: {
        RebillyCard,
        RebillyForm,
    },
};
</script>
```
Any DOM attributes you attach to `RebillyForm` will automatically be passed to the base `form` element.

`@error` will expose the error message returned if the `Rebilly.createToken()` request failed. You can inspect `error.message` and `error.code`.

`@token-ready` will expose the token object, if a Google/Apple Pay element was mounted in the form.

See here for all arguments to `extraData`: https://www.rebilly.com/docs/dev-docs/framepay-global-reference#extra-data.

See here for list of `data-rebilly` types: https://www.rebilly.com/docs/dev-docs/form-setup.


#### With rebilly-form and custom submit logic

If you want to perform your own logic after token creation but before form submission, attach a listener to `@submit` on `RebillyForm`. If `RebillyForm` detects the listener on `@submit`, it will not submit the form automatically but instead emit it alongside the newly created token.

```html
<rebilly-form @submit="submitHandler" @error="" :extraData="{}">
	<input data-rebilly="firstName">
	<input data-rebilly="lastName">
	<rebilly-card></rebilly-card>
</rebilly-form>

<script>
import { RebillyForm, RebillyCard } from '@rebilly/framepay-vue';

export default {
    components: {
        RebillyCard,
        RebillyForm,
    },
    methods: {
        submitHandler(token, form) {
     	    // do something with token
     	    form.submit()
        },
    },
};
</script>
```

#### With rebilly-token

If you prefer to call `createToken()` manually, use the example below. Note that you don't want to use the `Framepay` object directly, but rather the proxied `createToken` method provided by `framepay-vue`. This method returns a promise that waits for the FramePay script to be loaded before calling `Rebilly.createToken()`. Using the pattern below will help eliminate errors due to race conditions. 

```html
<form @submit="submitHandler">
	<input data-rebilly="firstName">
	<input data-rebilly="lastName">
	<rebilly-card></rebilly-card>
	<rebilly-token></rebilly-token>
</form>

<script>
import { createToken, RebillyCard, RebillyToken } from '@rebilly/framepay-vue';

export default {
    methods: {
        submitHandler(event) {
            event.preventDefault();
            const form = event.target;
            const extraData = { } // some stuff
            createToken(form, extraData))
                .then((token) => {
                    // the token is already added to the form via RebillyToken
       	            form.submit();
                })
                .catch((error) => {
                    // see error.code and error.message
                    console.log(error);
                });
        },
    },
};
</script>
```

#### Handle token manually

The token can also be handled entirely manually. As above, be sure to call the imported `createToken()` method instead of the global `Framepay` object. This approach offers the most flexibility, but still removes the need for you to handle initialization, mounting and destruction of payment method elements. 

```html
<form @submit="submitHandler">
	<input data-rebilly="firstName">
	<input data-rebilly="lastName">
	<rebilly-card></rebilly-card>
</form>

<script>
    import { createToken, RebillyCard } from '@rebilly/framepay-vue';

	export default {
	  methods: {
	    submitHandler(event) {
	        event.preventDefault();
	        const form = event.target;
	        const extraData = { } // some stuff
	        createToken(form, extraData))
	            .then((token) => {
                    // you must dynamically add the token id to the form
	        	    form.submit();
	            })
	            .catch((error) => {
	                // see error.code and error.message
	                console.log(error);
	            });
	    },
	  },
	};
</script>
```

## Advanced Options

### Multiple Payment Methods

#### v-if

Framepay will automatically use the first payment method it detects in the form. Multiple payment methods can be handled like this:

```html
<rebilly-form @error="" :extraData="{}">
	<input data-rebilly="firstName">
	<input data-rebilly="lastName">
	<rebilly-card v-if="paymentMethod === 'payment-card'"></rebilly-card>
	<div v-if="paymentMethod=== 'ach'">
		<rebilly-bank-account-type></rebilly-bank-account-type>
		<rebilly-bank-account-number></rebilly-bank-account-number>
		<rebilly-bank-routing-number></rebilly-bank-routing-number>
	</div>
</rebilly-form>

<button @click="paymentMethod = 'payment-card'">PaymentCard</button>
<button @click="paymentMethod = 'ach'">Bank</button>
```


#### v-show

`v-if` causes the elements to be destroyed and recycled, meaning payment method fields will be re-mounted each time `method` changes in the above example. 

It is possible to use `v-show` instead, which will allow you to preserve the user's input when they switch payment methods in your UI. However, you must specify which `method` FramePay should use to create the token, by passing it to `extraData`. 

```html
<rebilly-form @error="" :extraData="{ method: paymentMethod }">
	<input data-rebilly="firstName">
	<input data-rebilly="lastName">
	<rebilly-card v-show="paymentMethod === 'payment-card'"></rebilly-card>
	<div v-show="paymentMethod=== 'ach'">
		<rebilly-bank-account-type></rebilly-bank-account-type>
		<rebilly-bank-account-number></rebilly-bank-account-number>
		<rebilly-bank-routing-number></rebilly-bank-routing-number>
	</div>
</rebilly-form>

<button @click="paymentMethod = 'payment-card'">PaymentCard</button>
<button @click="paymentMethod = 'ach'">Bank</button>
```

### Events

#### `rebilly-form`

As covered above, `rebilly-form` emits `error` and `submit` events. 

#### on payment method components

Payment method components emit the following events: `on`, `ready`, `focus` and `change`.

See details: https://www.rebilly.com/docs/dev-docs/element

### Validation

 Validation errors on payment method components can be detected by attaching a listener to `change`. 

```html
<rebilly-form @error="" :extraData="{}">
	<input data-rebilly="firstName">
	<input data-rebilly="lastName">
	<rebilly-card @change="changeHandler"></rebilly-card>
</rebilly-form>

<script>
	export default {
	    methods: {
	        changeHandler(e) {
	    	    // e.valid, e.source, e.error
	        },
	    },
	};
</script>
```

See details: https://www.rebilly.com/docs/dev-docs/element

### Element IDs

By default, each payment method component's ID is the component name with `-mount` appended, eg: `rebilly-card-mount`

This can be changed by simply passing `id` as a prop to `<rebilly-card>`, `<rebilly-bank-account-number>` etc.

Because this will only change the ID of the element you are mounting Framepay to, it will not interfere any of the default or custom Framepay styling.

## Available Components and Methods

### Methods

#### `createToken` Proxy Method

`framepay-vue` exports a single method: `createToken()`. This method simply wraps the Framepay method `Rebilly.createToken()` in a promise to ensure that the Framepay script has loaded and the object is available. Be sure to import `createToken` from `@rebilly/framepay-vue` instead of using `Rebilly.createToken()`, otherwise you may run into errors due to race conditions. 

Again, you don't need to use `createToken` at all if you choose to use the `RebillyForm` component.

#### The `Framepay` Object

As mentioned above, Framepay will expose the `Framepay` object in the global namespace after it has loaded. We recommend that you never call the `Framepay` object directly, as `framepay-vue` is designed to either expose or abstract away all the methods you need to use Framepay.

For more information about the `Framepay` object, see: https://www.rebilly.com/docs/dev-docs/framepay-global-reference

### Components

#### `RebillyForm`

RebillyForm accepts the following props:

- `@submit`
- `@error`
- the `configuration` object for initialization
- `extraData` for passing additional information to `createToken()`
- any attributes from a standard HTML form will be passed properly

See: [Usage example](#with-rebilly-form)

#### `RebillyToken`

RebillyToken accepts no arguments. It simply adds a hidden `<input>` element to the form, with the property `data-rebilly="token"` set.

See: [Source code](./src/components/RebillyToken.vue) and [Usage example](#with-rebilly-token)

#### Payment Method Components

These components handle the mount/unmount lifecycle of a Framepay field, and can optionally be used for initialization. The available components are listed below.

##### Combined Credit Card field

- `RebillyCard` - mounts a combined payment card field for card number, CVV and expiration

##### Separate Credit Card fields

These elements must all be mounted in the same form in order to successfully create a token.

- `RebillyCardCvv` - mounts a CVV field
- `RebillycardExpiration` - mounts a credit card expiration field
- `RebillyCardNumber` - mounts a credit card number field

##### Separate Bank Account fields

These elements must all be mounted in the same form in order to successfully create a token.

- `RebillyBankAccountNumber` - mounts a bank account number field
- `RebillyBankAccountType` - mounts a set of inline buttons to select bank account type
- `RebillyBankRoutingNumber` - mounts a bank routing number field

##### IBAN (International Bank Account Number) field

- `RebillyIban` - mounts an IBAN field

##### Props

Payment method components all accept the same props:

- `id` for changing the ID of the element containing the mounted field
- `@ready`, `@change`, `@focus`, `@blur`
- the `configuration` object for initialization

## Further Reading

Rebilly API for Payment Tokens
https://rebilly.github.io/RebillyAPI/#tag/Payment-Tokens