mirror of
https://github.com/elyby/accounts-frontend.git
synced 2025-05-31 14:11:58 +05:30
Create app namespace for all absolute requires of app modules. Move all packages under packages yarn workspace
This commit is contained in:
3
packages/app/components/userbar/LoggedInPanel.intl.json
Normal file
3
packages/app/components/userbar/LoggedInPanel.intl.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"logout": "Logout"
|
||||
}
|
127
packages/app/components/userbar/LoggedInPanel.tsx
Normal file
127
packages/app/components/userbar/LoggedInPanel.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { AccountSwitcher } from 'app/components/accounts';
|
||||
|
||||
import styles from './loggedInPanel.scss';
|
||||
|
||||
export default class LoggedInPanel extends React.Component<
|
||||
{
|
||||
username: string;
|
||||
},
|
||||
{
|
||||
isAccountSwitcherActive: boolean;
|
||||
}
|
||||
> {
|
||||
state = {
|
||||
isAccountSwitcherActive: false,
|
||||
};
|
||||
|
||||
_isMounted: boolean = false;
|
||||
el: HTMLElement | null;
|
||||
|
||||
componentDidMount() {
|
||||
if (window.document) {
|
||||
window.document.addEventListener('click', this.onBodyClick);
|
||||
}
|
||||
|
||||
this._isMounted = true;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (window.document) {
|
||||
window.document.removeEventListener('click', this.onBodyClick);
|
||||
}
|
||||
|
||||
this._isMounted = false;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { username } = this.props;
|
||||
const { isAccountSwitcherActive } = this.state;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={el => (this.el = el)}
|
||||
className={classNames(styles.loggedInPanel)}
|
||||
>
|
||||
<div
|
||||
className={classNames(styles.activeAccount, {
|
||||
[styles.activeAccountExpanded]: isAccountSwitcherActive,
|
||||
})}
|
||||
>
|
||||
<button
|
||||
className={styles.activeAccountButton}
|
||||
onClick={this.onExpandAccountSwitcher}
|
||||
>
|
||||
<span className={styles.userIcon} />
|
||||
<span className={styles.userName}>{username}</span>
|
||||
<span className={styles.expandIcon} />
|
||||
</button>
|
||||
|
||||
<div className={classNames(styles.accountSwitcherContainer)}>
|
||||
<AccountSwitcher
|
||||
skin="light"
|
||||
onAfterAction={this.onToggleAccountSwitcher}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
toggleAccountSwitcher = () =>
|
||||
this._isMounted &&
|
||||
this.setState({
|
||||
isAccountSwitcherActive: !this.state.isAccountSwitcherActive,
|
||||
});
|
||||
|
||||
onToggleAccountSwitcher = () => {
|
||||
this.toggleAccountSwitcher();
|
||||
};
|
||||
|
||||
onExpandAccountSwitcher = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault();
|
||||
|
||||
this.toggleAccountSwitcher();
|
||||
};
|
||||
|
||||
onBodyClick = createOnOutsideComponentClickHandler(
|
||||
() => this.el,
|
||||
() => this.state.isAccountSwitcherActive && this._isMounted,
|
||||
() => this.toggleAccountSwitcher(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event handling function to handle clicks outside the component
|
||||
*
|
||||
* The handler will check if current click was outside container el and if so
|
||||
* and component isActive, it will call the callback
|
||||
*
|
||||
* @param {Function} getEl - the function, that returns reference to container el
|
||||
* @param {Function} isActive - whether the component is active and callback may be called
|
||||
* @param {Function} callback - the callback to call, when there was a click outside el
|
||||
*
|
||||
* @returns {Function}
|
||||
*/
|
||||
function createOnOutsideComponentClickHandler(
|
||||
getEl: () => HTMLElement | null,
|
||||
isActive: () => boolean,
|
||||
callback: () => void,
|
||||
) {
|
||||
// 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: { target: HTMLElement } & MouseEvent) => {
|
||||
const el = getEl();
|
||||
|
||||
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
|
||||
setTimeout(() => isActive() && callback(), 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
4
packages/app/components/userbar/Userbar.intl.json
Normal file
4
packages/app/components/userbar/Userbar.intl.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"register": "Join",
|
||||
"login": "Sign in"
|
||||
}
|
50
packages/app/components/userbar/Userbar.tsx
Normal file
50
packages/app/components/userbar/Userbar.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { FormattedMessage as Message } from 'react-intl';
|
||||
import { Account } from 'app/components/accounts/reducer';
|
||||
import buttons from 'app/components/ui/buttons.scss';
|
||||
|
||||
import messages from './Userbar.intl.json';
|
||||
import styles from './userbar.scss';
|
||||
import LoggedInPanel from './LoggedInPanel';
|
||||
|
||||
export default class Userbar extends Component<{
|
||||
account: Account | null;
|
||||
guestAction: 'register' | 'login';
|
||||
}> {
|
||||
static displayName = 'Userbar';
|
||||
|
||||
static defaultProps = {
|
||||
guestAction: 'register',
|
||||
};
|
||||
|
||||
render() {
|
||||
const { account, guestAction: actionType } = this.props;
|
||||
|
||||
let guestAction: React.ReactElement;
|
||||
|
||||
switch (actionType) {
|
||||
case 'login':
|
||||
guestAction = (
|
||||
<Link to="/login" className={buttons.blue}>
|
||||
<Message {...messages.login} />
|
||||
</Link>
|
||||
);
|
||||
break;
|
||||
case 'register':
|
||||
default:
|
||||
guestAction = (
|
||||
<Link to="/register" className={buttons.blue}>
|
||||
<Message {...messages.register} />
|
||||
</Link>
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.userbar}>
|
||||
{account ? <LoggedInPanel username={account.username} /> : guestAction}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
61
packages/app/components/userbar/loggedInPanel.scss
Normal file
61
packages/app/components/userbar/loggedInPanel.scss
Normal file
@@ -0,0 +1,61 @@
|
||||
@import '~app/components/ui/colors.scss';
|
||||
|
||||
.loggedInPanel {
|
||||
}
|
||||
|
||||
.activeAccount {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
$border: 1px solid rgba(#fff, 0.15);
|
||||
border-left: $border;
|
||||
border-right: $border;
|
||||
}
|
||||
|
||||
.activeAccountButton {
|
||||
composes: green from '~app/components/ui/buttons.scss';
|
||||
}
|
||||
|
||||
.activeAccountExpanded {
|
||||
.activeAccountButton {
|
||||
background-color: darker($green);
|
||||
}
|
||||
|
||||
.accountSwitcherContainer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.expandIcon {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.userIcon {
|
||||
composes: user from '~app/components/ui/icons.scss';
|
||||
|
||||
position: relative;
|
||||
bottom: 2px;
|
||||
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.expandIcon {
|
||||
composes: caret from '~app/components/ui/icons.scss';
|
||||
|
||||
margin-left: 4px;
|
||||
font-size: 6px;
|
||||
color: #ccc;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.userName {
|
||||
}
|
||||
|
||||
.accountSwitcherContainer {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: -2px;
|
||||
cursor: auto;
|
||||
|
||||
display: none;
|
||||
}
|
3
packages/app/components/userbar/userbar.scss
Normal file
3
packages/app/components/userbar/userbar.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
.userbar {
|
||||
text-align: right;
|
||||
}
|
Reference in New Issue
Block a user