From 5abf581f7f3c78f466abceee00a859e873618181 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Thu, 17 Nov 2016 10:45:54 -0800 Subject: [PATCH] Fixed signup and environments --- app/common/querystring.js | 15 +- app/export/har.js | 4 +- app/sync/session.js | 9 +- app/ui/components/RenderedQueryString.js | 4 +- app/ui/components/RequestPane.js | 5 +- app/ui/components/Wrapper.js | 7 +- app/ui/components/modals/GenerateCodeModal.js | 9 +- app/ui/components/modals/LoginModal.js | 2 +- app/ui/components/modals/SignupModal.js | 230 +++++++++++------- app/ui/components/settings/SettingsSync.js | 5 +- 10 files changed, 189 insertions(+), 101 deletions(-) diff --git a/app/common/querystring.js b/app/common/querystring.js index 8846894949..3ba0ea9771 100644 --- a/app/common/querystring.js +++ b/app/common/querystring.js @@ -64,8 +64,19 @@ export function deconstructToParams (qs, strict = true) { for (let stringPair of stringPairs) { const tmp = stringPair.split('='); - const name = decodeURIComponent(tmp[0] || ''); - const value = decodeURIComponent(tmp[1] || ''); + let name = ''; + try { + name = decodeURIComponent(tmp[0] || ''); + } catch (e) { + console.warn(`[querystring] Failed to decode name: ${tmp[0]}`, e); + } + + let value = ''; + try { + value = decodeURIComponent(tmp[0] || ''); + } catch (e) { + console.warn(`[querystring] Failed to decode value: ${tmp[1]}`, e); + } if (strict && !name) { continue; diff --git a/app/export/har.js b/app/export/har.js index e3966670ee..e4772225fa 100644 --- a/app/export/har.js +++ b/app/export/har.js @@ -29,9 +29,9 @@ export function exportHarWithRequest (renderedRequest, addContentLength = false) }; } -export async function exportHar (requestId, addContentLength = false) { +export async function exportHar (requestId, environmentId, addContentLength = false) { const request = await models.request.getById(requestId); - const renderedRequest = await getRenderedRequest(request); + const renderedRequest = await getRenderedRequest(request, environmentId); return exportHarWithRequest(renderedRequest, addContentLength); } diff --git a/app/sync/session.js b/app/sync/session.js index aea2b28e39..957668a7ea 100644 --- a/app/sync/session.js +++ b/app/sync/session.js @@ -221,7 +221,14 @@ export function isLoggedIn () { /** Log out and delete session data */ export async function logout () { - await util.post('/auth/logout'); + try { + await util.post('/auth/logout'); + } catch (e) { + // Not a huge deal if this fails, but we don't want it to prevent the + // user from signing out. + console.warn('Failed to logout', e); + } + unsetSessionData(); trackEvent('Session', 'Logout'); } diff --git a/app/ui/components/RenderedQueryString.js b/app/ui/components/RenderedQueryString.js index 552ddbcad4..2ff1935df0 100644 --- a/app/ui/components/RenderedQueryString.js +++ b/app/ui/components/RenderedQueryString.js @@ -15,7 +15,8 @@ class RenderedQueryString extends Component { _update (props, delay = false) { clearTimeout(this._askTimeout); this._askTimeout = setTimeout(async () => { - const {url, parameters} = await getRenderedRequest(props.request); + const {request, environmentId} = props; + const {url, parameters} = await getRenderedRequest(request, environmentId); const qs = querystring.buildFromParams(parameters); const fullUrl = querystring.joinURL(url, qs); this.setState({string: util.prepareUrlForSending(fullUrl)}); @@ -53,6 +54,7 @@ class RenderedQueryString extends Component { RenderedQueryString.propTypes = { request: PropTypes.object.isRequired, + environmentId: PropTypes.string.isRequired, // Optional placeholder: PropTypes.string diff --git a/app/ui/components/RequestPane.js b/app/ui/components/RequestPane.js index 615f2ed9ee..506b99145b 100644 --- a/app/ui/components/RequestPane.js +++ b/app/ui/components/RequestPane.js @@ -14,7 +14,8 @@ class RequestPane extends Component { render () { const { request, - handleImportFileToWorkspace, + environmentId, + handleImportFile, showPasswords, editorFontSize, editorLineWrapping, @@ -147,6 +148,7 @@ class RequestPane extends Component { @@ -200,6 +202,7 @@ RequestPane.propTypes = { showPasswords: PropTypes.bool.isRequired, editorFontSize: PropTypes.number.isRequired, editorLineWrapping: PropTypes.bool.isRequired, + environmentId: PropTypes.string.isRequired, // Optional request: PropTypes.object, diff --git a/app/ui/components/Wrapper.js b/app/ui/components/Wrapper.js index 0a0ddfcc1d..bad7543315 100644 --- a/app/ui/components/Wrapper.js +++ b/app/ui/components/Wrapper.js @@ -18,7 +18,6 @@ import Sidebar from './sidebar/Sidebar'; import RequestPane from './RequestPane'; import ResponsePane from './ResponsePane'; import * as models from '../../models/index'; -import {PREVIEW_MODE_FRIENDLY} from '../../common/constants'; const Wrapper = props => { @@ -115,6 +114,7 @@ const Wrapper = props => { useBulkHeaderEditor={settings.useBulkHeaderEditor} editorFontSize={settings.editorFontSize} editorLineWrapping={settings.editorLineWrapping} + environmentId={activeEnvironment ? activeEnvironment._id : 'n/a'} handleCreateRequest={handleCreateRequest.bind(null, activeRequest ? activeRequest.parentId : activeWorkspace._id)} updateRequestBody={body => models.request.update(activeRequest, {body})} updateRequestUrl={url => handleUpdateRequestUrl(activeRequest, url)} @@ -157,7 +157,10 @@ const Wrapper = props => { registerModal(m)}/> registerModal(m)}/> registerModal(m)}/> - registerModal(m)}/> + registerModal(m)} + environmentId={activeEnvironment ? activeEnvironment._id : 'n/a'} + /> registerModal(m)} handleExportWorkspaceToFile={handleExportWorkspaceToFile} diff --git a/app/ui/components/modals/GenerateCodeModal.js b/app/ui/components/modals/GenerateCodeModal.js index 3b0b73930f..3db002c9c6 100644 --- a/app/ui/components/modals/GenerateCodeModal.js +++ b/app/ui/components/modals/GenerateCodeModal.js @@ -1,4 +1,4 @@ -import React, {Component} from 'react'; +import React, {Component, PropTypes} from 'react'; import HTTPSnippet, {availableTargets} from 'httpsnippet'; import CopyButton from '../base/CopyButton'; @@ -57,7 +57,8 @@ class GenerateCodeModal extends Component { // Some clients need a content-length for the request to succeed const addContentLength = (TO_ADD_CONTENT_LENGTH[target.key] || []).find(c => c === client.key); - const har = await exportHar(request._id, addContentLength); + const {environmentId} = this.props; + const har = await exportHar(request._id, environmentId, addContentLength); const snippet = new HTTPSnippet(har); const cmd = snippet.convert(target.key, client.key); @@ -132,6 +133,8 @@ class GenerateCodeModal extends Component { } } -GenerateCodeModal.propTypes = {}; +GenerateCodeModal.propTypes = { + environmentId: PropTypes.string.isRequired, +}; export default GenerateCodeModal; diff --git a/app/ui/components/modals/LoginModal.js b/app/ui/components/modals/LoginModal.js index afe5ae01c0..edf05b5dfb 100644 --- a/app/ui/components/modals/LoginModal.js +++ b/app/ui/components/modals/LoginModal.js @@ -66,7 +66,7 @@ class LoginModal extends Component {
this.modal = m} {...this.props}> {title || "Login to Your Account"} - + {message ? (

{message}

) : null} diff --git a/app/ui/components/modals/SignupModal.js b/app/ui/components/modals/SignupModal.js index 1247f96385..f247d18008 100644 --- a/app/ui/components/modals/SignupModal.js +++ b/app/ui/components/modals/SignupModal.js @@ -1,4 +1,6 @@ import React, {Component} from 'react'; +import classnames from 'classnames'; +import Link from '../base/Link'; import Modal from '../base/Modal'; import ModalBody from '../base/ModalBody'; import ModalHeader from '../base/ModalHeader'; @@ -9,11 +11,15 @@ import LoginModal from './LoginModal'; import * as sync from '../../../sync'; import {trackEvent} from '../../../analytics'; +const STEP_BASIC_INFO = 'basic'; +const STEP_CONFIRM_PASSWORD = 'confirm'; +const STEP_LOGIN_INFO = 'done'; + class SignupModal extends Component { constructor (props) { super(props); this.state = { - step: 1, + step: STEP_BASIC_INFO, error: '', loading: false } @@ -21,6 +27,12 @@ class SignupModal extends Component { async _handleSignup (e) { e.preventDefault(); + + if (this.state.step === STEP_BASIC_INFO) { + this.setState({step: STEP_CONFIRM_PASSWORD}); + return; + } + this.setState({error: '', loading: true}); const email = this._emailInput.value; @@ -30,7 +42,7 @@ class SignupModal extends Component { try { await session.signup(firstName, lastName, email, password); - this.setState({step: 2, loading: false}); + this.setState({step: STEP_LOGIN_INFO, loading: false}); sync.init(); } catch (e) { this.setState({error: e.message, loading: false}); @@ -45,101 +57,147 @@ class SignupModal extends Component { trackEvent('Auth', 'Switch', 'To Login'); } + _checkPasswordsMatch () { + if (this._passwordInput.value !== this._passwordConfirmInput.value) { + this._passwordConfirmInput.setCustomValidity('Password didn\'t match') + } else { + this._passwordConfirmInput.setCustomValidity('') + } + } + show () { - this.setState({step: 1}); + this.setState({step: STEP_BASIC_INFO}); this.modal.show(); setTimeout(() => this._nameFirstInput.focus(), 200); } render () { const {step} = this.state; - if (step === 1) { - return ( - - this.modal = m} {...this.props}> - Sign Up For a New Account - - -
- this._nameFirstInput = n}/> -
- -
- this._nameLastInput = n}/> -
- -
- this._emailInput = n}/> -
- -
- this._passwordInput = n}/> -
-

- NOTE: your password is used for end-to-end encryption so try not - to lose it + + let inner = null; + if (step === STEP_BASIC_INFO || step === STEP_CONFIRM_PASSWORD) { + inner = [ + Sign Up For a New Account, + +

+ +
+ this._nameFirstInput = n}/> +
+ +
+ this._nameLastInput = n}/> +
+ +
+ this._emailInput = n}/> +
+ +
+ this._passwordInput = n}/> +
+
+ {step === STEP_CONFIRM_PASSWORD ? ( +
+

+ Keep your password safe because it cannot be recovered +
+ + Read More + {" "} + on how your password is used to encrypt your data +

- {this.state.error ? ( -
** {this.state.error}
- ) : null} - - -
- Already have an account? - {" "} - Login +
+ +
+ this._passwordConfirmInput = n}/> +
+
- - - - - ) +
+ ) : null} + {this.state.error ? ( +
** {this.state.error}
+ ) : null} + , + +
+ Already have an account? + {" "} + Login +
+ +
+ ] } else { - return ( - this.modal = m} {...this.props}> - Account Created - -

Please verify your account

-

- A verification email has been sent to your email address. Once - you have received it, you may login. -

-
- - - -
- ) + inner = [ + Account Created, + +

Please verify your account

+

+ A verification email has been sent to your email address. Once + you have received it, you may login. +

+
, + + + + ] } + + return ( +
+ this.modal = m} {...this.props}> + {inner} + +
+ ) } } diff --git a/app/ui/components/settings/SettingsSync.js b/app/ui/components/settings/SettingsSync.js index be409e1db2..25c341d6fc 100644 --- a/app/ui/components/settings/SettingsSync.js +++ b/app/ui/components/settings/SettingsSync.js @@ -66,9 +66,10 @@ const SettingsSync = ({

,

$5 per month or $50 per year -

+
+ 14-day trial (credit card required) cancel at any time -
+

]}