# OdinPay JavaScript Elements

The JS elements library provides OdinPay customers the means to collect sensitive data from users within their web applications, without the risk of managing such data. Currently the only supported data collection is Bank Account and Credit Card information but this data set will grow over time.

- [Getting Started](#getting-started)
- [API Documentation](#api-documentation)
  - [Initializer](#initializer)
  - [Methods](#methods)
  - [Theme](#theme)
  - [Error Handling](#error-handling)
  - [Type Definitions](#type-definitions)
- [Demo](#demo)

---

<a name="getting-started"></a>

## Getting Started

To instantiate OdinPay JS elements follow these steps:

1. Generate a public token using the [Generate Token endpoint](https://documenter.getpostman.com/view/617088/2s93zCagN3#e6a7ff70-dbcb-425a-9158-2335c9753e98) and use the generated token to initialize the OdinPay JS elements library.

2. Define the HTML elements where the JS Elements will be rendered. Each one of these elements needs to have a user defined unique ID that will be used for mapping and injecting the JS elements into your form, for example:

```html
<div id="[user-defined-id-cardInfo]"></div>
<div id="[user-defined-id-postalcode]"></div>
<button id="[user-defined-id-button]">Save Payment Method</button>
```

3. Include the library script in the page directly via a script tag (CDN), or via dependencies:

```html
<script src="https://js.odinpay.net"></script>
```

```js
const OdinPay = require("@clubessentialholdings/js-elements");
// or
import OdinPay from "@clubessentialholdings/js-elements";
```

4. Then, add the following code to initialize the library. OdinPay will be defined as a global variable as well as accessible via `window.OdinPay`.

```javascript
// CDN
window.addEventListener("load", async () => {
	const odinPayElements = OdinPay("public-token", {
		theme,
		country
	});
});

// via import
const odinPayElements = OdinPay("public-token", {
	theme,
	country
});
```

5. Once the library has been initialized and the html elements haven defined, components can be rendered. Below is the example of how you’d render a credit card form with just the required fields:

```javascript
odinPayElements.createCreditCardForm({
	submitButton: {
		selector: "[user-defined-id-button]",
		callback: (result) => {
			//... your goes code here
		}
	},
	fields: {
		cardInformation: {
			selector: "[user-defined-id-cardInfo]",
			ariaLabel: "testLabel"
		},
		postalCode: {
			selector: "[user-defined-id-postalcode]",
			placeholder: "Postal Code",
			ariaLabel: "testLabel"
		}
	},
	onChangeValidation: (fieldInformation) => {
		handleValidation(fieldInformation, "cardWithPostalCode-errors");
	}
});
```

---

<a name="api-documentation"></a>

## API Documentation

<a name="initializer"></a>

### INITIALIZER

### `OdinPay(token, config)`

Initializes the OdinPay object

#### PARAMETERS:

| Name              | Type   | Attributes | Description                                                                      |
| :---------------- | :----- | :--------- | :------------------------------------------------------------------------------- |
| token             | string |            | Token generated by using the generate public token endpoint from the OdinPay API |
| [config](#config) | object | optional   | Configuration of the theme & country                                             |

---

<a name="methods"></a>

### METHODS

| Methods                                                               | Explanation                                                                                                                                                                                                                                                         |
| :-------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `createCardForm ({ submitButton, fields, onChangeValidation })`       | Renders a credit card form based on the desired configuration. The cardInformation and postalCode fields are required to be able to render a credit card form.                                                                                                      |
| `createBankAccountForm({ submitButton, fields, onChangeValidation })` | Defines the look and feel of the component(s) inputsRenders a bank account form based on the desired configuration. The accountNumber, bankAccountType, routingNumber and name (name on account) fields are required to be able to render a bank account card form. |

#### PARAMETERS:

| Property                              | Type     | attributes | Explanation                                                        |
| :------------------------------------ | :------- | :--------- | :----------------------------------------------------------------- |
| [submitButton](#submit-button)        | object   |            | Submit button configuration                                        |
| [fields](#fields-properties)          | object   |            | Defines the fields that will be rendered in the credit card form.  |
| [onChangeValidation](#error-handling) | function | optional   | If desired, you can access the field validation object using this. |

#### Card Example

```javascript
OdinPay.createCardForm({
	submitButton: {
		selector: "[user-defined-id-submitButton]",
		callback: (result) => {
			handleResponse(result);
		}
	},
	fields: {
		cardInformation: {
			selector: "[user-defined-id-cardInformation]",
			ariaLabel: "testLabel"
		},
		postalCode: {
			selector: "[user-defined-id-postalCode]",
			placeholder: "Postal Code",
			ariaLabel: "testLabel"
		}
	},
	onChangeValidation: (validation) => handleValidation(validation)
});
```

#### Bank Account Example

```javascript
OdinPay(token).createBankAccountForm({
	submitButton: {
		selector: "[user-defined-id-submitButton]",
		callback: (result) => {
			handleResponse(result);
		}
	},
	fields: {
		accountNumber: {
			selector: "[user-defined-id-accountNumber]",
			ariaLabel: "testLabel",
			placeholder: "Account Number"
		},
		routingNumber: {
			selector: "[user-defined-id-routingNumber]",
			placeholder: "Routing Number"
		},
		bankAccountType: {
			selector: "[user-defined-id-bankAccountType]"
		},
		name: {
			selector: "[user-defined-id-nameOnAccount]",
			placeholder: "Name"
		}
	},
	onChangeValidation: (validation) => handleValidation(validation)
});
```

---

<a name="config"></a>

### CONFIG

Is an optional property in OdinPay initialization, allowing additional configurations for theme and country

```json
{
	"theme": {},
	"country": "US"
}
```

| Property        | Type      | Attributes | Explanation                                             |
| :-------------- | :-------- | :--------- | :------------------------------------------------------ |
| [theme](#theme) | object    | optional   | Defines certain font-related styles and pseudo-elements |
| country         | "US","CA" | optional   | defaults to US, used for bank account fields            |

**Currently Supported Countries**

- US
- CA

---

<a name="theme"></a>

### THEME

An optional object to allow the user to define custom styles for background colors, padding, fonts and pseudo-elements. These will be applied through the theme object rather than through a CSS stylesheet.

Other styling for things such as borders to your container divs should be done in a CSS sheet.

Example theme object:

```json
{
	"fontFamily": "Fira Sans,Droid Sans",
	"fontSize": "16px",
	"::placeholder": {
		"color": "rgb(117, 117, 117)",
		"fontSize": "16px"
	}
}
```

**Allowed CSS Properties in the theme object**

- backgroundColor
- color
- fontFamily
- fontSize
- fontSmooth
- fontStyle
- fontVariant
- fontWeight
- lineHeight
- letterSpacing
- textAlign
- padding
- textDecoration
- textShadow
- textTransform

**Allowed pseudo-elements in the theme object**

- :hover
- :focus
- :read-only
- ::placeholder
- ::selection
- :disabled

---

<a name="error-handling"><a/>

### ERROR HANDLING

There are two types of error handling: on change and on submit. Both return the same format of error object to provide a more uniform response for error handling.

### On Change

An optional function in the configuration object when using createCardForm or createBankForm. Used to handle field validation errors.

It will return an [error object](#error-object) during blur and change events.

Please see the static folder for a fully functional example of onChange validation.

```javascript

const handleValidation = (fieldInformation) => {
    const {selector, errorCode, fieldName} = fieldInformation;
    //handle validation errors here
}

await op.createCardForm({
  submitButton: {...},
  fields: {...},
  onChangeValidation: (fieldInformation) => {
    handleValidation(fieldInformation);
  }
})
```

### On Submit

This will only trigger when the user clicks the submit button. It returns the [submit response](#submit-response).

If there are errors, it will return an array of the same [error object](#error-object) as the onChange validation. However, onSubmit can also return backend errors unlike the onChange validation.

Please see static folder for fully functional examples of onSubmit error handling.

```javascript
await op.createCardForm({
    onChangeValidation: {...},
    fields: {...},
    submitButton: {
        selector: "bankOnly-submit-CA",
        callback: (result) => {
            result?.errors?.forEach((fieldInformation) => {
                handleValidation(fieldInformation);
            });
        }
    }
});
```

---

<a name="type-definitions"></a>

### TYPE DEFINITIONS

<a name="submit-button"></a>

### Submit Button

The configuration object for your form's submit button.

| Parameter | Type     | Attributes | Explanation                              |
| :-------- | :------- | :--------- | :--------------------------------------- |
| selector  | string   | required   | the id of the HTML button element        |
| callback  | function | required   | callback to handle response from OdinPay |

<a name="field"></a>

### Field

Configuration object for an input field.

#### PROPERTIES:

| Parameter    | Type   | Attributes                            | Explanation                                  |
| :----------- | :----- | :------------------------------------ | :------------------------------------------- |
| selector     | string |                                       | User defined id of the HTML element          |
| ariaLabel    | string | optional                              | Aria label for the input                     |
| placeholder  | string | optional - n/a for card field         | Placeholder for input                        |
| initialValue | string | optional - n/a for card & bank fields | Pass initial values to the inputs if desired |

<a name="fields-properties"></a>

### Fields Properties

These are the properties that are allowed in the fields list

##### PROPERTIES:

| Name            | Type             | Attributes        |
| :-------------- | :--------------- | :---------------- |
| cardInformation | [object](#field) | required for card |
| accountNumber   | [object](#field) | required for bank |
| routingNumber   | [object](#field) | required for bank |
| bankAccountType | [object](#field) | required for bank |
| postalCode      | [object](#field) | required for card |
| name            | [object](#field) | optional for bank |
| addressLine1    | [object](#field) | optional          |
| addressLine2    | [object](#field) | optional          |
| city            | [object](#field) | optional          |
| state           | [object](#field) | optional          |
| country         | [object](#field) | optional          |
| emailAddress    | [object](#field) | optional          |
| phoneNumber     | [object](#field) | optional          |

<a name="#submit-response"></a>

### Submit Response

returned from the submit button's callback.

| Name          | Type                              | Attributes                                 |
| :------------ | :-------------------------------- | :----------------------------------------- |
| success       | Boolean                           |                                            |
| errors        | [Error[]](#error-object)          | an array of error objects, if errors exist |
| paymentMethod | [Payment Method](#payment-method) | on success, you will receive this object   |

<a name="#payment-method"></a>

### Payment Method

The payment method object from the submit callback.

| Name               | Type                                           | Attributes                                   |
| :----------------- | :--------------------------------------------- | :------------------------------------------- |
| id                 | String                                         |                                              |
| createdAt          | String                                         |                                              |
| updatedAt          | String                                         |                                              |
| type               | "CREDIT_CARD", "DEBIT_CARD", or "BANK_ACCOUNT" |                                              |
| billingInformation | Object                                         | all billing information supplied by the user |
| accountNumber      | String                                         | a masked version of the account number       |
| expirationDate     | String                                         | card only                                    |
| cardBrand          | String                                         | card only                                    |
| bankAccountType    | "CHECKING" or "SAVINGS"                        | bank only                                    |
| accountNumber      | String                                         | bank only                                    |
| routingNumber      | String                                         | US bank only                                 |
| transitNumber      | String                                         | CA bank only                                 |
| institutionNumber  | String                                         | CA bank only                                 |
| country            | String                                         | bank only - 2 digit country code             |

<a name="#error-object"></a>

### Error Object

Returned from both the onChange and onSubmit validation.

| Name      | Type                      | Attributes                                           |
| :-------- | :------------------------ | :--------------------------------------------------- |
| selector  | String                    | the provided selector for the field's container div  |
| errorCode | [ErrorCode](#error-codes) | a code describing the error                          |
| fieldName | String                    | name of the field                                    |
| type      | [ErrorType](#error-types) | either field validation or backend                   |
| isValid   | Boolean                   | will only return true onChange if the field is valid |

<a name="error-types"></a>

#### Error types:

| Error Code       | Description                     |
| :--------------- | :------------------------------ |
| FIELD_VALIDATION | an error from schema validation |
| BACKEND          | an error from the Odin backend  |

<a name="error-codes"></a>

#### ERROR CODES:

| Error Code               | Description                            |
| :----------------------- | :------------------------------------- |
| INVALID                  | generic invalidation against a schema  |
| INVALID_CARD_INFORMATION | invalid card field                     |
| INVALID_BANK_INFORMATION | invalid bank field                     |
| MAX_LENGTH_EXCEEDED      | max length of schema has been exceeded |
| REQUIRED                 | field is blank but required            |
| UNAUTHORIZED             | API Unauthorized error                 |
| TOKENIZATION_FAILED      | API failure for tokenization           |
| VALIDATION_ERROR         | API validation error                   |

---

<a name="demo"></a>

## Demo

Try out different CodePen examples for both card and bank forms:

https://codepen.io/collection/vOYpPa
