ducky/web
ducky/web/src/pages/register.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.
1 import app from 'ampersand-app'
2 import React from 'react/addons'
3 import localLinks from 'local-links'
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 onboardingStyles from '../styles/onboarding.scss'
9 import flashStyles from '../styles/_flashes.scss'
10 import debounce from 'lodash.debounce'
12 export default React.createClass({
13 displayName: 'RegisterPage',
14 mixins: [React.addons.LinkedStateMixin],
16 getInitialState () {
17 return {
18 email: null,
19 emailConfirmation: null,
20 passphrase: null,
21 passphraseConfirmation: null,
22 active: false,
23 errors: [],
24 }
25 },
27 emailValidationOutputs: {
28 'missing': 'We need to know how to contact you. We promise not to share it.',
29 'overflow': 'Hm, that’s a bit long. Do you have a shorter email address?',
30 'invalid_format': 'That doesn’t look like an email address… Double check it?',
31 },
33 emailConfirmationValidationOutputs: {
34 'invalid_value': 'Oops! Those emails don’t match. Maybe double-check them?',
35 },
37 passphraseValidationOutputs: {
38 'insufficient': 'A longer passphrase would be better.',
39 'missing': 'Looks like you forgot to enter a passphrase. You need one!',
40 'overflow': 'We can’t store that long a passphrase. Try a shorter one.',
41 },
43 passphraseConfirmationValidationOutputs: {
44 'invalid_value': 'Oops! Those passphrases don’t match. Maybe double-check them?',
45 },
47 debouncedValidateForm (event) {
48 this._validateForm(event)
49 },
51 _validateForm (event) {
52 const fields = {
53 email: this.state.email,
54 emailConfirmation: this.state.emailConfirmation,
55 passphrase: this.state.passphrase,
56 passphraseConfirmation: this.state.passphraseConfirmation,
57 }
58 if (event != null) {
59 if (event.target.id == 'emailInput') {
60 fields.email = event.target.value
61 }
62 else if (event.target.id == 'emailConfirmationInput') {
63 fields.emailConfirmation = event.target.value
64 }
65 else if (event.target.id == 'passphraseInput') {
66 fields.passphrase = event.target.value
67 }
68 else if (event.target.id == 'passphraseConfirmationInput') {
69 fields.passphraseConfirmation = event.target.value
70 }
71 }
72 const errors = this.validate(fields, event == null)
73 this.setState({errors: errors})
74 return errors.length <= 0
75 },
77 validateForm (event) {
78 event.persist()
79 this.debouncedValidateForm(event)
80 },
82 validate (fields, all) {
83 const errors = []
84 if (fields.email != null) {
85 if (fields.email.length == 0) {
86 errors.push({'error': 'missing', 'field': '/email'})
87 } else if (fields.email.length > 64) {
88 errors.push({'error': 'overflow', 'field': '/email'})
89 } else if (!fields.email.match(/.+@.+\..+/)) {
90 errors.push({'error': 'invalid_format', 'field': '/email'})
91 }
92 } else if (all) {
93 errors.push({'error': 'missing', 'field': '/email'})
94 }
95 if (fields.emailConfirmation != null || all) {
96 if (fields.emailConfirmation != fields.email && (fields.email || fields.emailConfirmation)) {
97 errors.push({'error': 'invalid_value', 'field': '/email_confirmation'})
98 }
99 }
100 if (fields.passphrase != null) {
101 if (fields.passphrase.length == 0) {
102 errors.push({'error': 'missing', 'field': '/passphrase'})
103 } else if (fields.passphrase.length < 6) {
104 errors.push({'error': 'insufficient', 'field': '/passphrase'})
105 } else if (fields.passphrase.length > 64) {
106 errors.push({'error': 'overflow', 'field': '/passphrase'})
107 }
108 } else if (all) {
109 errors.push({'error': 'missing', 'field': '/passphrase'})
110 }
111 if (fields.passphraseConfirmation != null || all) {
112 if (fields.passphraseConfirmation != fields.passphrase && (fields.passphrase || fields.passphraseConfirmation)) {
113 errors.push({'error': 'invalid_value', 'field': '/passphrase_confirmation'})
114 }
115 }
116 return errors
117 },
119 componentDidMount () {
120 app.profiles.on('request', (moc, xhr, options) => {
121 this.setState({active: true})
122 })
123 app.profiles.on('error', (moc, xhr, options) => {
124 this.setState({active: false})
125 })
126 app.profiles.on('sync', (moc, xhr, options) => {
127 app.me.login(this.state.email, this.state.passphrase)
128 })
129 app.me.on('sync', (moc, xhr, options) => {
130 this.setState({active: false})
131 app.router.navigate('/register/payment')
132 })
133 },
135 componentWillMount () {
136 this.debouncedValidateForm = debounce(this.debouncedValidateForm, 900)
137 },
139 register (e) {
140 e.preventDefault()
141 const success = this._validateForm(null)
142 if (!success) {
143 return
144 }
145 app.profiles.register(this.state.email, this.state.passphrase)
146 },
148 onBackClick (event) {
149 event.preventDefault()
150 window.history.back()
151 },
153 render () {
154 return (
155 <div className='container'>
156 <HeroUnit title='Create an Account'>We’d like to get to know you better.</HeroUnit>
157 <article className='onboarding register'>
158 <form onSubmit={this.register}>
159 <div>
160 <label htmlFor='emailInput'>Email</label>
161 <input id='emailInput' type='email' placeholder='Ours is quack@useducky.com' valueLink={this.linkState('email')} disabled={this.state.active} onInput={this.validateForm} />
162 <ValidationError errors={this.state.errors} field='/email' outputs={this.emailValidationOutputs} />
164 <label htmlFor='emailConfirmationInput'>Verify Email</label>
165 <input id='emailConfirmationInput' type='email' placeholder='Typos are the absolute worst.' valueLink={this.linkState('emailConfirmation')} disabled={this.state.active} onInput={this.validateForm} />
166 <ValidationError errors={this.state.errors} field='/email_confirmation' outputs={this.emailConfirmationValidationOutputs} />
168 <label htmlFor='passphraseInput'>Passphrase</label>
169 <input id='passphraseInput' type='password' placeholder='We use a sentence. Try it!' valueLink={this.linkState('passphrase')} disabled={this.state.active} onInput={this.validateForm} />
170 <ValidationError errors={this.state.errors} field='/passphrase' outputs={this.passphraseValidationOutputs} />
172 <label htmlFor='passphraseConfirmationInput'>Verify Passphrase</label>
173 <input id='passphraseConfirmationInput' type='password' placeholder='Just to make sure you know it.' valueLink={this.linkState('passphraseConfirmation')} disabled={this.state.active} onInput={this.validateForm} />
174 <ValidationError errors={this.state.errors} field='/passphrase_confirmation' outputs={this.passphraseConfirmationValidationOutputs} />
175 </div>
176 <div className='actionbuttons'>
177 <button onClick={this.onBackClick} disabled={this.state.active} type='button' className='ladda-button'>Back</button>
178 <LaddaButton style='expand-right' active={this.state.active}>
179 <button type='submit' className='primary' disabled={this.state.active || this.state.errors.length}>Register</button>
180 </LaddaButton>
181 </div>
182 </form>
183 </article>
184 </div>
185 )
186 }
187 })