Skip to content
This repository has been archived by the owner on Mar 22, 2023. It is now read-only.

Commit

Permalink
feat: Add Paypal components (#57)
Browse files Browse the repository at this point in the history
* Add PayPal elements

* Update readme to include new HOCs

* Bump version number
  • Loading branch information
Weetbix authored Feb 16, 2022
1 parent 2131f00 commit 5c91af2
Show file tree
Hide file tree
Showing 15 changed files with 278 additions and 21 deletions.
49 changes: 37 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,30 @@ Supported: React 14, 15, 16 (latest)
This package is a wrapper for [FramePay](https://rebilly.github.io/framepay-docs/) offering out-of-the-box support for Redux and other common React features.

## Table of Contents
- [FramePay documentation](#framepay-documentation)
- [Demos](#demos)
- [Installation](#installation)
- [Getting started](#getting-started)
- [The FramePay context (`FramePayProvider`)](#the-framepay-context-framepayprovider)
- [Setting up your payment form](#setting-up-your-payment-form)
- [Provided props](#provided-props)
- [framepay-react](#framepay-react)
- [Table of Contents](#table-of-contents)
- [FramePay documentation](#framepay-documentation)
- [Demos](#demos)
- [Installation](#installation)
- [Getting started](#getting-started)
- [The FramePay context (`FramePayProvider`)](#the-framepay-context-framepayprovider)
- [Setting up your payment form](#setting-up-your-payment-form)
- [WARNING](#warning)
- [withFramePay (All props)](#withframepay-all-props)
- [withFramePayCardComponent (Card props)](#withframepaycardcomponent-card-props)
- [withFramePayBankComponent (Bank props)](#withframepaybankcomponent-bank-props)
- [withFramePayApplePayComponent (Apple Pay props)](#withframepayapplepaycomponent-apple-pay-props)
- [withFramePayGooglePayComponent (Google Pay props)](#withframepaygooglepaycomponent-google-pay-props)
- [withFramePayPaypalComponent (Paypal props)](#withframepaypaypalcomponent-paypal-props)
- [With FramePay (`withFramePay`) HOC](#with-framepay-withframepay-hoc)
- [Card elements (`withFramePayCardComponent`) HOC](#card-elements-withframepaycardcomponent-hoc)
- [Bank elements (`withFramePayBankComponent`) HOC](#bank-elements-withframepaybankcomponent-hoc)
- [Advanced options](#advanced-options)
- [Initialize settings](#initialization-settings)
- [Create Token params](#create-token-parameters)
- [Troubleshooting](#troubleshooting)
- [Advanced options](#advanced-options)
- [Initialization settings](#initialization-settings)
- [Create Token Parameters](#create-token-parameters)
- [Troubleshooting](#troubleshooting)
- [Incorrect](#incorrect)
- [Correct](#correct)

### FramePay documentation
For more information on FramePay see its [official documentation](https://rebilly.github.io/framepay-docs/) or [repository](https://github.com/Rebilly/framepay-docs).
Expand Down Expand Up @@ -97,6 +107,9 @@ The react lifecycle methods already implemented in the library.
- `CardCvvElement`
- `CardExpiryElement`
- `CardNumberElement`
- `ApplePayElement`
- `GooglePayElement`
- `PaypalElement`

###### withFramePayCardComponent (Card props)
- Rebilly
Expand All @@ -111,12 +124,24 @@ The react lifecycle methods already implemented in the library.
- `BankAccountTypeElement`
- `BankRoutingNumberElement`

###### withFramePayApplePayComponent (Apple Pay props)
- Rebilly
- `ApplePayElement`

###### withFramePayGooglePayComponent (Google Pay props)
- Rebilly
- `GooglePayElement`

###### withFramePayPaypalComponent (Paypal props)
- Rebilly
- `PaypalElement`

##### With FramePay (`withFramePay`) HOC
This simple FramePay HOC is used to provide the `Rebilly` API in your component. It is most commonly used in combination with multiple payment methods.

- [Payment cards and ACH (CodeSandbox)](https://codesandbox.io/s/z2q2lx9ry4?module=/src/elements/MultiplePaymentMethods.js)
- [Payment cards and ACH Short version (CodeSandbox)](https://codesandbox.io/s/z2q2lx9ry4?module=/src/elements/MultiplePaymentMethodsShort.js)
- [PayPal and Bitcoin (CodeSandbox)](https://codesandbox.io/s/z2q2lx9ry4?module=/src/elements/OtherPaymentMethods.js)
- [Alternative methods (Bitcoin) (CodeSandbox)](https://codesandbox.io/s/z2q2lx9ry4?module=/src/elements/OtherPaymentMethods.js)

##### Card elements (`withFramePayCardComponent`) HOC

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rebilly/framepay-react",
"version": "1.3.0",
"version": "1.4.0",
"description": "A React wrapper for Rebilly's FramePay offering out-of-the-box support for Redux and other common React features",
"main": "build/index.js",
"author": "Rebilly",
Expand Down
8 changes: 6 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
withFramePayBankComponent,
withFramePayCardComponent,
withFramePayGooglePayComponent,
withFramePayIBANComponent
withFramePayIBANComponent,
withFramePayPaypalComponent
} from './lib/components/injector';

import FramePayProvider from './lib/components/provider';
Expand All @@ -17,7 +18,8 @@ import {
FramePayCardProps,
FramePayComponentProps,
FramePayGooglePayProps,
FramePayIBANProps
FramePayIBANProps,
FramePayPaypalProps
} from '../types/injector';

export {
Expand All @@ -29,10 +31,12 @@ export {
withFramePayIBANComponent,
withFramePayApplePayComponent,
withFramePayGooglePayComponent,
withFramePayPaypalComponent,
FramePayComponentProps,
FramePayCardProps,
FramePayBankProps,
FramePayIBANProps,
FramePayApplePayProps,
FramePayGooglePayProps,
FramePayPaypalProps
};
51 changes: 51 additions & 0 deletions src/lib/components/elements/paypal-element.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as React from 'react';
import FramePayError from '../../framepay-error';
import BaseElement from './base-element';

export default class PaypalElement extends BaseElement<
PaypalProps,
PaypalState
> {
setupElement() {
const { Rebilly, onTokenReady } = this.props;

const makeElement = () => {
// elementNode already checked in BaseElement.handleSetupElement
// just ts checks fix
if (!this.elementNode) {
throw FramePayError({
code: FramePayError.codes.elementMountError,
details: `PaypalElement invalid elementNode`
});
}

try {
return Rebilly.paypal.mount(this.elementNode);
} catch (e) {
throw FramePayError({
code: FramePayError.codes.elementMountError,
details: `PaypalElement error in remote api call`,
trace: e
});
}
};

const element = makeElement();

try {
Rebilly.on('token-ready', (token: string) => {
if (onTokenReady) {
onTokenReady(token);
}
});

this.setState({ element });
} catch (e) {
throw FramePayError({
code: FramePayError.codes.elementMountError,
details: `PaypalElement events binding error`,
trace: e
});
}
}
}
58 changes: 56 additions & 2 deletions src/lib/components/injector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ import BankElementComponent from './elements/bank-element';
import CardElementComponent from './elements/card-element';
import GooglePayElementComponent from './elements/googlepay-element';
import IBANElementComponent from './elements/iban-element';
import PaypalElementComponent from './elements/paypal-element';

import {
FramePayApplePayProps,
FramePayBankProps,
FramePayCardProps,
FramePayComponentProps,
FramePayGooglePayProps,
FramePayIBANProps
FramePayIBANProps,
FramePayPaypalProps
} from '../../../types/injector';

const makeRebillyProps = (data: FramePayContext): RebillyProps =>
Expand Down Expand Up @@ -230,6 +232,25 @@ const elementsFabric = (type: PaymentElements): object => {
};
}

if (type === 'paypal') {
/**
* Paypal
*/

const PaypalElement = Hoc(
'PaypalElement',
PaypalElementComponent,
(data: FramePayContext) =>
({
Rebilly: makeRebillyProps(data)
} as PaypalProps)
);

return {
PaypalElement
};
}

/**
* Throw the error by default.
*/
Expand All @@ -248,7 +269,8 @@ export function withFramePay<OriginalProps extends object>(
...elementsFabric('bankAccount'),
...elementsFabric('iban'),
...elementsFabric('applePay'),
...elementsFabric('googlePay')
...elementsFabric('googlePay'),
...elementsFabric('paypal')
};
return class extends React.Component<
OriginalProps & FramePayComponentProps,
Expand Down Expand Up @@ -439,3 +461,35 @@ export function withFramePayGooglePayComponent<OriginalProps extends object>(
}
};
}

export function withFramePayPaypalComponent<OriginalProps extends object>(
WrappedComponent: React.ComponentType<OriginalProps & FramePayPaypalProps>
) {
const elements = elementsFabric('paypal');
return class extends React.Component<
OriginalProps & FramePayPaypalProps,
{}
> {
static readonly displayName = `withFramePayPaypalComponent${name}(${WrappedComponent.displayName ||
WrappedComponent.name ||
'Component'})`;

render() {
return (
<ContextConsumer>
{(data: FramePayContext) => {
return (
<WrappedComponent
{...{
...this.props,
...elements,
Rebilly: makeRebillyProps(data)
}}
/>
);
}}
</ContextConsumer>
);
}
};
}
3 changes: 2 additions & 1 deletion test/e2e/fixtures/nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ setTimeout(() => {
'checkout-combined',
'google-pay',
'iban',
'multiple-methods'
'multiple-methods',
'paypal',
]
.forEach(route => {
node.innerHTML += `<li><a href="/${route}.html">${route}</a></li>`;
Expand Down
15 changes: 15 additions & 0 deletions test/e2e/fixtures/paypal.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8" />
<title>Test Paypal</title>
</head>

<body>
<div id="app"></div>
<script src="paypal.js"></script>
<script src="nav.js"></script>
</body>

</html>
64 changes: 64 additions & 0 deletions test/e2e/fixtures/paypal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

import { FramePayProvider, withFramePayPaypalComponent } from '../../../build';
import { ReactVersion } from './util';
import './style.css';

const params = {
publishableKey: 'pk_sandbox_S95ATjj4hXZs-T9QpZq1ENl2tDSrUkCGv98utc9',
organizationId: '5977150c-1c97-4dd4-9860-6bb2bab070b4',
websiteId: 'demo.com',
transactionData: {
amount: 10,
currency: 'USD',
},
};

class PaypalElementComponent extends Component {

constructor(props) {
super(props);
this.state = {
token: {
error: null,
data: null
}
};
}

render() {
return (<div>
<h2>{this.props.title}</h2>
<h3>FramePay version: {this.props.Rebilly.version}</h3>
<div className="flex-wrapper">
<div className="example-2">
<this.props.PaypalElement />
</div>
</div>
</div>);
}
}

const PaypalElement = withFramePayPaypalComponent(PaypalElementComponent);

class App extends Component {

render() {
return (<FramePayProvider injectStyle
{...params}
onReady={() => {
console.log('FramePayProvider.onReady');
}}
onError={(err) => {
console.log('FramePayProvider.onError', err);
}}>
<div>
{ReactVersion()}
<PaypalElement />
</div>
</FramePayProvider>);
}
}

ReactDOM.render(<App/>, document.getElementById('app'));
3 changes: 2 additions & 1 deletion test/unit/specs/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const exportKeys: ReadonlyArray<string> = [
'withFramePayCardComponent',
'withFramePayBankComponent',
'withFramePayGooglePayComponent',
'withFramePayIBANComponent'
'withFramePayIBANComponent',
'withFramePayPaypalComponent'
].sort();

describe('lib/index', () => {
Expand Down
10 changes: 10 additions & 0 deletions types/elements.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ interface GooglePayProps extends RebillyProps {
readonly onTokenReady?: (data: string) => void;
}

interface PaypalProps extends RebillyProps {
readonly Rebilly: RebillyProps;
readonly id?: string;
readonly onTokenReady?: (data: string) => void;
}

interface BankState extends PaymentComponentState {
readonly element: PaymentElement | null;
}
Expand All @@ -64,3 +70,7 @@ interface ApplePayState extends PaymentComponentState {
interface GooglePayState extends PaymentComponentState {
readonly element: PaymentElement | null;
}

interface PaypalState extends PaymentComponentState {
readonly element: PaymentElement | null;
}
Loading

0 comments on commit 5c91af2

Please sign in to comment.