├── LICENSE
├── README.md
└── StripeWrapper
├── StripeAPI.js
├── StripeWrapperTests
├── Info.plist
└── StripeWrapperTests.m
├── __tests__
└── stripe_api_test.js
├── iOS
├── AppDelegate.h
├── AppDelegate.m
├── Base.lproj
│ └── LaunchScreen.xib
├── Images.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Info.plist
├── main.jsbundle
└── main.m
├── index.ios.js
├── package.json
└── stripeConfig.js
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Juan Gabriel Gutierrez
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Stripe API Wrapper
2 | Stripe API wrapper for react native and a credit card information form generated with tcomb-form-native.
3 |
4 | ## Set up
5 |
6 | - npm install
7 | - Modify stripeConfig.js to use your configuration to get access to Stripe API.
8 |
9 |
--------------------------------------------------------------------------------
/StripeWrapper/StripeAPI.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Gabriel on 15-07-15.
3 | **/
4 |
5 | "use strict";
6 |
7 | var superagent = require('superagent');
8 | var base64 = require('base-64');
9 | var utf8 = require('utf8');
10 |
11 |
12 | module.exports = function (stripe_url, secret_key) {
13 | var module = {};
14 |
15 |
16 |
17 |
18 | module.createCardToken = function (cardNumber , expMonth ,expYear , cvc , callback ) {
19 |
20 |
21 | var bytes = utf8.encode(secret_key+':');
22 | var encodedSecretKey = base64.encode(bytes);
23 |
24 | try {
25 |
26 | superagent
27 | .post(stripe_url+'tokens')
28 | .set('Accept', '*/*')
29 | .set('Content-Type', 'application/x-www-form-urlencoded')
30 | .set('Authorization', 'Basic '+encodedSecretKey)
31 | .send('card'+'[number]='+cardNumber)
32 | .send('card'+'[exp_month]='+expMonth)
33 | .send('card'+'[exp_year]='+expYear)
34 | .send('card'+'[cvc]='+cvc)
35 | .end(function(err, res){
36 |
37 | if (err) {
38 | if (!err.response) {
39 | res = {
40 | ok: false,
41 | body: { errors: { default: 'Server connection error' }}
42 | }
43 | } else {
44 | res = err.response;
45 |
46 | }
47 | } else if(!res.ok){
48 |
49 | res = {
50 | ok: false,
51 | body: JSON.parse(res.text)
52 | }
53 |
54 | }else{
55 |
56 | res = {
57 | ok: true,
58 | body: JSON.parse(res.text)
59 | }
60 |
61 | }
62 |
63 | console.log('response ',res.text);
64 | callback && callback(res);
65 |
66 | }
67 | );
68 |
69 | } catch (e) {
70 | var error = {ok: false, unauthorized: false, exception: e};
71 | console.log('error ',error );
72 | callback && callback(error);
73 | }
74 |
75 |
76 | };
77 |
78 |
79 |
80 | return module;
81 | };
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/StripeWrapper/StripeWrapperTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/StripeWrapper/StripeWrapperTests/StripeWrapperTests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 | #import
12 |
13 | #import "RCTAssert.h"
14 | #import "RCTRedBox.h"
15 | #import "RCTRootView.h"
16 |
17 | #define TIMEOUT_SECONDS 240
18 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
19 |
20 | @interface StripeWrapperTests : XCTestCase
21 |
22 | @end
23 |
24 | @implementation StripeWrapperTests
25 |
26 |
27 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
28 | {
29 | if (test(view)) {
30 | return YES;
31 | }
32 | for (UIView *subview in [view subviews]) {
33 | if ([self findSubviewInView:subview matching:test]) {
34 | return YES;
35 | }
36 | }
37 | return NO;
38 | }
39 |
40 | - (void)testRendersWelcomeScreen {
41 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
42 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
43 | BOOL foundElement = NO;
44 | NSString *redboxError = nil;
45 |
46 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
47 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
48 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
49 |
50 | redboxError = [[RCTRedBox sharedInstance] currentErrorMessage];
51 |
52 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
53 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
54 | return YES;
55 | }
56 | return NO;
57 | }];
58 | }
59 |
60 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
61 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
62 | }
63 |
64 |
65 | @end
66 |
--------------------------------------------------------------------------------
/StripeWrapper/__tests__/stripe_api_test.js:
--------------------------------------------------------------------------------
1 |
2 | jest.dontMock('../StripeAPI');
3 | jest.autoMockOff();
4 |
5 | //var superagent = require('superagent');
6 | var request = require('supertest');
7 | var chai = require('chai'),
8 | expect = chai.expect,
9 | should = chai.should();
10 |
11 |
12 | var config = require('./stripeConfig');
13 | var StripeAPI = require('../StripeAPI')(config.stripeUrl,config.apiKey);
14 |
15 | var validCardToken ='tok_16RRf0DE9ZivpJtCYYBpeIWM';
16 |
17 |
18 | var card_data = {
19 | card: {
20 | "number": 4242424242424242,
21 | "exp_month": 12,
22 | "exp_year": 2016,
23 | "cvc": 123
24 | }
25 | };
26 |
27 | describe('StripeAPI request tokens', function() {
28 |
29 |
30 | it('call function createCardToken', function(done) {
31 |
32 | this.timeout(60000);
33 |
34 | stripe.createCardTokenTest(request, card_data.card.number,
35 | card_data.card.exp_month,
36 | card_data.card.exp_year,
37 | card_data.card.cvc,
38 | function(err, res) {
39 |
40 | if (err)
41 | return done(err);
42 |
43 | expect(res.ok).to.be.true;
44 | expect(res.body.id).to.have.length(1);
45 | done();
46 | }
47 |
48 | );
49 |
50 |
51 |
52 |
53 | });
54 | });
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/StripeWrapper/iOS/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | @interface AppDelegate : UIResponder
13 |
14 | @property (nonatomic, strong) UIWindow *window;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/StripeWrapper/iOS/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import "AppDelegate.h"
11 |
12 | #import "RCTRootView.h"
13 |
14 | @implementation AppDelegate
15 |
16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
17 | {
18 | NSURL *jsCodeLocation;
19 |
20 | /**
21 | * Loading JavaScript code - uncomment the one you want.
22 | *
23 | * OPTION 1
24 | * Load from development server. Start the server from the repository root:
25 | *
26 | * $ npm start
27 | *
28 | * To run on device, change `localhost` to the IP address of your computer
29 | * (you can get this by typing `ifconfig` into the terminal and selecting the
30 | * `inet` value under `en0:`) and make sure your computer and iOS device are
31 | * on the same Wi-Fi network.
32 | */
33 |
34 | jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle"];
35 |
36 | /**
37 | * OPTION 2
38 | * Load from pre-bundled file on disk. To re-generate the static bundle
39 | * from the root of your project directory, run
40 | *
41 | * $ react-native bundle --minify
42 | *
43 | * see http://facebook.github.io/react-native/docs/runningondevice.html
44 | */
45 |
46 | // jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
47 |
48 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
49 | moduleName:@"StripeWrapper"
50 | launchOptions:launchOptions];
51 |
52 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
53 | UIViewController *rootViewController = [[UIViewController alloc] init];
54 | rootViewController.view = rootView;
55 | self.window.rootViewController = rootViewController;
56 | [self.window makeKeyAndVisible];
57 | return YES;
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/StripeWrapper/iOS/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/StripeWrapper/iOS/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/StripeWrapper/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UIViewControllerBasedStatusBarAppearance
38 |
39 | NSLocationWhenInUseUsageDescription
40 |
41 | NSAppTransportSecurity
42 |
43 |
44 | NSAllowsArbitraryLoads
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/StripeWrapper/iOS/main.jsbundle:
--------------------------------------------------------------------------------
1 | // Offline JS
2 | // To re-generate the offline bundle, run this from the root of your project:
3 | //
4 | // $ react-native bundle --minify
5 | //
6 | // See http://facebook.github.io/react-native/docs/runningondevice.html for more details.
7 |
8 | throw new Error('Offline JS file is empty. See iOS/main.jsbundle for instructions');
9 |
--------------------------------------------------------------------------------
/StripeWrapper/iOS/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | * All rights reserved.
4 | *
5 | * This source code is licensed under the BSD-style license found in the
6 | * LICENSE file in the root directory of this source tree. An additional grant
7 | * of patent rights can be found in the PATENTS file in the same directory.
8 | */
9 |
10 | #import
11 |
12 | #import "AppDelegate.h"
13 |
14 | int main(int argc, char * argv[]) {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/StripeWrapper/index.ios.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample Stripe Wrapper
3 | *
4 | */
5 | 'use strict';
6 |
7 | var React = require('react-native');
8 | var tCombForms = require('tcomb-form-native');
9 | var config = require('./stripeConfig');
10 |
11 | var StripeAPI = require('./StripeAPI')(config.stripeUrl,config.apiKey);
12 |
13 | var { AppRegistry, StyleSheet, Text, View, TouchableHighlight } = React;
14 |
15 |
16 | var Form = tCombForms.form.Form;
17 |
18 | // 4242424242424242,12,2016,123,this._onReceiveToken);
19 |
20 | var CreditCard = tCombForms.struct({
21 | number: tCombForms.Num,
22 | exp_month: tCombForms.Num,
23 | exp_year: tCombForms.Num ,
24 | cvc: tCombForms.Num ,
25 | rememberMe: tCombForms.Bool
26 | });
27 |
28 | var options = {
29 | auto: 'none',
30 |
31 | fields: {
32 | number: {
33 | placeholder: 'Card number',
34 | error: 'Insert a valid credit card number'
35 | },
36 | exp_month: {
37 | placeholder: 'MM'
38 | },
39 | exp_year: {
40 | placeholder: 'YYYY'
41 | },
42 | cvc: {
43 | placeholder: 'CVC'
44 | }
45 |
46 | }
47 | };
48 |
49 |
50 |
51 |
52 | var RCTStripe = React.createClass({
53 |
54 |
55 | _onError : function(error) {
56 |
57 | console.log("error ",error);
58 |
59 |
60 | },
61 |
62 | _onReceiveToken: function(response){
63 |
64 | if(!response.ok){
65 | console.log('error',response.text);
66 | }else {
67 | console.log('card token',response.body.id);
68 | alert('token:'+response.body.id);
69 | }
70 |
71 |
72 | },
73 |
74 | onPress: function () {
75 | // call getValue() to get the values of the form
76 | var value = this.refs.form.getValue();
77 |
78 | if (value) { // if validation fails, value will be null
79 |
80 | console.log(value);
81 | StripeAPI.createCardToken(value.number,value.exp_month,value.exp_year,value.cvc,this._onReceiveToken);
82 |
83 | }
84 | },
85 |
86 | render: function() {
87 | return (
88 |
89 | {/* display */}
90 |
95 |
96 | Pay $20.0
97 |
98 |
99 | );
100 | }
101 |
102 | });
103 |
104 | var styles = StyleSheet.create({
105 | container: {
106 | justifyContent: 'center',
107 | marginTop: 50,
108 | padding: 20,
109 | backgroundColor: '#ffffff',
110 | },
111 | title: {
112 | fontSize: 30,
113 | alignSelf: 'center',
114 | marginBottom: 30
115 | },
116 | buttonText: {
117 | fontSize: 18,
118 | color: 'white',
119 | alignSelf: 'center'
120 | },
121 | button: {
122 | height: 36,
123 | backgroundColor: '#48BBEC',
124 | borderColor: '#48BBEC',
125 | borderWidth: 1,
126 | borderRadius: 8,
127 | marginBottom: 10,
128 | alignSelf: 'stretch',
129 | justifyContent: 'center'
130 | }
131 | });
132 |
133 | AppRegistry.registerComponent('StripeWrapper', () => RCTStripe);
134 |
--------------------------------------------------------------------------------
/StripeWrapper/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "StripeWrapper",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node_modules/react-native/packager/packager.sh",
7 | "test": "jest"
8 | },
9 | "dependencies": {
10 | "base-64": "^0.1.0",
11 | "react-native": "^0.8.0",
12 | "superagent": "^1.3.0",
13 | "tcomb-form-native": "^0.2.4",
14 | "utf8": "^2.1.1"
15 | },
16 | "devDependencies": {
17 | "babel-core": "^5.8.12",
18 | "babel-jest": "^5.3.0",
19 | "jest-cli": "facebook/jest#0.5.x"
20 | },
21 | "repository": {
22 | "type": "git",
23 | "url": "https://github.com/llanox/react-native-stripe-wrapper"
24 | },
25 | "author": "Juan Gabriel Gutierrez ",
26 | "license": "MIT",
27 | "bugs": {
28 | "url": "https://github.com/llanox/react-native-stripe-wrapper/issues"
29 | },
30 | "jest": {
31 | "scriptPreprocessor": "/node_modules/babel-jest",
32 | "testFileExtensions": [
33 | "es6",
34 | "js"
35 | ],
36 | "collectCoverage": true
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/StripeWrapper/stripeConfig.js:
--------------------------------------------------------------------------------
1 | var config = module.exports = {};
2 |
3 | //StripeSettings
4 |
5 | config.stripeUrl = 'https://api.stripe.com/v1/';
6 | config.apiKey = 'sk_test_xxxxxxxxxxxxxxxxxx';
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------