Last active
November 13, 2019 19:45
-
-
Save jscodelover/da73c80d366cf03ae536a82ac1c456eb 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