Forked from jscodelover/react_stripe_save_read_card.js
Created
November 13, 2019 19:45
-
-
Save iamamused/7077022af4ea1f2f576bc26c8428df4f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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