diff --git a/src/components/accounts/AccountSwitcher.js b/src/components/accounts/AccountSwitcher.js index a29b0b1..36e369f 100644 --- a/src/components/accounts/AccountSwitcher.js +++ b/src/components/accounts/AccountSwitcher.js @@ -28,7 +28,7 @@ export class AccountSwitcher extends Component { id: PropTypes.number })) }), - user: userShape, // TODO: remove me, when we will be sure, that accounts.active is always set for user + user: userShape, // TODO: remove me, when we will be sure, that accounts.active is always set for user (event after register) skin: PropTypes.oneOf(skins), highlightActiveAccount: PropTypes.bool, // whether active account should be expanded and shown on the top allowLogout: PropTypes.bool, // whether to show logout icon near each account @@ -46,7 +46,8 @@ export class AccountSwitcher extends Component { render() { const { accounts, skin, allowAdd, allowLogout, highlightActiveAccount } = this.props; - const activeAccount = accounts.active || this.props.user; + // const activeAccount = accounts.active || this.props.user; + const activeAccount = this.props.user; let {available} = accounts; @@ -163,8 +164,7 @@ import { authenticate, revoke } from 'components/accounts/actions'; export default connect(({accounts, user}) => ({ accounts, - user, - userLang: user.lang // this is to force re-render on lang change + user }), { switchAccount: authenticate, removeAccount: revoke diff --git a/src/components/user/reducer.js b/src/components/user/reducer.js index da29117..c8b92f3 100644 --- a/src/components/user/reducer.js +++ b/src/components/user/reducer.js @@ -1,23 +1,25 @@ +// @flow import { UPDATE, SET, CHANGE_LANG } from './actions'; export type User = { - id: number, - uuid: string, + id: ?number, + uuid: ?string, token: string, username: string, email: string, avatar: string, isGuest: boolean, isActive: boolean, - passwordChangedAt: number, + passwordChangedAt: ?number, hasMojangUsernameCollision: bool, }; -const defaults = { +const defaults: User = { id: null, uuid: null, username: '', + token: '', email: '', // will contain user's email or masked email // (e.g. ex**ple@em*il.c**) depending on what information user have already provided @@ -35,8 +37,8 @@ const defaults = { }; export default function user( - state = null, - {type, payload = null} + state: User = defaults, + {type, payload}: {type: string, payload: ?Object} ) { switch (type) { case CHANGE_LANG: diff --git a/src/components/userbar/LoggedInPanel.js b/src/components/userbar/LoggedInPanel.js index adad7d5..882148a 100644 --- a/src/components/userbar/LoggedInPanel.js +++ b/src/components/userbar/LoggedInPanel.js @@ -1,5 +1,5 @@ +// @flow import React, { Component } from 'react'; -import ReactDOM from 'react-dom'; import classNames from 'classnames'; @@ -7,25 +7,33 @@ import { AccountSwitcher } from 'components/accounts'; import styles from './loggedInPanel.scss'; -import { userShape } from 'components/user/User'; +import type { User } from 'components/user'; export default class LoggedInPanel extends Component { - static displayName = 'LoggedInPanel'; - static propTypes = { - user: userShape + props: { + user: User }; state = { isAccountSwitcherActive: false }; + _isMounted: boolean = false; + el: ?HTMLElement; + componentDidMount() { - document.addEventListener('click', this.onBodyClick); + if (window.document) { + window.document.addEventListener('click', this.onBodyClick); + } + this._isMounted = true; } componentWillUnmount() { - document.removeEventListener('click', this.onBodyClick); + if (window.document) { + window.document.removeEventListener('click', this.onBodyClick); + } + this._isMounted = false; } @@ -34,7 +42,7 @@ export default class LoggedInPanel extends Component { const { isAccountSwitcherActive } = this.state; return ( -
+
this.el = el} className={classNames(styles.loggedInPanel)}>
@@ -45,7 +53,7 @@ export default class LoggedInPanel extends Component {
- +
@@ -56,14 +64,18 @@ export default class LoggedInPanel extends Component { isAccountSwitcherActive: !this.state.isAccountSwitcherActive }); - onExpandAccountSwitcher = (event) => { + onToggleAccountSwitcher = () => { + this.toggleAccountSwitcher(); + }; + + onExpandAccountSwitcher = (event: Event) => { event.preventDefault(); this.toggleAccountSwitcher(); }; onBodyClick = createOnOutsideComponentClickHandler( - () => ReactDOM.findDOMNode(this), + () => this.el, () => this.state.isAccountSwitcherActive && this._isMounted, () => this.toggleAccountSwitcher() ); @@ -81,15 +93,19 @@ export default class LoggedInPanel extends Component { * * @return {function} */ -function createOnOutsideComponentClickHandler(getEl, isActive, callback) { +function createOnOutsideComponentClickHandler( + getEl: () => ?HTMLElement, + isActive: () => boolean, + callback: Function +) { // TODO: we have the same logic in LangMenu // Probably we should decouple this into some helper function // TODO: the name of function may be better... - return (event) => { - if (isActive()) { - const el = getEl(); + return (event: MouseEvent & {target: HTMLElement}) => { + const el = getEl(); - if (!el.contains(event.target) && el !== event.taget) { + if (isActive() && el) { + if (!el.contains(event.target) && el !== event.target) { event.preventDefault(); // add a small delay for the case someone have alredy called toggle