From 1c88c9ea3092e62ab4b3e8940ce5079619306aaf Mon Sep 17 00:00:00 2001 From: Honza Pokorny Date: Fri, 3 Mar 2017 14:58:20 -0400 Subject: [PATCH] Add language switcher to login page Closes-Bug: #1667064 Change-Id: Ifa5d8f3a19b77ddfe0a8e3b0d1dba61582065719 --- .../notes/i18n-login-e5464553686d53c8.yaml | 5 ++ src/__tests__/components/Login.tests.js | 2 +- src/js/components/App.js | 2 +- src/js/components/i18n/I18nDropdown.js | 34 ++++----- src/js/components/login/LanguageInput.js | 73 +++++++++++++++++++ src/js/components/{ => login}/Login.js | 44 ++++++++--- src/js/services/utils.js | 2 +- 7 files changed, 128 insertions(+), 34 deletions(-) create mode 100644 releasenotes/notes/i18n-login-e5464553686d53c8.yaml create mode 100644 src/js/components/login/LanguageInput.js rename src/js/components/{ => login}/Login.js (80%) diff --git a/releasenotes/notes/i18n-login-e5464553686d53c8.yaml b/releasenotes/notes/i18n-login-e5464553686d53c8.yaml new file mode 100644 index 00000000..e93b884f --- /dev/null +++ b/releasenotes/notes/i18n-login-e5464553686d53c8.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixes `bug 1667064 `__ + Add a language picker to the login page diff --git a/src/__tests__/components/Login.tests.js b/src/__tests__/components/Login.tests.js index 5d8b3daa..198f4c8b 100644 --- a/src/__tests__/components/Login.tests.js +++ b/src/__tests__/components/Login.tests.js @@ -17,7 +17,7 @@ import React from 'react'; import ReactTestUtils from 'react-dom/test-utils'; -import Login from '../../js/components/Login'; +import Login from '../../js/components/login/Login'; import LoginActions from '../../js/actions/LoginActions'; let loginInstance; diff --git a/src/js/components/App.js b/src/js/components/App.js index 1347c722..0515aa83 100644 --- a/src/js/components/App.js +++ b/src/js/components/App.js @@ -17,7 +17,7 @@ import React from 'react'; import { Route, Switch } from 'react-router-dom'; -import Login from './Login'; +import Login from './login/Login'; import UserAuthenticator from './UserAuthenticator'; export default class App extends React.Component { diff --git a/src/js/components/i18n/I18nDropdown.js b/src/js/components/i18n/I18nDropdown.js index 6a03af6a..cc0a6d2f 100644 --- a/src/js/components/i18n/I18nDropdown.js +++ b/src/js/components/i18n/I18nDropdown.js @@ -22,9 +22,9 @@ import React from 'react'; import Dropdown from '../ui/dropdown/Dropdown'; import DropdownToggle from '../ui/dropdown/DropdownToggle'; import DropdownItem from '../ui/dropdown/DropdownItem'; -import { getEnabledLanguages } from '../../services/utils'; import I18nActions from '../../actions/I18nActions'; import { MESSAGES } from './messages'; +import { getEnabledLanguages } from '../../services/utils'; const messages = defineMessages({ language: { @@ -35,25 +35,21 @@ const messages = defineMessages({ class I18nDropdown extends React.Component { _renderDropdownItems() { - const configLanguages = getEnabledLanguages(); - const langList = Object.keys(configLanguages).sort( - (a, b) => configLanguages[a] > configLanguages[b] - ); - const enabledLang = this.props.language; - - return langList.map(lang => { - const active = enabledLang === lang; - return MESSAGES[lang] || lang === 'en' - ? - {configLanguages[lang]} - - : null; - }); + return getEnabledLanguages() + .map((langName, langKey) => { + const active = enabledLang === langKey; + return MESSAGES[langKey] || langKey === 'en' + ? + {langName} + + : null; + }) + .toList(); } render() { diff --git a/src/js/components/login/LanguageInput.js b/src/js/components/login/LanguageInput.js new file mode 100644 index 00000000..696797a4 --- /dev/null +++ b/src/js/components/login/LanguageInput.js @@ -0,0 +1,73 @@ +/** + * Copyright 2017 Red Hat Inc. + * + * 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 { injectIntl } from 'react-intl'; +import { getEnabledLanguages } from '../../services/utils'; + +class LanguageInput extends React.Component { + _renderOptions() { + return getEnabledLanguages() + .map((langName, langKey) => { + return ( + + ); + }) + .toList(); + } + + _onChange(event) { + this.props.chooseLanguage(event.currentTarget.value); + } + + render() { + return ( +
+
+ ); + } +} + +LanguageInput.propTypes = { + autoFocus: PropTypes.bool, + chooseLanguage: PropTypes.func.isRequired, + language: PropTypes.string, + name: PropTypes.string.isRequired +}; + +LanguageInput.defaultProps = { + autoFocus: false +}; + +export default injectIntl(LanguageInput); diff --git a/src/js/components/Login.js b/src/js/components/login/Login.js similarity index 80% rename from src/js/components/Login.js rename to src/js/components/login/Login.js index aa7d1273..d11c96d9 100644 --- a/src/js/components/Login.js +++ b/src/js/components/login/Login.js @@ -23,14 +23,16 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Redirect } from 'react-router-dom'; -import FormErrorList from './ui/forms/FormErrorList'; -import Loader from './ui/Loader'; -import LoginInput from './ui/forms/LoginInput'; -import LoginActions from '../actions/LoginActions'; -import NotificationsToaster from './notifications/NotificationsToaster'; +import FormErrorList from '../ui/forms/FormErrorList'; +import I18nActions from '../../actions/I18nActions'; +import Loader from '../ui/Loader'; +import LoginInput from '../ui/forms/LoginInput'; +import LanguageInput from './LanguageInput'; +import LoginActions from '../../actions/LoginActions'; +import NotificationsToaster from '../notifications/NotificationsToaster'; -import LogoSvg from '../../img/logo.svg'; -import TripleoOwlSvg from '../../img/tripleo-owl.svg'; +import LogoSvg from '../../../img/logo.svg'; +import TripleoOwlSvg from '../../../img/tripleo-owl.svg'; const messages = defineMessages({ authenticating: { @@ -103,7 +105,7 @@ class Login extends React.Component { handleLogin(formData, resetForm, invalidateForm) { const formFields = Object.keys(this.refs.form.inputs); - this.props.dispatch(LoginActions.authenticateUser(formData, formFields)); + this.props.authenticateUser(formData, formFields); } render() { @@ -143,6 +145,11 @@ class Login extends React.Component { onValid={this._enableButton.bind(this)} onInvalid={this._disableButton.bind(this)} > + { + return { + chooseLanguage: language => dispatch(I18nActions.chooseLanguage(language)), + authenticateUser: (formData, formFields, nextPath) => + dispatch(LoginActions.authenticateUser(formData, formFields, nextPath)) + }; +}; + +export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(Login)); diff --git a/src/js/services/utils.js b/src/js/services/utils.js index 3978c6b9..777d3f39 100644 --- a/src/js/services/utils.js +++ b/src/js/services/utils.js @@ -70,5 +70,5 @@ export function getEnabledLanguages() { delete configLanguages[language]; }); - return configLanguages; + return Map(configLanguages).sort(); }