Skip to content

Instantly share code, notes, and snippets.

@jscodelover
Last active November 13, 2019 19:45
Show Gist options
  • Save jscodelover/da73c80d366cf03ae536a82ac1c456eb to your computer and use it in GitHub Desktop.
Save jscodelover/da73c80d366cf03ae536a82ac1c456eb to your computer and use it in GitHub Desktop.
import React, { Component } from 'react';
import {
CardElement,
injectStripe,
StripeProvider,
CardNumberElement,
CardExpiryElement,
CardCVCElement,
Elements
} from 'react-stripe-elements';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import CONFIG from '../../../utils/config';
import { setupCard, saveCard } from './action';
import { URL } from '../../../utils/url_contants';
import './style.scss';
const createOptions = () => {
return {
style: {
base: {
fontSize: '16px',
color: '#465160',
fontFamily: 'Nunito Sans',
'::placeholder': {
color: '#8da5ab',
fontFamily: 'Nunito Sans',
fontStyle: 'italic',
letterSpacing: '0.025em'
}
},
invalid: {
color: '#c23d4b'
}
}
};
};
class _CardForm extends Component {
constructor(props) {
super(props);
this.state = {
errorMessage: '',
cardName: ''
};
this.myRef = React.createRef();
}
componentDidMount() {
this.props.setupCard();
}
handleChange = ({ error }) => {
if (error) {
this.setState({ errorMessage: error.message });
}
};
handleCardName = e => {
this.setState({ cardName: e.target.value });
};
handleSubmit = async evt => {
evt.preventDefault();
const {
cardData: { client_secret }
} = this.props;
const otherData = {
payment_method_data: {
billing_details: { name: this.state.cardName }
}
};
if (this.props.stripe) {
const result = await this.props.stripe.handleCardSetup(
client_secret,
this.myref,
otherData
);
if (result.setupIntent) {
await this.props.saveCard({
payment_method: result.setupIntent.payment_method
});
const { status, history } = this.props;
status && history.push(URL.CARD);
} else {
this.setState({ errorMessage: 'Please try again...' });
}
}
};
render() {
return (
<div className='cardDemo demo-1'>
<form onSubmit={this.handleSubmit.bind(this)}>
<h1 className='d-flex justify-content-center'>My Card</h1>
<label className='label'>CardHolder's Name</label>
<input
type='text'
className='name-holder'
placeholder='Name on card'
onChange={this.handleCardName}
value={this.state.cardName}
/>
<label className='label'>Card details</label>
<CardElement
{...createOptions()}
ref={this.myRef}
onChange={this.handleChange}
/>
<div className='error' role='alert'>
{this.state.errorMessage}
</div>
<button>Save Card</button>
</form>
</div>
);
}
}
class _SplitFieldsForm extends Component {
state = {
errorMessage: '',
cardName: '',
postal_code: ''
};
handleChange = ({ error }) => {
if (error) {
this.setState({ errorMessage: error.message });
}
};
handleCardName = e => {
this.setState({ cardName: e.target.value });
};
handlePostalCode = e => {
this.setState({ postal_code: e.target.value });
};
handleSubmit = async evt => {
evt.preventDefault();
const { cardName, postal_code } = this.state;
const {
cardData: { client_secret }
} = this.props;
const token = await this.props.stripe.createToken();
const otherData = {
payment_method_data: {
billing_details: { name: cardName, address: { postal_code } },
card: token.id
}
};
if (this.props.stripe) {
const result = await this.props.stripe.handleCardSetup(
client_secret,
otherData
);
if (result.setupIntent) {
await this.props.saveCard({
payment_method: result.setupIntent.payment_method
});
const { status, history } = this.props;
status && history.push(URL.CARD);
} else {
this.setState({ errorMessage: 'Please try again...' });
}
}
};
render() {
const { cardName, postal_code, errorMessage } = this.state;
return (
<div className='cardDemo demo-2'>
<form onSubmit={this.handleSubmit.bind(this)}>
<h1 className='d-flex justify-content-center'>My Card</h1>
<label className='label'>CardHolder's Name</label>
<input
type='text'
className='name-holder'
placeholder='Name on card'
onChange={this.handleCardName}
value={cardName}
/>
<label className='label'>Card number</label>
<CardNumberElement
{...createOptions()}
onChange={this.handleChange}
/>
<label className='label'>Expiration date</label>
<CardExpiryElement
{...createOptions()}
onChange={this.handleChange}
/>
<label className='label'>CVC</label>
<CardCVCElement {...createOptions()} onChange={this.handleChange} />
<label className='label'>Postal code</label>
<input
type='text'
placeholder='94115'
className='name-holder'
onChange={this.handlePostalCode}
value={postal_code}
/>
<div className='error' role='alert'>
{errorMessage}
</div>
<button>SAVE CARD</button>
</form>
</div>
);
}
}
const CardForm = injectStripe(_CardForm);
const SplitFieldsForm = injectStripe(_SplitFieldsForm);
class SaveCard extends Component {
render() {
const { status, message } = this.props;
return (
<StripeProvider apiKey={CONFIG.stripe_ApiKey}>
<div className='payment-wrapper'>
{!status && (
<div className='alert alert-danger' role='alert'>
{message}
</div>
)}
<Elements>
<CardForm handleResult={this.props.handleResult} {...this.props} />
</Elements>
<Elements>
<SplitFieldsForm
handleResult={this.props.handleResult}
{...this.props}
/>
</Elements>
</div>
</StripeProvider>
);
}
}
const mapStateToProps = ({ cardReducer }) => {
return {
cardData: cardReducer.cardData,
status: cardReducer.status,
message: cardReducer.message
};
};
const mapDispatchToProps = dispatch => {
return {
setupCard: bindActionCreators(setupCard, dispatch),
saveCard: bindActionCreators(saveCard, dispatch)
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(SaveCard);
/* important link :
https://stripe.com/docs/testing
https://stripe.com/docs/api/payment_methods/object
https://stripe.com/docs/payments/cards/saving-cards-without-payment#collect-payment-details-without-payment-web
https://stripe.dev/react-stripe-elements
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment