Skip to content

Instantly share code, notes, and snippets.

@mattlo
Created March 4, 2016 05:17
Show Gist options
  • Save mattlo/804594fcd02445103a70 to your computer and use it in GitHub Desktop.
Save mattlo/804594fcd02445103a70 to your computer and use it in GitHub Desktop.
React Bare Credit Card Form
import React from 'react';
export default class CardCvc extends React.Component {
static propTypes = {
onChange: React.PropTypes.func.isRequired,
value: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number
]).isRequired
};
constructor(props) {
super(props);
}
handleOnChange = (e) => {
this.props.onChange(e.target.value);
};
render() {
return (
<input
type="text"
className="form-control"
onChange={this.handleOnChange}
value={this.props.value}
placeholder="CVC"
maxLength={4}
/>
);
}
}
import React from 'react';
import KeyCodes from 'keycodes-enum';
export default class CardExpiration extends React.Component {
static propTypes = {
onChange: React.PropTypes.func.isRequired,
value: React.PropTypes.object
};
constructor(props) {
super(props);
this.state = {
displayValue: this.transformRawValue(props.value),
lastKeyCode: -1
};
}
componentWillReceiveProps(props) {
this.setState({
displayValue: this.transformRawValue(props.value)
});
}
handleOnKeyDown = (e) => {
this.setState({
lastKeyCode: e.keyCode
});
};
handleOnChange = (e) => {
const value = e.target.value;
this.props.onChange(this.transformDisplayValue(value));
};
transformDisplayValue(displayValue) {
let month;
let year;
let value;
value = displayValue || '';
value = value.replace(/[^0-9]/g, '');
const chunks = value.split('/', 2);
month = chunks[0];
year = chunks[1];
// lead zero if it doesn't start with 1
if (month && month.length === 1 && parseInt(month, 10) > 1) {
month = '0' + month;
}
// if month has a greater number than 2, override and leak into year
if (month && month.length >= 2 && (!year || year.length === 0)) {
year = month.substr(2);
month = month.substr(0, 2);
}
// odd case when month is only 1 item, switch it up
if (month && month.length === 1 && year && year.length > 0) {
month = month + year.substr(0, 1);
year = year.substr(1);
}
return {
month,
year: year && year.length > 0 ? year : undefined
};
}
transformRawValue(value) {
let out = '';
if (value) {
if (value.month) {
out = value.month;
}
const validKey = this.state ?
this.state.lastKeyCode !== KeyCodes.backspace && this.state.lastKeyCode !== undefined
: false;
if ((value.month >= 2 && validKey) || value.year) {
out += ' / ';
}
if (value.year) {
out += value.year;
}
}
return out;
}
render() {
return (
<input
type="text"
className="form-control"
onChange={this.handleOnChange}
value={this.state.displayValue}
placeholder="Expiration"
onKeyDown={this.handleOnKeyDown}
maxLength={9}
/>
);
}
}
import React from 'react';
import KeyCodes from 'keycodes-enum';
export default class CardNumber extends React.Component {
static propTypes = {
onChange: React.PropTypes.func.isRequired,
value: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number
])
};
constructor(props) {
super(props);
this.state = {
displayValue: this.transformRawValue(props.value),
lastKeyCode: -1
};
}
componentWillReceiveProps(props) {
this.setState({
displayValue: this.transformRawValue(props.value)
});
}
handleOnKeyDown = (e) => {
this.setState({
lastKeyCode: e.keyCode
});
};
handleOnChange = (e) => {
const value = e.target.value;
this.props.onChange(this.transformDisplayValue(value));
};
transformDisplayValue(displayValue) {
const parsedOutput = displayValue.replace(/[^0-9]/g, '');
if (parsedOutput.length > 0) {
return parseInt(parsedOutput, 10);
}
}
transformRawValue(value) {
return (value ? value.toString() : '').split('').reduce((last, char, index, src) => {
let out = last;
out += char;
if ((index + 1) % 4 === 0 && index < src.length - 1) {
out += ' ';
}
return out;
}, '');
}
render() {
return (
<input
type="text"
className="form-control"
onChange={this.handleOnChange}
value={this.state.displayValue}
placeholder="Card Number"
onKeyDown={this.handleOnKeyDown}
maxLength={19}
/>
);
}
}
import React from 'react';
import CardNumber from './CardNumber/CardNumber';
import CardCvc from './CardCvc/CardCvc';
import CardExpiration from './CardExpiration/CardExpiration';
export default class CreditCardForm extends React.Component {
constructor(props) {
super(props);
this.state = {
cardNumber: '',
cardExpiration: {},
cardCvc: ''
};
}
handleOnChange = (prop) => (value) => {
this.setState({
[prop]: value
});
};
render() {
return (
<div>
<div className="form-group">
<CardNumber
onChange={this.handleOnChange('cardNumber')}
value={this.state.cardNumber}
/>
</div>
<div className="form-group">
<CardExpiration
onChange={this.handleOnChange('cardExpiration')}
value={this.state.cardExpiration}
/>
</div>
<div className="form-group">
<CardCvc
onChange={this.handleOnChange('cardCvc')}
value={this.state.cardCvc}
/>
</div>
</div>
);
}
}
@mattlo
Copy link
Author

mattlo commented Mar 4, 2016

react-card-info

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