Created
March 4, 2016 05:17
-
-
Save mattlo/804594fcd02445103a70 to your computer and use it in GitHub Desktop.
React Bare Credit Card Form
This file contains hidden or 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 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} | |
/> | |
); | |
} | |
} |
This file contains hidden or 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 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} | |
/> | |
); | |
} | |
} |
This file contains hidden or 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 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} | |
/> | |
); | |
} | |
} |
This file contains hidden or 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 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> | |
); | |
} | |
} |
Author
mattlo
commented
Mar 4, 2016
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment