mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-02-20 22:23:53 +08:00
[N1] Validate input in the signup dialog
Summary: This diff bundles a number of small usability fixes to the "Create account" window. It notably: - forces users to enter required fields before moving on to the next step - validates email addresses and domain names Test Plan: Tested manually by going through all the possible auth flows. Reviewers: evan, juan, bengotow Reviewed By: bengotow Subscribers: bengotow Projects: #edgehill Differential Revision: https://phab.nylas.com/D2377
This commit is contained in:
parent
fc20b60b61
commit
da54fa7e29
3 changed files with 120 additions and 12 deletions
|
@ -1,4 +1,5 @@
|
|||
React = require 'react'
|
||||
_ = require 'underscore'
|
||||
{ipcRenderer, dialog, remote} = require 'electron'
|
||||
{RetinaImg} = require 'nylas-component-kit'
|
||||
{EdgehillAPI, NylasAPI, APIError, Actions} = require 'nylas-exports'
|
||||
|
@ -88,12 +89,59 @@ class AccountSettingsPage extends React.Component
|
|||
settings[field] = event.target.checked
|
||||
else
|
||||
settings[field] = formatter(event.target.value)
|
||||
|
||||
setting_field = _.find(@state.provider.settings, ((e) -> return e['name'] == field))
|
||||
|
||||
# If the field defines an isValid method, try to validate
|
||||
# the input.
|
||||
if setting_field?.isValid?
|
||||
if not setting_field.isValid(event.target.value)
|
||||
errorFields = _.uniq(@state.errorFieldNames.concat Array(field))
|
||||
@setState({errorFieldNames: errorFields})
|
||||
else
|
||||
errorFields = _.uniq((x for x in @state.errorFieldNames when x != field))
|
||||
@setState({errorFieldNames: errorFields})
|
||||
|
||||
@setState({settings})
|
||||
|
||||
_noFormErrors: =>
|
||||
allFields = @state.provider.fields.concat(@state.provider.settings || [])
|
||||
fieldsOnThisPage = allFields.filter(@_fieldOnCurrentPage)
|
||||
fieldNames = _.pluck(fieldsOnThisPage, 'name')
|
||||
return _.intersection(fieldNames, @state.errorFieldNames).length == 0
|
||||
|
||||
_fieldRequired: (f) =>
|
||||
return f?.required == true
|
||||
|
||||
_allRequiredFieldsFilled: =>
|
||||
allFields = @state.provider.fields.concat(@state.provider.settings || [])
|
||||
requiredFields = allFields.filter(@_fieldOnCurrentPage).filter(@_fieldRequired)
|
||||
fields = _.extend(@state.fields, @state.settings)
|
||||
|
||||
for field in requiredFields
|
||||
fieldName = field['name']
|
||||
if not (fieldName of fields) or fields[fieldName] == ''
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
_onValueChanged: (event) =>
|
||||
field = event.target.dataset.field
|
||||
fields = @state.fields
|
||||
fields[field] = event.target.value
|
||||
|
||||
provider_field = _.find(@state.provider.fields, ((e) -> return e['name'] == field))
|
||||
|
||||
# If the field defines an isValid method, try to validate
|
||||
# the input.
|
||||
if provider_field?.isValid?
|
||||
if not provider_field.isValid(event.target.value)
|
||||
errorFields = _.uniq(@state.errorFieldNames.concat [field])
|
||||
@setState({errorFieldNames: errorFields})
|
||||
else
|
||||
errorFields = _.uniq((x for x in @state.errorFieldNames when x != field))
|
||||
@setState({errorFieldNames: errorFields})
|
||||
|
||||
@setState({fields})
|
||||
|
||||
_onFieldKeyPress: (event) =>
|
||||
|
@ -180,14 +228,23 @@ class AccountSettingsPage extends React.Component
|
|||
_renderButton: =>
|
||||
pages = @state.provider.pages || []
|
||||
if pages.length > @state.pageNumber+1
|
||||
<button className="btn btn-large btn-gradient" type="button" onClick={@_onNextButton}>Continue</button>
|
||||
# We're not on the last page.
|
||||
if @_noFormErrors() and @_allRequiredFieldsFilled()
|
||||
<button className="btn btn-large btn-gradient" type="button" onClick={@_onNextButton}>Continue</button>
|
||||
else
|
||||
# Disable the "Continue" button if the fields haven't been filled correctly.
|
||||
<button className="btn btn-large btn-gradient btn-disabled" type="button">Continue</button>
|
||||
else if @state.provider.name isnt 'gmail'
|
||||
if @state.tryingToAuthenticate
|
||||
<button className="btn btn-large btn-disabled btn-add-account-spinning" type="button">
|
||||
<RetinaImg name="sending-spinner.gif" width={15} height={15} mode={RetinaImg.Mode.ContentPreserve} /> Adding account…
|
||||
</button>
|
||||
else
|
||||
<button className="btn btn-large btn-gradient btn-add-account" type="button" onClick={@_onSubmit}>Add account</button>
|
||||
if @_noFormErrors() and @_allRequiredFieldsFilled()
|
||||
<button className="btn btn-large btn-gradient btn-add-account" type="button" onClick={@_onSubmit}>Add account</button>
|
||||
else
|
||||
# Disable the "Add Account" button if the fields haven't been filled correctly.
|
||||
<button className="btn btn-large btn-gradient btn-add-account btn-disabled" type="button">Add account</button>
|
||||
|
||||
_onNextButton: (event) =>
|
||||
@setState(pageNumber: @state.pageNumber + 1)
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
RegExpUtils = require('nylas-exports').RegExpUtils
|
||||
|
||||
validEmail = (address) ->
|
||||
return RegExpUtils.emailRegex().test(address)
|
||||
|
||||
validDomain = (domain) ->
|
||||
return RegExpUtils.domainRegex().test(domain)
|
||||
|
||||
Providers = [
|
||||
{
|
||||
name: 'gmail'
|
||||
displayName: 'Gmail'
|
||||
displayName: 'Gmail or Google Apps'
|
||||
icon: 'ic-settings-account-gmail.png'
|
||||
header_icon: 'setup-icon-provider-gmail.png'
|
||||
color: '#e99999'
|
||||
|
@ -14,17 +20,23 @@ Providers = [
|
|||
icon: 'ic-settings-account-eas.png'
|
||||
header_icon: 'setup-icon-provider-exchange.png'
|
||||
color: '#1ea2a3'
|
||||
pages: ['Set up your Exchange account', 'Advanced settings']
|
||||
fields: [
|
||||
{
|
||||
name: 'name'
|
||||
type: 'text'
|
||||
placeholder: 'Ashton Letterman'
|
||||
label: 'Name'
|
||||
required: true
|
||||
page: 0
|
||||
}, {
|
||||
name: 'email'
|
||||
type: 'text'
|
||||
type: 'email'
|
||||
placeholder: 'you@example.com'
|
||||
label: 'Email'
|
||||
isValid: validEmail
|
||||
required: true
|
||||
page: 0
|
||||
}
|
||||
]
|
||||
settings: [
|
||||
|
@ -33,16 +45,21 @@ Providers = [
|
|||
type: 'text'
|
||||
placeholder: 'MYCORP\\bob (if known)'
|
||||
label: 'Username (optional)'
|
||||
page: 1
|
||||
}, {
|
||||
name: 'password'
|
||||
type: 'password'
|
||||
placeholder: 'Password'
|
||||
label: 'Password'
|
||||
required: true
|
||||
page: 1
|
||||
}, {
|
||||
name: 'eas_server_host'
|
||||
type: 'text'
|
||||
placeholder: 'mail.company.com'
|
||||
label: 'Exchange server (optional)'
|
||||
name: 'eas_server_host'
|
||||
type: 'text'
|
||||
placeholder: 'mail.company.com'
|
||||
label: 'Exchange server (optional)'
|
||||
isValid: validDomain
|
||||
page: 1
|
||||
}
|
||||
]
|
||||
}, {
|
||||
|
@ -57,11 +74,16 @@ Providers = [
|
|||
type: 'text'
|
||||
placeholder: 'Ashton Letterman'
|
||||
label: 'Name'
|
||||
required: true
|
||||
page: 0
|
||||
}, {
|
||||
name: 'email'
|
||||
type: 'text'
|
||||
type: 'email'
|
||||
placeholder: 'you@icloud.com'
|
||||
label: 'Email'
|
||||
isValid: validEmail
|
||||
required: true
|
||||
page: 0
|
||||
}
|
||||
]
|
||||
settings: [{
|
||||
|
@ -69,6 +91,8 @@ Providers = [
|
|||
type: 'password'
|
||||
placeholder: 'Password'
|
||||
label: 'Password'
|
||||
required: true
|
||||
page: 0
|
||||
}]
|
||||
}, {
|
||||
name: 'outlook'
|
||||
|
@ -82,11 +106,16 @@ Providers = [
|
|||
type: 'text'
|
||||
placeholder: 'Ashton Letterman'
|
||||
label: 'Name'
|
||||
required: true
|
||||
page: 0
|
||||
}, {
|
||||
name: 'email'
|
||||
type: 'text'
|
||||
type: 'email'
|
||||
placeholder: 'you@hotmail.com'
|
||||
label: 'Email'
|
||||
isValid: validEmail
|
||||
required: true
|
||||
page: 0
|
||||
}
|
||||
]
|
||||
settings: [{
|
||||
|
@ -94,6 +123,8 @@ Providers = [
|
|||
type: 'password'
|
||||
placeholder: 'Password'
|
||||
label: 'Password'
|
||||
required: true
|
||||
page: 0
|
||||
}]
|
||||
}, {
|
||||
name: 'yahoo'
|
||||
|
@ -107,11 +138,16 @@ Providers = [
|
|||
type: 'text'
|
||||
placeholder: 'Ashton Letterman'
|
||||
label: 'Name'
|
||||
required: true
|
||||
page: 0
|
||||
}, {
|
||||
name: 'email'
|
||||
type: 'text'
|
||||
type: 'email'
|
||||
placeholder: 'you@yahoo.com'
|
||||
label: 'Email'
|
||||
isValid: validEmail
|
||||
required: true
|
||||
page: 0
|
||||
}
|
||||
]
|
||||
settings: [{
|
||||
|
@ -119,6 +155,7 @@ Providers = [
|
|||
type: 'password'
|
||||
placeholder: 'Password'
|
||||
label: 'Password'
|
||||
required: true
|
||||
}]
|
||||
}, {
|
||||
name: 'imap'
|
||||
|
@ -133,12 +170,15 @@ Providers = [
|
|||
placeholder: 'Ashton Letterman'
|
||||
label: 'Name'
|
||||
page: 0
|
||||
required: true
|
||||
}, {
|
||||
name: 'email'
|
||||
type: 'text'
|
||||
type: 'email'
|
||||
placeholder: 'you@example.com'
|
||||
label: 'Email'
|
||||
isValid: validEmail
|
||||
page: 0
|
||||
required: true
|
||||
}
|
||||
]
|
||||
settings: [
|
||||
|
@ -148,6 +188,8 @@ Providers = [
|
|||
placeholder: 'imap.domain.com'
|
||||
label: 'IMAP Server'
|
||||
page: 1
|
||||
required: true
|
||||
isValid: validDomain
|
||||
}, {
|
||||
name: 'imap_port'
|
||||
type: 'text'
|
||||
|
@ -170,18 +212,22 @@ Providers = [
|
|||
placeholder: 'Username'
|
||||
label: 'Username'
|
||||
page: 1
|
||||
required: true
|
||||
}, {
|
||||
name: 'imap_password'
|
||||
type: 'password'
|
||||
placeholder: 'Password'
|
||||
label: 'Password'
|
||||
page: 1
|
||||
required: true
|
||||
}, {
|
||||
name: 'smtp_host'
|
||||
type: 'text'
|
||||
placeholder: 'smtp.domain.com'
|
||||
label: 'SMTP Server'
|
||||
page: 2
|
||||
required: true
|
||||
isValid: validDomain
|
||||
}, {
|
||||
name: 'smtp_port'
|
||||
type: 'text'
|
||||
|
@ -204,12 +250,14 @@ Providers = [
|
|||
placeholder: 'Username'
|
||||
label: 'Username'
|
||||
page: 2
|
||||
required: true
|
||||
}, {
|
||||
name: 'smtp_password'
|
||||
type: 'password'
|
||||
placeholder: 'Password'
|
||||
label: 'Password'
|
||||
page: 2
|
||||
required: true
|
||||
}
|
||||
]
|
||||
# }, {
|
||||
|
|
|
@ -13,6 +13,9 @@ RegExpUtils =
|
|||
# https://en.wikipedia.org/wiki/Email_address#Local_part
|
||||
emailRegex: -> new RegExp(/([a-z.A-Z0-9!#$%&'*+\-/=?^_`{|}~;:]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,63})/g)
|
||||
|
||||
# http://stackoverflow.com/a/16463966
|
||||
domainRegex: -> new RegExp(/^(?!:\/\/)([a-zA-Z0-9]+\.)?[a-zA-Z0-9][a-zA-Z0-9-]+\.[a-zA-Z]{2,11}?$/i)
|
||||
|
||||
# https://regex101.com/r/zG7aW4/3
|
||||
imageTagRegex: -> /<img\s+[^>]*src="([^"]*)"[^>]*>/g
|
||||
|
||||
|
|
Loading…
Reference in a new issue