ducky/web

Paddy 2015-05-29 Parent:b9d0efb44eaa Child:62e0c0df28bb

3:7ae5dd64c482 Go to Latest

ducky/web/src/pages/payment.jsx

Stop ignoring our build folder. Now that our HTML lives in our build folder, we should probably stop ignoring it. This means that an `hg clone` followed by an `npm install` followed by an `npm run deploy` will work. I hope.

History
1 import app from 'ampersand-app'
2 import React from 'react'
3 import ScriptLoaderMixin from 'react-script-loader'
4 import LaddaButton from 'react-ladda'
5 import LaddaCSS from '../../node_modules/ladda/dist/ladda.min.css'
6 import HeroUnit from '../components/hero'
7 import ValidationError from '../components/validation-error'
8 import onboardStyles from '../styles/onboarding.scss'
9 import config from '../config'
11 export default React.createClass({
12 displayName: 'PaymentMethodPage',
13 mixins: [ScriptLoaderMixin.ReactScriptLoaderMixin, React.addons.LinkedStateMixin],
14 getScriptURL () {
15 return 'https://js.stripe.com/v2/'
16 },
18 getInitialState () {
19 return {
20 stripeLoading: true,
21 stripeFailedToLoad: false,
22 active: false,
23 errors: [],
24 number: null,
25 name: null,
26 cvc: null,
27 expireMonth: null,
28 expireYear: null,
29 }
30 },
32 nameValidationOutputs: {},
33 numberValidationOutputs: {},
34 cvcValidationOutputs: {},
35 expirationValidationOutputs: {},
37 onScriptLoaded () {
38 Stripe.setPublishableKey(config.stripeKey)
39 this.setState({stripeLoading: false})
40 },
42 onScriptError () {
43 this.setState({stripeFailedToLoad: true})
44 },
46 getChargeDate () {
47 let created = new Date()
48 if (app.me && app.me.profile && app.me.profile.created && app.me.profile.created < created) {
49 console.log("using register date...")
50 created = app.me.profile.created
51 }
52 let month = created.getMonth()
53 let day = created.getDate()
54 month = month + 1
55 if (day > 1) {
56 day = 1
57 month = month + 1
58 }
59 let result = new Date(created.toString())
60 result.setDate(day)
61 result.setMonth(month)
62 return result
63 },
65 addCard (e) {
66 e.preventDefault()
67 if (this.state.stripeLoading || this.state.stripeFailedToLoad) {
68 return
69 }
70 this.setState({active: true})
71 const t = this
72 const errors = []
73 Stripe.card.createToken({
74 number: this.state.number,
75 cvc: this.state.cvc,
76 exp_month: this.state.expireMonth,
77 exp_year: this.state.expireYear,
78 name: this.state.name,
79 }, function(status, response) {
80 console.log(status)
81 console.log(response)
82 if (response.error) {
83 if (response.error.type == 'card_error') {
84 switch (response.error.code) {
85 case 'incorrect_number':
86 errors.push({'error': 'invalid_value', 'field': '/number'})
87 break
88 case 'invalid_number':
89 errors.push({'error': 'invalid_format', 'field': '/number'})
90 break
91 case 'invalid_expiry_month':
92 errors.push({'error': 'invalid_format', 'field': '/expireMonth'})
93 break
94 case 'invalid_expiry_year':
95 errors.push({'error': 'invalid_format', 'field': '/expireYear'})
96 break
97 case 'invalid_cvc':
98 errors.push({'error': 'invalid_format', 'field': '/cvc'})
99 break
100 case 'expired_card':
101 errors.push({'error': 'invalid_value', 'field': '/expiration'})
102 break
103 case 'incorrect_cvc':
104 errors.push({'error': 'invalid_value', 'field': '/cvc'})
105 break
106 case 'incorrect_zip':
107 errors.push({'error': 'invalid_value', 'field': '/zip'})
108 break
109 case 'card_declined':
110 errors.push({'error': 'insufficient', 'field': '/balance'})
111 break
112 case 'missing':
113 errors.push({'error': 'missing', 'field': '/customer/card'})
114 break
115 case 'processing_error':
116 errors.push({'error': 'act_of_god', 'field': '/'})
117 break
118 case 'rate_limit':
119 errors.push({'error': 'access_denied', 'field': '/rate'})
120 break
121 default:
122 errors.push({'error': 'act_of_god', 'field': '/'})
123 break
124 }
125 } else {
126 console.log('Error:', response.error.message)
127 }
128 } else {
129 console.log('Sending '+response.id+' to server to create customer')
130 }
131 t.setState({active: false, errors: errors})
132 })
133 },
135 render () {
136 return (
137 <div className='container'>
138 <HeroUnit title='Add a Payment Method'>Gotta keep our servers online and food on the table.</HeroUnit>
139 <article className='onboarding payment'>
140 <p>Ducky costs $2 a month to use. We’ll charge the card you enter below on the first of every month until your account is disabled. You won’t be charged before {this.getChargeDate().toLocaleDateString(navigator.languages, {month: 'long', year: 'numeric', day: 'numeric'})}.</p>
141 <form onSubmit={this.addCard}>
142 <div>
143 <label htmlFor='name'>Cardholder Name</label>
144 <input id='name' type='text' placeholder='This is the name on your card' valueLink={this.linkState('name')} />
145 <ValidationError errors={this.state.errors} field='/name' outputs={this.nameValidationOutputs} />
147 <label htmlFor='cardNumber'>Card Number</label>
148 <input id='cardNumber' type='text' placeholder='4242 4242 4242 4242' valueLink={this.linkState('number')} />
149 <ValidationError errors={this.state.errors} field='/number' outputs={this.numberValidationOutputs} />
151 <label htmlFor='cvc'>Security Code / CVC</label>
152 <input id='cvc' className='cvc' type='password' placeholder='123' valueLink={this.linkState('cvc')} />
154 <label htmlFor='expireMonth' className='expiration'>Expires</label>
155 <input id='expireMonth' className='expiration month' type='text' placeholder='01' valueLink={this.linkState('expireMonth')} />
156 <input id='expireYear' className='expiration year' type='text' placeholder='15' valueLink={this.linkState('expireYear')} />
157 <ValidationError errors={this.state.errors} field='/cvc' outputs={this.cvcValidationOutputs} />
158 <ValidationError errors={this.state.errors} field='/expiration' outputs={this.expirationValidationOutputs} />
160 <div className='actionbuttons'>
161 <button type='button' onClick={this.skip} className='ladda-button' disabled={this.state.active}>Not Now</button>
162 <LaddaButton style='expand-right' active={this.state.active}>
163 <button type='submit' className='primary' disabled={this.state.stripeLoading || this.state.stripeFailedToLoad || this.state.active || this.state.errors.length}>Add Card</button>
164 </LaddaButton>
165 </div>
166 </div>
167 </form>
168 </article>
169 </div>
170 )
171 }
172 })