From 0bee324e48a911f586e8120272d73135a904562a Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 24 Jan 2019 14:22:25 -0600 Subject: [PATCH 01/22] Add server type selector component --- res/css/_components.scss | 1 + res/css/views/auth/_ServerTypeSelector.scss | 69 ++++++++++ res/img/feather-icons/globe.svg | 7 + res/img/feather-icons/matrix-org-bw-logo.svg | 13 ++ res/img/feather-icons/modular-bw-logo.svg | 18 +++ .../views/auth/ServerTypeSelector.js | 122 ++++++++++++++++++ src/i18n/strings/en_EN.json | 6 + 7 files changed, 236 insertions(+) create mode 100644 res/css/views/auth/_ServerTypeSelector.scss create mode 100644 res/img/feather-icons/globe.svg create mode 100644 res/img/feather-icons/matrix-org-bw-logo.svg create mode 100644 res/img/feather-icons/modular-bw-logo.svg create mode 100644 src/components/views/auth/ServerTypeSelector.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 0603296ef5..a55cf2749a 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -33,6 +33,7 @@ @import "./views/auth/_InteractiveAuthEntryComponents.scss"; @import "./views/auth/_LanguageSelector.scss"; @import "./views/auth/_ServerConfig.scss"; +@import "./views/auth/_ServerTypeSelector.scss"; @import "./views/avatars/_BaseAvatar.scss"; @import "./views/avatars/_MemberStatusMessageAvatar.scss"; @import "./views/context_menus/_MessageContextMenu.scss"; diff --git a/res/css/views/auth/_ServerTypeSelector.scss b/res/css/views/auth/_ServerTypeSelector.scss new file mode 100644 index 0000000000..03f5386501 --- /dev/null +++ b/res/css/views/auth/_ServerTypeSelector.scss @@ -0,0 +1,69 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_ServerTypeSelector { + display: flex; + margin-bottom: 28px; +} + +.mx_ServerTypeSelector_type { + margin: 0 5px; +} + +.mx_ServerTypeSelector_type:first-child { + margin-left: 0; +} + +.mx_ServerTypeSelector_type:last-child { + margin-right: 0; +} + +.mx_ServerTypeSelector_label { + text-align: center; + font-weight: 600; + color: $primary-fg-color; + margin: 8px 0; +} + +.mx_ServerTypeSelector_type .mx_AccessibleButton { + padding: 10px; + border: 1px solid $input-border-color; + border-radius: 4px; +} + +.mx_ServerTypeSelector_type.mx_ServerTypeSelector_type_selected .mx_AccessibleButton { + border-color: $input-valid-border-color; +} + +.mx_ServerTypeSelector_logo { + display: flex; + justify-content: center; + height: 18px; + margin-bottom: 12px; + font-weight: 600; + color: $primary-fg-color; +} + +.mx_ServerTypeSelector_logo > div { + display: flex; + width: 70%; + align-items: center; + justify-content: space-evenly; +} + +.mx_ServerTypeSelector_description { + font-size: 10px; +} diff --git a/res/img/feather-icons/globe.svg b/res/img/feather-icons/globe.svg new file mode 100644 index 0000000000..8af7dc41dc --- /dev/null +++ b/res/img/feather-icons/globe.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/res/img/feather-icons/matrix-org-bw-logo.svg b/res/img/feather-icons/matrix-org-bw-logo.svg new file mode 100644 index 0000000000..a8c92c539a --- /dev/null +++ b/res/img/feather-icons/matrix-org-bw-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + .org + + diff --git a/res/img/feather-icons/modular-bw-logo.svg b/res/img/feather-icons/modular-bw-logo.svg new file mode 100644 index 0000000000..924a587805 --- /dev/null +++ b/res/img/feather-icons/modular-bw-logo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/components/views/auth/ServerTypeSelector.js b/src/components/views/auth/ServerTypeSelector.js new file mode 100644 index 0000000000..0640bad6d0 --- /dev/null +++ b/src/components/views/auth/ServerTypeSelector.js @@ -0,0 +1,122 @@ +/* +Copyright 2019 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import PropTypes from 'prop-types'; +import { _t } from '../../../languageHandler'; +import sdk from '../../../index'; +import classnames from 'classnames'; + +const MODULAR_URL = 'https://modular.im/?utm_source=riot-web&utm_medium=web&utm_campaign=riot-web-authentication'; + +const TYPES = [ + { + id: 'Free', + label: () => _t('Free'), + logo: () => , + description: () => _t('Join millions for free on the largest public server'), + }, + { + id: 'Premium', + label: () => _t('Premium'), + logo: () => , + description: () => _t('Premium hosting for organisations Learn more', {}, { + a: sub => + {sub} + , + }), + }, + { + id: 'Advanced', + label: () => _t('Advanced'), + logo: () =>
+ + {_t('Other')} +
, + description: () => _t('Find other public servers or use a custom server'), + }, +]; + +export default class ServerTypeSelector extends React.PureComponent { + static propTypes = { + // ID of the initial type to show as selected or null for none. + selected: PropTypes.string, + // Handler called when the selected type changes. + onChange: PropTypes.func.isRequired, + } + + constructor(props) { + super(props); + + this.state = { + selected: null, + }; + } + + componentWillReceiveProps(props) { + const { selected } = props; + this.setState({ + selected, + }); + } + + onClick = (e) => { + e.stopPropagation(); + const id = e.currentTarget.dataset.id; + if (this.state.selected === id) { + return; + } + this.setState({ + selected: id, + }); + if (this.props.onChange) { + this.props.onChange(id); + } + } + + render() { + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + + const serverTypes = TYPES.map(type => { + const { id, label, logo, description } = type; + const classes = classnames( + "mx_ServerTypeSelector_type", + `mx_ServerTypeSelector_type_${id}`, + { + "mx_ServerTypeSelector_type_selected": id === this.state.selected, + }, + ); + + return
+
+ {label()} +
+ +
+ {logo()} +
+
+ {description()} +
+
+
; + }); + + return
+ {serverTypes} +
; + } +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index d8b8b12479..db157ba7b0 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1198,6 +1198,12 @@ "Home server URL": "Home server URL", "Identity server URL": "Identity server URL", "What does this mean?": "What does this mean?", + "Free": "Free", + "Join millions for free on the largest public server": "Join millions for free on the largest public server", + "Premium": "Premium", + "Premium hosting for organisations Learn more": "Premium hosting for organisations Learn more", + "Other": "Other", + "Find other public servers or use a custom server": "Find other public servers or use a custom server", "Sorry, your browser is not able to run Riot.": "Sorry, your browser is not able to run Riot.", "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.", "Please install Chrome or Firefox for the best experience.": "Please install Chrome or Firefox for the best experience.", From fa4ad21e0a0d0d95b8110f586d201a83e77dd7dc Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 24 Jan 2019 15:07:49 -0600 Subject: [PATCH 02/22] Remove dead code for `!withToggleButton` in `ServerConfig` --- .../structures/auth/ForgotPassword.js | 1 - src/components/structures/auth/Login.js | 1 - .../structures/auth/Registration.js | 1 - src/components/views/auth/ServerConfig.js | 48 ++++++++----------- 4 files changed, 20 insertions(+), 31 deletions(-) diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js index 73d9f95e20..1b8b15981b 100644 --- a/src/components/structures/auth/ForgotPassword.js +++ b/src/components/structures/auth/ForgotPassword.js @@ -211,7 +211,6 @@ module.exports = React.createClass({ if (!SdkConfig.get()['disable_custom_urls']) { serverConfigSection = ( - - -    - - - - ); - } + const toggleButton = ( +
+ + +    + + +
+ ); return (
@@ -177,7 +171,6 @@ module.exports = React.createClass({ From 350c24c503fd611f5d03176d86eeac62ef9e764e Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 25 Jan 2019 10:42:45 -0600 Subject: [PATCH 03/22] Initial wiring of server type selector --- src/components/structures/auth/Login.js | 66 ++++++++++++++----- .../views/auth/ServerTypeSelector.js | 56 ++++++++++------ 2 files changed, 87 insertions(+), 35 deletions(-) diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 85baab6dbf..b380d431f9 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -26,6 +26,7 @@ import Login from '../../../Login'; import SdkConfig from '../../../SdkConfig'; import { messageForResourceLimitError } from '../../../utils/ErrorUtils'; import { AutoDiscovery } from "matrix-js-sdk"; +import * as ServerType from '../../views/auth/ServerTypeSelector'; // For validating phone numbers without country codes const PHONE_NUMBER_REGEX = /^[0-9()\-\s]*$/; @@ -80,6 +81,8 @@ module.exports = React.createClass({ busy: false, errorText: null, loginIncorrect: false, + + serverType: null, enteredHomeserverUrl: this.props.customHsUrl || this.props.defaultHsUrl, enteredIdentityServerUrl: this.props.customIsUrl || this.props.defaultIsUrl, @@ -299,6 +302,12 @@ module.exports = React.createClass({ }); }, + onServerTypeChange(type) { + this.setState({ + serverType: type, + }); + }, + onRegisterClick: function(ev) { ev.preventDefault(); ev.stopPropagation(); @@ -475,7 +484,45 @@ module.exports = React.createClass({ return errorText; }, - componentForStep: function(step) { + serverComponentForStep() { + const ServerTypeSelector = sdk.getComponent("auth.ServerTypeSelector"); + const ServerConfig = sdk.getComponent("auth.ServerConfig"); + + // TODO: May need to adjust the behavior of this config option + if (SdkConfig.get()['disable_custom_urls']) { + return null; + } + + let serverDetails = null; + switch (this.state.serverType) { + case ServerType.FREE: + break; + case ServerType.PREMIUM: + break; + case ServerType.ADVANCED: + serverDetails = ; + break; + } + + return
+ + {serverDetails} +
; + }, + + loginComponentForStep() { + const step = this.state.currentFlow; + if (!step) { return null; } @@ -530,7 +577,6 @@ module.exports = React.createClass({ const AuthPage = sdk.getComponent("auth.AuthPage"); const AuthHeader = sdk.getComponent("auth.AuthHeader"); const AuthBody = sdk.getComponent("auth.AuthBody"); - const ServerConfig = sdk.getComponent("auth.ServerConfig"); const loader = this.state.busy ?
: null; const errorText = this.props.defaultServerDiscoveryError || this.state.discoveryError || this.state.errorText; @@ -543,18 +589,6 @@ module.exports = React.createClass({
; } - let serverConfig; - - if (!SdkConfig.get()['disable_custom_urls']) { - serverConfig = ; - } - let errorTextSection; if (errorText) { errorTextSection = ( @@ -573,8 +607,8 @@ module.exports = React.createClass({ {loader} { errorTextSection } - { this.componentForStep(this.state.currentFlow) } - { serverConfig } + { this.serverComponentForStep() } + { this.loginComponentForStep() } { _t('Create account') } diff --git a/src/components/views/auth/ServerTypeSelector.js b/src/components/views/auth/ServerTypeSelector.js index 0640bad6d0..765cc58280 100644 --- a/src/components/views/auth/ServerTypeSelector.js +++ b/src/components/views/auth/ServerTypeSelector.js @@ -22,15 +22,21 @@ import classnames from 'classnames'; const MODULAR_URL = 'https://modular.im/?utm_source=riot-web&utm_medium=web&utm_campaign=riot-web-authentication'; +export const FREE = 'Free'; +export const PREMIUM = 'Premium'; +export const ADVANCED = 'Advanced'; + +const MATRIX_ORG_HS = 'https://matrix.org'; + const TYPES = [ { - id: 'Free', + id: FREE, label: () => _t('Free'), logo: () => , description: () => _t('Join millions for free on the largest public server'), }, { - id: 'Premium', + id: PREMIUM, label: () => _t('Premium'), logo: () => , description: () => _t('Premium hosting for organisations Learn more', {}, { @@ -40,7 +46,7 @@ const TYPES = [ }), }, { - id: 'Advanced', + id: ADVANCED, label: () => _t('Advanced'), logo: () =>
@@ -50,10 +56,24 @@ const TYPES = [ }, ]; +function getDefaultType(defaultHsUrl) { + if (!defaultHsUrl) { + return null; + } else if (defaultHsUrl === MATRIX_ORG_HS) { + return FREE; + } else if (new URL(defaultHsUrl).hostname.endsWith('.modular.im')) { + // TODO: Use a Riot config parameter to detect Modular-ness. + // https://github.com/vector-im/riot-web/issues/8253 + return PREMIUM; + } else { + return ADVANCED; + } +} + export default class ServerTypeSelector extends React.PureComponent { static propTypes = { - // ID of the initial type to show as selected or null for none. - selected: PropTypes.string, + // The default HS URL as another way to set the initially selected type. + defaultHsUrl: PropTypes.string, // Handler called when the selected type changes. onChange: PropTypes.func.isRequired, } @@ -61,30 +81,28 @@ export default class ServerTypeSelector extends React.PureComponent { constructor(props) { super(props); + const { defaultHsUrl } = props; this.state = { - selected: null, + selected: getDefaultType(defaultHsUrl), }; } - componentWillReceiveProps(props) { - const { selected } = props; + updateSelectedType(type) { + if (this.state.selected === type) { + return; + } this.setState({ - selected, + selected: type, }); + if (this.props.onChange) { + this.props.onChange(type); + } } onClick = (e) => { e.stopPropagation(); - const id = e.currentTarget.dataset.id; - if (this.state.selected === id) { - return; - } - this.setState({ - selected: id, - }); - if (this.props.onChange) { - this.props.onChange(id); - } + const type = e.currentTarget.dataset.id; + this.updateSelectedType(type); } render() { From 73aeb26a7982d85d44c7082b60567b33d141b288 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 25 Jan 2019 12:57:17 -0600 Subject: [PATCH 04/22] Remove dead code for empty `matrixIdText` in `PasswordLogin` --- res/css/structures/auth/_Login.scss | 4 ---- src/components/views/auth/PasswordLogin.js | 22 ++++++++-------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss index c32f70a696..240c0713d9 100644 --- a/res/css/structures/auth/_Login.scss +++ b/res/css/structures/auth/_Login.scss @@ -32,10 +32,6 @@ limitations under the License. margin-bottom: 14px; } -.mx_Login_field_disabled { - opacity: 0.3; -} - .mx_Login_fieldLabel { margin-top: -10px; margin-left: 8px; diff --git a/src/components/views/auth/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js index bf1c27e6e3..6021fc911f 100644 --- a/src/components/views/auth/PasswordLogin.js +++ b/src/components/views/auth/PasswordLogin.js @@ -158,10 +158,9 @@ class PasswordLogin extends React.Component { this.props.onPasswordChanged(ev.target.value); } - renderLoginField(loginType, disabled) { + renderLoginField(loginType) { const classes = { mx_Login_field: true, - mx_Login_field_disabled: disabled, }; switch (loginType) { @@ -169,7 +168,7 @@ class PasswordLogin extends React.Component { classes.mx_Login_email = true; classes.error = this.props.loginIncorrect && !this.state.username; return {this._loginField = e;}} key="email_input" type="text" @@ -179,7 +178,6 @@ class PasswordLogin extends React.Component { placeholder="joe@example.com" value={this.state.username} autoFocus - disabled={disabled} />; case PasswordLogin.LOGIN_FIELD_MXID: classes.mx_Login_username = true; @@ -198,7 +196,6 @@ class PasswordLogin extends React.Component { }) : _t("User name")} value={this.state.username} autoFocus - disabled={disabled} />; case PasswordLogin.LOGIN_FIELD_PHONE: { const CountryDropdown = sdk.getComponent('views.auth.CountryDropdown'); @@ -212,7 +209,6 @@ class PasswordLogin extends React.Component { value={this.state.phoneCountry} isSmall={true} showPrefix={true} - disabled={disabled} />
; } @@ -271,13 +266,12 @@ class PasswordLogin extends React.Component { const pwFieldClass = classNames({ mx_Login_field: true, - mx_Login_field_disabled: matrixIdText === '', error: this.props.loginIncorrect && !this.isLoginEmpty(), // only error password if error isn't top field }); const Dropdown = sdk.getComponent('elements.Dropdown'); - const loginField = this.renderLoginField(this.state.loginType, matrixIdText === ''); + const loginField = this.renderLoginField(this.state.loginType); let loginType; if (!SdkConfig.get().disable_3pid_login) { @@ -287,7 +281,6 @@ class PasswordLogin extends React.Component { { matrixIdText } { _t('Email address') } @@ -297,8 +290,6 @@ class PasswordLogin extends React.Component { ); } - const disableSubmit = this.props.disableSubmit || matrixIdText === ''; - return (
@@ -308,11 +299,14 @@ class PasswordLogin extends React.Component { name="password" value={this.state.password} onChange={this.onPasswordChanged} placeholder={_t('Password')} - disabled={matrixIdText === ''} />
{ forgotPasswordJsx } - +
); From cd280ca79fa5c0bf7e9cfe970045629eeaf2a770 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 25 Jan 2019 14:25:29 -0600 Subject: [PATCH 05/22] Username is one word --- src/Analytics.js | 2 +- src/components/structures/auth/Registration.js | 2 +- src/components/views/auth/PasswordLogin.js | 4 ++-- src/components/views/auth/RegistrationForm.js | 4 ++-- src/i18n/strings/en_EN.json | 10 +++++----- src/notifications/VectorPushRulesDefinitions.js | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Analytics.js b/src/Analytics.js index d85d635b28..3a8c5d6e10 100644 --- a/src/Analytics.js +++ b/src/Analytics.js @@ -66,7 +66,7 @@ const customVariables = { }, 'User Type': { id: 3, - expl: _td('Whether or not you\'re logged in (we don\'t record your user name)'), + expl: _td('Whether or not you\'re logged in (we don\'t record your username)'), example: 'Logged In', }, 'Chosen Language': { diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js index edf419137e..3a63115a43 100644 --- a/src/components/structures/auth/Registration.js +++ b/src/components/structures/auth/Registration.js @@ -255,7 +255,7 @@ module.exports = React.createClass({ errMsg = _t("Only use lower case letters, numbers and '=_-./'"); break; case "RegistrationForm.ERR_USERNAME_BLANK": - errMsg = _t('You need to enter a user name.'); + errMsg = _t('You need to enter a username.'); break; default: console.error("Unknown error code: %s", errCode); diff --git a/src/components/views/auth/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js index 6021fc911f..40f4c1178a 100644 --- a/src/components/views/auth/PasswordLogin.js +++ b/src/components/views/auth/PasswordLogin.js @@ -93,7 +93,7 @@ class PasswordLogin extends React.Component { case PasswordLogin.LOGIN_FIELD_MXID: username = this.state.username; if (!username) { - error = _t('The user name field must not be blank.'); + error = _t('The username field must not be blank.'); } break; case PasswordLogin.LOGIN_FIELD_PHONE: @@ -193,7 +193,7 @@ class PasswordLogin extends React.Component { placeholder={SdkConfig.get().disable_custom_urls ? _t("Username on %(hs)s", { hs: this.props.hsUrl.replace(/^https?:\/\//, ''), - }) : _t("User name")} + }) : _t("Username")} value={this.state.username} autoFocus />; diff --git a/src/components/views/auth/RegistrationForm.js b/src/components/views/auth/RegistrationForm.js index b38d8ca361..571040188b 100644 --- a/src/components/views/auth/RegistrationForm.js +++ b/src/components/views/auth/RegistrationForm.js @@ -305,7 +305,7 @@ module.exports = React.createClass({ ); - const placeholderUserName = _t("User name"); + const placeholderUsername = _t("Username"); return (
@@ -313,7 +313,7 @@ module.exports = React.createClass({ { emailSection } { phoneSection }
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index db157ba7b0..13f9b03876 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -4,7 +4,7 @@ "Failed to verify email address: make sure you clicked the link in the email": "Failed to verify email address: make sure you clicked the link in the email", "The platform you're on": "The platform you're on", "The version of Riot.im": "The version of Riot.im", - "Whether or not you're logged in (we don't record your user name)": "Whether or not you're logged in (we don't record your user name)", + "Whether or not you're logged in (we don't record your username)": "Whether or not you're logged in (we don't record your username)", "Your language of choice": "Your language of choice", "Which officially provided instance you are using, if any": "Which officially provided instance you are using, if any", "Whether or not you're using the Richtext mode of the Rich Text Editor": "Whether or not you're using the Richtext mode of the Rich Text Editor", @@ -305,7 +305,7 @@ "Uploading report": "Uploading report", "Waiting for response from server": "Waiting for response from server", "Messages containing my display name": "Messages containing my display name", - "Messages containing my user name": "Messages containing my user name", + "Messages containing my username": "Messages containing my username", "Messages containing @room": "Messages containing @room", "Messages in one-to-one chats": "Messages in one-to-one chats", "Encrypted messages in one-to-one chats": "Encrypted messages in one-to-one chats", @@ -1180,11 +1180,11 @@ "Code": "Code", "Start authentication": "Start authentication", "The email field must not be blank.": "The email field must not be blank.", - "The user name field must not be blank.": "The user name field must not be blank.", + "The username field must not be blank.": "The username field must not be blank.", "The phone number field must not be blank.": "The phone number field must not be blank.", "The password field must not be blank.": "The password field must not be blank.", "Username on %(hs)s": "Username on %(hs)s", - "User name": "User name", + "Username": "Username", "Mobile phone number": "Mobile phone number", "Not sure of your password? Set a new one": "Not sure of your password? Set a new one", "%(serverName)s Matrix ID": "%(serverName)s Matrix ID", @@ -1406,7 +1406,7 @@ "This doesn't look like a valid phone number.": "This doesn't look like a valid phone number.", "An email address is required to register on this homeserver.": "An email address is required to register on this homeserver.", "A phone number is required to register on this homeserver.": "A phone number is required to register on this homeserver.", - "You need to enter a user name.": "You need to enter a user name.", + "You need to enter a username.": "You need to enter a username.", "An unknown error occurred.": "An unknown error occurred.", "Create your account": "Create your account", "Commands": "Commands", diff --git a/src/notifications/VectorPushRulesDefinitions.js b/src/notifications/VectorPushRulesDefinitions.js index 3df2e70774..402a69e7a6 100644 --- a/src/notifications/VectorPushRulesDefinitions.js +++ b/src/notifications/VectorPushRulesDefinitions.js @@ -83,7 +83,7 @@ module.exports = { // Messages containing user's username (localpart/MXID) ".m.rule.contains_user_name": new VectorPushRuleDefinition({ kind: "override", - description: _td("Messages containing my user name"), // passed through _t() translation in src/components/views/settings/Notifications.js + description: _td("Messages containing my username"), // passed through _t() translation in src/components/views/settings/Notifications.js vectorStateToActions: { // The actions for each vector state, or null to disable the rule. on: StandardActions.ACTION_NOTIFY, loud: StandardActions.ACTION_HIGHLIGHT_DEFAULT_SOUND, From e5e0b349588f7c0b1c84cf743ba585be9e5321f4 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 25 Jan 2019 14:56:57 -0600 Subject: [PATCH 06/22] Fix indentation --- src/components/views/auth/PasswordLogin.js | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/components/views/auth/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js index 40f4c1178a..5b56f1da00 100644 --- a/src/components/views/auth/PasswordLogin.js +++ b/src/components/views/auth/PasswordLogin.js @@ -293,20 +293,20 @@ class PasswordLogin extends React.Component { return (
- { loginType } - { loginField } - {this._passwordField = e;}} type="password" - name="password" - value={this.state.password} onChange={this.onPasswordChanged} - placeholder={_t('Password')} - /> -
- { forgotPasswordJsx } - + { loginType } + { loginField } + {this._passwordField = e;}} type="password" + name="password" + value={this.state.password} onChange={this.onPasswordChanged} + placeholder={_t('Password')} + /> +
+ { forgotPasswordJsx } +
); From 7934a2950cb36cdec1226c21f6b0de868007304c Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 25 Jan 2019 15:08:28 -0600 Subject: [PATCH 07/22] Add 'Your account' header --- res/css/views/auth/_AuthBody.scss | 12 ++++++++++++ res/css/views/auth/_AuthPage.scss | 6 ------ src/components/views/auth/PasswordLogin.js | 9 +++++---- src/i18n/strings/en_EN.json | 3 ++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/res/css/views/auth/_AuthBody.scss b/res/css/views/auth/_AuthBody.scss index cb28d57801..21641978b6 100644 --- a/res/css/views/auth/_AuthBody.scss +++ b/res/css/views/auth/_AuthBody.scss @@ -24,6 +24,18 @@ limitations under the License. color: $authpage-body-color; } +.mx_AuthBody h2 { + font-size: 24px; + font-weight: 600; + margin-top: 8px; +} + +.mx_AuthBody h3 { + font-size: 14px; + font-weight: 600; + color: $primary-fg-color; +} + .mx_AuthBody a:link, .mx_AuthBody a:hover, .mx_AuthBody a:visited { diff --git a/res/css/views/auth/_AuthPage.scss b/res/css/views/auth/_AuthPage.scss index 04dab59ed6..cf509248fd 100644 --- a/res/css/views/auth/_AuthPage.scss +++ b/res/css/views/auth/_AuthPage.scss @@ -23,12 +23,6 @@ limitations under the License. background-color: $authpage-bg-color; } -.mx_AuthPage h2 { - font-size: 24px; - font-weight: 600; - margin-top: 8px; -} - .mx_AuthPage_modal { display: flex; margin: 100px auto auto; diff --git a/src/components/views/auth/PasswordLogin.js b/src/components/views/auth/PasswordLogin.js index 5b56f1da00..5bf40ea098 100644 --- a/src/components/views/auth/PasswordLogin.js +++ b/src/components/views/auth/PasswordLogin.js @@ -252,13 +252,13 @@ class PasswordLogin extends React.Component { ; } - let matrixIdText = _t('Matrix ID'); + let yourMatrixAccountText = _t('Your account'); if (this.props.hsName) { - matrixIdText = _t('%(serverName)s Matrix ID', {serverName: this.props.hsName}); + yourMatrixAccountText = _t('Your %(serverName)s account', {serverName: this.props.hsName}); } else { try { const parsedHsUrl = new URL(this.props.hsUrl); - matrixIdText = _t('%(serverName)s Matrix ID', {serverName: parsedHsUrl.hostname}); + yourMatrixAccountText = _t('Your %(serverName)s account', {serverName: parsedHsUrl.hostname}); } catch (e) { // ignore } @@ -282,7 +282,7 @@ class PasswordLogin extends React.Component { className="mx_Login_type_dropdown" value={this.state.loginType} onOptionChange={this.onLoginTypeChange}> - { matrixIdText } + { _t('Username') } { _t('Email address') } { _t('Phone') } @@ -292,6 +292,7 @@ class PasswordLogin extends React.Component { return (
+

{ yourMatrixAccountText }

{ loginType } { loginField } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 13f9b03876..40c737dc5d 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1187,7 +1187,8 @@ "Username": "Username", "Mobile phone number": "Mobile phone number", "Not sure of your password? Set a new one": "Not sure of your password? Set a new one", - "%(serverName)s Matrix ID": "%(serverName)s Matrix ID", + "Your account": "Your account", + "Your %(serverName)s account": "Your %(serverName)s account", "Sign in with": "Sign in with", "Sign in": "Sign in", "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "If you don't specify an email address, you won't be able to reset your password. Are you sure?", From 344a5d1547846c7d00c02f96df5ffd443e5341d4 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 25 Jan 2019 15:10:19 -0600 Subject: [PATCH 08/22] Style login type with primary color --- res/css/structures/auth/_Login.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss index 240c0713d9..41c2cd1966 100644 --- a/res/css/structures/auth/_Login.scss +++ b/res/css/structures/auth/_Login.scss @@ -101,6 +101,7 @@ limitations under the License. .mx_Login_type_container { display: flex; margin-bottom: 14px; + color: $primary-fg-color; } .mx_Login_type_label { From 306380d647e4718858fb1e249a68bfe6a572d4e0 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 25 Jan 2019 23:36:18 -0600 Subject: [PATCH 09/22] Update HS / IS URLs when changing server types --- src/components/structures/auth/Login.js | 22 ++++++++++++ .../views/auth/ServerTypeSelector.js | 36 +++++++++++-------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index b380d431f9..6d61eac895 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -306,6 +306,28 @@ module.exports = React.createClass({ this.setState({ serverType: type, }); + + // When changing server types, set the HS / IS URLs to reasonable defaults for the + // the new type. + switch (type) { + case ServerType.FREE: { + const { hsUrl, isUrl } = ServerType.TYPES.FREE; + this.onServerConfigChange({ + hsUrl, + isUrl, + }); + break; + } + case ServerType.PREMIUM: + // TODO: Handle the Modular case. + break; + case ServerType.ADVANCED: + this.onServerConfigChange({ + hsUrl: this.props.defaultHsUrl, + isUrl: this.props.defaultIsUrl, + }); + break; + } }, onRegisterClick: function(ev) { diff --git a/src/components/views/auth/ServerTypeSelector.js b/src/components/views/auth/ServerTypeSelector.js index 765cc58280..de76e6acf9 100644 --- a/src/components/views/auth/ServerTypeSelector.js +++ b/src/components/views/auth/ServerTypeSelector.js @@ -26,16 +26,16 @@ export const FREE = 'Free'; export const PREMIUM = 'Premium'; export const ADVANCED = 'Advanced'; -const MATRIX_ORG_HS = 'https://matrix.org'; - -const TYPES = [ - { +export const TYPES = { + FREE: { id: FREE, label: () => _t('Free'), logo: () => , description: () => _t('Join millions for free on the largest public server'), + hsUrl: 'https://matrix.org', + isUrl: 'https://vector.im', }, - { + PREMIUM: { id: PREMIUM, label: () => _t('Premium'), logo: () => , @@ -45,7 +45,7 @@ const TYPES = [ , }), }, - { + ADVANCED: { id: ADVANCED, label: () => _t('Advanced'), logo: () =>
@@ -54,12 +54,12 @@ const TYPES = [
, description: () => _t('Find other public servers or use a custom server'), }, -]; +}; function getDefaultType(defaultHsUrl) { if (!defaultHsUrl) { return null; - } else if (defaultHsUrl === MATRIX_ORG_HS) { + } else if (defaultHsUrl === TYPES.FREE.hsUrl) { return FREE; } else if (new URL(defaultHsUrl).hostname.endsWith('.modular.im')) { // TODO: Use a Riot config parameter to detect Modular-ness. @@ -81,10 +81,17 @@ export default class ServerTypeSelector extends React.PureComponent { constructor(props) { super(props); - const { defaultHsUrl } = props; + const { + defaultHsUrl, + onChange, + } = props; + const type = getDefaultType(defaultHsUrl); this.state = { - selected: getDefaultType(defaultHsUrl), + selected: type, }; + if (onChange) { + onChange(type); + } } updateSelectedType(type) { @@ -108,7 +115,8 @@ export default class ServerTypeSelector extends React.PureComponent { render() { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); - const serverTypes = TYPES.map(type => { + const serverTypes = []; + for (const type of Object.values(TYPES)) { const { id, label, logo, description } = type; const classes = classnames( "mx_ServerTypeSelector_type", @@ -118,7 +126,7 @@ export default class ServerTypeSelector extends React.PureComponent { }, ); - return
+ serverTypes.push(
{label()}
@@ -130,8 +138,8 @@ export default class ServerTypeSelector extends React.PureComponent { {description()}
-
; - }); +
); + } return
{serverTypes} From b1f698586eb5ff804c56b3fdf47b3e945bea5101 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 25 Jan 2019 23:36:36 -0600 Subject: [PATCH 10/22] Style SSO login like a button --- res/css/structures/auth/_Login.scss | 8 +++++--- src/components/structures/auth/Login.js | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss index 41c2cd1966..2102a1e321 100644 --- a/res/css/structures/auth/_Login.scss +++ b/res/css/structures/auth/_Login.scss @@ -45,6 +45,7 @@ limitations under the License. width: 100%; margin-top: 35px; margin-bottom: 24px; + box-sizing: border-box; } .mx_Login_submit:hover { @@ -65,10 +66,11 @@ limitations under the License. margin-right: 10px; } -.mx_Login_sso_link { - display: block; +.mx_AuthBody a.mx_Login_sso_link:link, +.mx_AuthBody a.mx_Login_sso_link:hover, +.mx_AuthBody a.mx_Login_sso_link:visited { + color: $button-primary-fg-color; text-align: center; - margin-bottom: 20px; } .mx_Login_loader { diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 6d61eac895..386c091bda 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -590,7 +590,7 @@ module.exports = React.createClass({ // user's browser, let them log into their SSO provider, then redirect their browser // to vector://vector which, of course, will not work. return ( - { _t('Sign in with single sign-on') } + { _t('Sign in with single sign-on') } ); }, From 3a698ef4fae2b111afb633899af30e182e956d5d Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Sat, 26 Jan 2019 00:25:00 -0600 Subject: [PATCH 11/22] Clean up Custom Server Help dialog --- .../views/auth/CustomServerDialog.js | 18 +++++++++--------- src/i18n/strings/en_EN.json | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/views/auth/CustomServerDialog.js b/src/components/views/auth/CustomServerDialog.js index 474a4097d1..228586e28d 100644 --- a/src/components/views/auth/CustomServerDialog.js +++ b/src/components/views/auth/CustomServerDialog.js @@ -27,17 +27,17 @@ module.exports = React.createClass({ { _t("Custom Server Options") }
- +

{ _t("You can use the custom server options to sign into other Matrix " + - "servers by specifying a different Home server URL.") } -
+ "servers by specifying a different homeserver URL.") } { _t("This allows you to use this app with an existing Matrix account on " + - "a different home server.") } -
-
- { _t("You can also set a custom identity server but this will typically prevent " + - "interaction with users based on email address.") } - + "a different homeserver.") } +

+

+ {_t("You can also set a custom identity server, but you won't be " + + "able to invite users by email address, or be invited by " + + "email address yourself.")} +

); - }, -}); + } +} From 7da5a55c7ea215b7ffa4b3454c556267ef447aaf Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 28 Jan 2019 21:50:49 -0600 Subject: [PATCH 21/22] Add space to CustomServerDialog, format like riot-web variant --- .../views/auth/CustomServerDialog.js | 22 +++++++++---------- src/i18n/strings/en_EN.json | 3 +-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/components/views/auth/CustomServerDialog.js b/src/components/views/auth/CustomServerDialog.js index 228586e28d..cb0ee93de9 100644 --- a/src/components/views/auth/CustomServerDialog.js +++ b/src/components/views/auth/CustomServerDialog.js @@ -27,17 +27,17 @@ module.exports = React.createClass({ { _t("Custom Server Options") }
-

- { _t("You can use the custom server options to sign into other Matrix " + - "servers by specifying a different homeserver URL.") } - { _t("This allows you to use this app with an existing Matrix account on " + - "a different homeserver.") } -

-

- {_t("You can also set a custom identity server, but you won't be " + - "able to invite users by email address, or be invited by " + - "email address yourself.")} -

+

{_t( + "You can use the custom server options to sign into other " + + "Matrix servers by specifying a different homeserver URL. This " + + "allows you to use this app with an existing Matrix account on a " + + "different homeserver.", + )}

+

{_t( + "You can also set a custom identity server, but you won't be " + + "able to invite users by email address, or be invited by email " + + "address yourself.", + )}