Skip to content

Instantly share code, notes, and snippets.

@mingca
Created October 9, 2019 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mingca/48449d49e372e3a6ea344f984de34fcf to your computer and use it in GitHub Desktop.
Save mingca/48449d49e372e3a6ea344f984de34fcf to your computer and use it in GitHub Desktop.
Authorize.net Accept.js React Native
/**
* Accept.js Webview implementation HOC
*
* Inspired by https://gist.github.com/mingca/3bc6e349a80a2957dfdc4b59c7154bec
*/
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
ScrollView,
View,
StyleSheet,
WebView
} from 'react-native';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { stopSubmit } from 'redux-form'
import { Actions } from 'react-native-router-flux';
import { Deferred } from 'es6-deferred-promise'
import NewPaymentMethod from './NewPaymentMethodContainer'
import { createPaymentThunk } from '../reducer';
import { appMsg } from '@containers/ui/MessageBar/reducer';
import { AppStyles, AppColors, AppFonts } from '@theme/';
import { AppConfig } from '@constants/';
const styles = StyleSheet.create({
webViewContainer: {
flex: 1,
height: 100,
display: 'none',
},
});
class AcceptHoc extends Component {
constructor(props) {
super(props);
this.onWebViewMessage = this.onWebViewMessage.bind(this);
this.sendToBridge = this.sendToBridge.bind(this);
this.state = { webviewLoading: true, webviewError: false };
}
/* Receive all events from webview */
onWebViewMessage(event) {
console.log("Message received from webview");
/* TODO: get initial LOADED_SIGNAL from accept_hosted to ensure correct page is loaded */
let msgData;
try {
msgData = JSON.parse(event.nativeEvent.data);
} catch (err) {
console.warn(err);
return;
}
console.log(`Message from web view ${event.nativeEvent.data}`);
this.deferred.resolve(msgData);
}
sendToBridge(data) {
this.deferred = new Deferred();
/* Check Webview is loaded */
if (this.state.webviewLoading) {
this.props.actions.appMsg('Page not fully loaded. Plz try again.', 'warning');
this.deferred.reject('WebView not loaded');
}
if (this.state.webviewError) {
this.props.actions.appMsg('Error while fetching Authorize.net library', 'error');
this.deferred.reject('WebView not loaded');
}
const promiseHandled = this.deferred.promise.then(response => {
/* Can't reach Authorize.net on webview */
if (response.error) {
this.props.actions.appMsg(response.error, 'Can\'t reach Authroize.net');
throw new Error();
}
/* Response from Authorize.net */
if (response.messages.resultCode === 'Error') {
this.props.actions.stopSubmit('paymentForm', { _error: AcceptHoc.parseErrors(response) });
throw new Error();
}
/* Send payment nonce to our API backend */
return this.props.actions.create(AcceptHoc.buildRequestBody(data, response));
});
/* send card/bank form data to webview */
/* TODO: Ensure this occures only once */
this.myWebView.postMessage(JSON.stringify(AcceptHoc.refinedData(data)));
return promiseHandled;
}
render = () => (
<ScrollView style={[AppStyles.container]}>
<NewPaymentMethod
id="create"
actions={{
create: this.sendToBridge,
}}
/>
<View style={styles.webViewContainer}>
<WebView
ref={webview => {
this.myWebView = webview;
}}
scrollEnabled={false}
source={{uri: AppConfig.urls.ACCEPT_SELF_HOSTED}}
onMessage={this.onWebViewMessage}
style={styles.webViewContainer}
onLoad={this._onLoadEnd.bind(this)}
onError={this._onLoadError.bind(this)}
/>
</View>
</ScrollView>
);
_onLoadEnd() {
this.setState({ webviewLoading: false });
}
_onLoadError() {
this.setState({ webviewError: true });
}
/* Parse Accept Errors */
static parseErrors(response) {
let i = 0
const result = []
while (i < response.messages.message.length) {
result.push(`${response.messages.message[i].code}: ${response.messages.message[i].text}`)
i += 1;
}
return result.join('\n');
}
/*
Refines card/bank data before pass to Accept.js
Warning: Accept.js slightly fails when the values are not string(ex: Integer)
Ensure that they are String.
*/
static refinedData(data) {
const authData = {
clientKey: AppConfig.authNet.AUTHNET_PUBLIC_CLIENT_KEY,
apiLoginID: AppConfig.authNet.AUTHNET_API_LOGIN_ID,
}
const newData = {}
newData.authData = authData
if (data.profile_type === 'card') {
const { addressAttributes, ...cardDataWithoutAddress } = data.cardData;
newData.cardData = cardDataWithoutAddress
newData.cardData.cardNumber = newData.cardData.cardNumber.replace(/ /g, '')
} else {
newData.bankData = data.bankData
}
return newData
}
/* Build body to send to Cobalt */
static buildRequestBody(data, acceptResponse) {
let body = { profile_type: data.profile_type }
const { opaqueData } = acceptResponse
console.log(data.cardData);
if (data.profile_type === 'card') {
body = {
...body,
opaqueData,
card: {
month: data.cardData.month,
year: data.cardData.year,
address_attributes: data.cardData.addressAttributes,
},
}
} else if (data.profile_type === 'ach') {
body = {
...body,
account: data.bankData.accountNumber,
routing: data.bankData.routingNumber,
bank_name: data.bankData.bankName,
account_holder: data.bankData.nameOnAccount,
account_type: data.bankData.accountType,
}
}
return body
}
}
AcceptHoc.propTypes = {
}
AcceptHoc.defaultProps = {
};
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators({
create: createPaymentThunk,
appMsg: appMsg,
stopSubmit: stopSubmit,
}, dispatch),
});
export default connect(null, mapDispatchToProps)(AcceptHoc);
@krunalray
Copy link

how can i get import NewPaymentMethod from './NewPaymentMethodContainer' file

@ARIPRASATH4664
Copy link

how can i get import NewPaymentMethod from './NewPaymentMethodContainer' file

Yeah Same what is that NewPaymentMethodContainer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment