Skip to content

Commit ecd7033

Browse files
committed
version 1.0.0
1 parent c2a2a49 commit ecd7033

28 files changed

+12312
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ build
44
node_modules
55

66
npm-debug.log
7+
.env

.npmignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.babelrc
2+
demo
3+
Makefile
4+
webpack.config.js
5+
.env

Makefile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
BIN = ./node_modules/.bin
2+
WEBPACK = $(BIN)/webpack
3+
SERVER = $(BIN)/webpack-dev-server --inline --hot --port 8040
4+
5+
server: build
6+
ifdef RECURLY_JS_CERT
7+
@$(SERVER) --https --cert $(RECURLY_JS_CERT) --key $(RECURLY_JS_KEY) --display-error-details
8+
else
9+
@$(SERVER) --https
10+
endif
11+
12+
build: build/demo.js
13+
build/demo.js: demo lib node_modules
14+
@$(WEBPACK) --display-reasons --display-chunks
15+
16+
test:
17+
@npm test
18+
19+
publish: lib clean node_modules
20+
@npm publish --access public
21+
22+
node_modules: package.json
23+
@npm install
24+
25+
clean:
26+
@rm -rf node_modules build
27+
28+
.PHONY: clean publish server test

README.md

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,180 @@
1-
# react-recurly
1+
# react-recurly
2+
3+
*React components for Recurly.js*
4+
5+
## Demo
6+
7+
See the [demo](demo) directory.
8+
9+
These examples provide a quick start to using `react-recurly`. The [card-element-demo](demo/demos/card-element-demo.js) is a great place to begin seeing how you might structure your own payment form components.
10+
11+
1. `make demo`
12+
2. [https://localhost:8040](https://localhost:8040)
13+
14+
## Getting Started
15+
16+
If you haven't yet, please review the [Recurly.js documentation](https://developers.recurly.com/reference/recurly-js/). This will give you a solid understanding of the total capabilities of the library before we begin implementing some of its features in React. Now let's begin!
17+
18+
First, install this package
19+
20+
```bash
21+
npm install @recurly/react-recurly
22+
```
23+
24+
Then, include recurly.js in your application via our CDN.
25+
26+
```html
27+
<script src="https://js.recurly.com/v4/recurly.js"></script>
28+
<!-- optional: include recurly.css -->
29+
<link rel="stylesheet" href="https://js.recurly.com/v4/recurly.css">
30+
```
31+
32+
From here, you will structure your React application's checkout components in the following manner. We will go into more detail on each component below.
33+
34+
## Simplest Implementation
35+
36+
```jsx
37+
import React from 'react';
38+
import { CardElement, Elements, RecurlyProvider, useRecurly } from 'react-recurly';
39+
import { render } from 'react-dom';
40+
41+
const App = () => {
42+
return (
43+
<RecurlyProvider publicKey="ewr1-abcdefghijklmno">
44+
<Elements>
45+
<CardForm />
46+
</Elements>
47+
</RecurlyProvider>
48+
);
49+
};
50+
51+
function CardForm (props) {
52+
const recurly = useRecurly();
53+
let form = React.createRef();
54+
55+
const handleSubmit = event => {
56+
if (event.preventDefault) event.preventDefault();
57+
recurly.token(form.current, (err, token) => {
58+
if (err) console.log('[error]', err);
59+
else console.log('[token]', token);
60+
});
61+
};
62+
63+
return (
64+
<form onSubmit={handleSubmit} ref={form}>
65+
<input type="text" data-recurly="first_name" defaultValue="John" />
66+
<input type="text" data-recurly="last_name" defaultValue="Rambo" />
67+
<CardElement onSubmit={handleSubmit} />
68+
<button>Submit</button>
69+
</form>
70+
);
71+
}
72+
73+
render(<App />, document.querySelector('.App'));
74+
```
75+
76+
### RecurlyProvider
77+
78+
This component accepts your `publicKey` as a prop. It is responsible for creating a `recurly` instance on which we will generate tokens. This should wrap any other `react-recurly` component you will use.
79+
80+
*`index.js`*
81+
```jsx
82+
import React from 'react';
83+
import { RecurlyProvider } from 'react-recurly';
84+
import { render } from 'react-dom';
85+
86+
import MyCardForm from './my-card-form';
87+
88+
const App = () => {
89+
return (
90+
<RecurlyProvider publicKey="ewr1-abcdefghijklmno">
91+
<MyCardForm />
92+
</RecurlyProvider>
93+
);
94+
};
95+
96+
render(<App />, document.querySelector('.App'));
97+
```
98+
99+
### Elements
100+
101+
This component groups `Element` components together. When generating tokens, it is used to determine which values will be tokenized. This should wrap your checkout form.
102+
103+
*`index.js`*
104+
```jsx
105+
import React from 'react';
106+
import { Elements, RecurlyProvider } from 'react-recurly';
107+
import { render } from 'react-dom';
108+
109+
import MyCardForm from './my-card-form';
110+
111+
const App = () => {
112+
return (
113+
<RecurlyProvider publicKey="ewr1-abcdefghijklmno">
114+
<Elements>
115+
<MyCardForm />
116+
</Elements>
117+
</RecurlyProvider>
118+
);
119+
};
120+
121+
render(<App />, document.querySelector('.App'));
122+
```
123+
124+
### CardElement
125+
126+
This component renders a [Card Element](https://developers.recurly.com/reference/recurly-js/#the-card-element). Your users will enter their card information (number, expiry, and cvv) here.
127+
128+
*`my-card-form.js`*
129+
```jsx
130+
import React from 'react';
131+
import { CardElement } from 'react-recurly';
132+
133+
export function MyCardForm (props) {
134+
return (
135+
<form>
136+
<input type="text" data-recurly="first_name" />
137+
<input type="text" data-recurly="last_name" />
138+
<CardElement />
139+
</form>
140+
);
141+
}
142+
```
143+
144+
### CardNumberElement, CardMonthElement, CardYearElement, CardCvvElement
145+
146+
If the `CardElement` does not suit your design needs, you may alternatively use individual card fields.
147+
148+
### Getting a token: `useRecurly`
149+
150+
Use the `useRecurly` hook to generate a token! When your user submits your checkout form, this hook is used to submit their card information securely to Recurly, generate a token, and return that token to you. You will then send this token to your server, and [use it in the Recurly API](https://developers.recurly.com/reference/recurly-js/#using-a-token) to store or charge your customer's credit card.
151+
152+
`useRecurly` will return a `recurly` instance on which you will call `recurly.token`. You will create a ref to your form using [`React.createRef`](https://reactjs.org/docs/refs-and-the-dom.html), and pass this to `recurly.token`.
153+
154+
*`my-card-form.js`*
155+
```jsx
156+
import React from 'react';
157+
import { CardElement, useRecurly } from 'react-recurly';
158+
159+
export function MyCardForm (props) {
160+
const recurly = useRecurly();
161+
let form = React.createRef();
162+
163+
const handleSubmit = event => {
164+
if (event.preventDefault) event.preventDefault();
165+
recurly.token(form.current, (err, token) => {
166+
if (err) console.log('[error]', err);
167+
else console.log('[token]', token);
168+
});
169+
};
170+
171+
return (
172+
<form onSubmit={handleSubmit} ref={form}>
173+
<input type="text" data-recurly="first_name" />
174+
<input type="text" data-recurly="last_name" />
175+
<CardElement onSubmit={handleSubmit} />
176+
<button>Submit</button>
177+
</form>
178+
);
179+
}
180+
```

babel.config.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// using babel.config.js instead of a .babelrc because
2+
// node_modules are not transpiled by babel-jest with
3+
// a .babelrc file.
4+
// See https://github.com/facebook/jest/issues/8365
5+
6+
module.exports = {
7+
'presets': [
8+
'@babel/preset-react',
9+
'@babel/preset-env'
10+
],
11+
'plugins': [
12+
'transform-class-properties'
13+
]
14+
};

demo/demos/card-element-demo.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import React, { useState } from 'react';
2+
3+
// in your app, these would be imported from 'react-recurly'
4+
import {
5+
CardElement,
6+
Elements,
7+
RecurlyProvider,
8+
useRecurly
9+
} from '../../lib/index';
10+
11+
const handleBlur = () => console.log('[blur]');
12+
const handleChange = change => console.log('[change]', change);
13+
const handleClick = () => console.log('[click]');
14+
const handleFocus = () => console.log('[focus]');
15+
const handleReady = () => console.log('[ready]');
16+
17+
export function CardElementDemo (props) {
18+
const [fontSize, setFontSize] = useState('18');
19+
20+
const handleChangeFontSize = event => setFontSize(event.target.value);
21+
22+
return (
23+
<div className="DemoSection">
24+
<RecurlyProvider publicKey={process.env.RECURLY_PUBLIC_KEY}>
25+
<Elements>
26+
<CardForm fontSize={`${fontSize}px`} />
27+
</Elements>
28+
</RecurlyProvider>
29+
30+
<div>
31+
<label htmlFor="element-font-size-card-demo">font size</label>
32+
<input
33+
id="element-font-size-card-demo"
34+
type="range"
35+
value={fontSize}
36+
onChange={handleChangeFontSize}
37+
min="0"
38+
max="32"
39+
/>
40+
{fontSize}px
41+
</div>
42+
</div>
43+
);
44+
}
45+
46+
function CardForm (props) {
47+
const { fontSize } = props;
48+
const recurly = useRecurly();
49+
let form = React.createRef();
50+
51+
const handleSubmit = event => {
52+
if (event.preventDefault) event.preventDefault();
53+
recurly.token(form.current, (err, token) => {
54+
if (err) console.log('[error]', err);
55+
else console.log('[token]', token);
56+
});
57+
};
58+
59+
return (
60+
<form onSubmit={handleSubmit} ref={form}>
61+
<div>
62+
<input data-recurly="first_name" placeholder="First Name" defaultValue="John" />
63+
<input data-recurly="last_name" placeholder="Last Name" defaultValue="Rambo" />
64+
<input data-recurly="postal_code" placeholder="Postal Code" defaultValue="94117" />
65+
</div>
66+
<CardElement
67+
onBlur={handleBlur}
68+
onChange={handleChange}
69+
onFocus={handleFocus}
70+
onReady={handleReady}
71+
onSubmit={handleSubmit}
72+
style={{ fontSize }}
73+
/>
74+
<div>
75+
<button>Pay</button>
76+
</div>
77+
</form>
78+
);
79+
}

0 commit comments

Comments
 (0)