Commit 56bf1abe authored by Matija Obreza's avatar Matija Obreza

Merge branch '240-user-and-language-menu-update' into 'master'

User and language menu update

Closes #243 and #240

See merge request genesys-pgr/genesys-ui!252
parents 0f0eb05f b8908798
......@@ -73,7 +73,9 @@ export const createPureApiCaller = (method) => {
} else {
log(`Call failed. Err: ${err}`);
dispatch(showSnackbar(`API error: ${err.message} ${err.response.data.error || ''}`));
throw new Error(`API error: ${err}`);
const errorMessage = (err.response && err.response.data && err.response.data.error_description) ?
err.response.data.error_description : `API error ${err}`;
throw new Error(errorMessage);
}
});
};
......
import { COLLAPSE_SIDEBAR } from 'constants/layout';
import { COLLAPSE_SIDEBAR, LOGIN_MENU_FOCUS } from 'constants/layout';
export const collapseSidebar = (isOpen: boolean) => (dispatch) => {
dispatch({type: COLLAPSE_SIDEBAR, payload: isOpen});
};
export const loginMenuFocus = (isFocused: boolean) => (dispatch) => {
dispatch({type: LOGIN_MENU_FOCUS, payload: isFocused});
};
export const COLLAPSE_SIDEBAR = 'COLLAPSE_SIDEBAR';
export const LOGIN_MENU_FOCUS = 'LOGIN_MENU_FOCUS';
......@@ -4,17 +4,16 @@ import { withStyles} from '@material-ui/core/styles';
import languages from 'data/Languages';
import { withRouter } from 'react-router-dom';
import Button from '@material-ui/core/Button';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import ArrowDropDown from '@material-ui/icons/ArrowDropDown';
import { translate } from 'react-i18next';
import { LinkMenuItem, CollapsibleMenu } from 'ui/layout/headers/v1/MenuItem';
interface ILanguageListProps extends React.ClassAttributes<any> {
classes: any;
i18n: any;
location: any;
color?: any;
theme?: any;
}
const styles = {
......@@ -22,12 +21,13 @@ const styles = {
langMenuBtn: {
minWidth: '48px',
fontSize: '1.14rem',
height: '100%',
paddingRight: 0,
textTransform: 'capitalize' as 'capitalize',
'&:hover': {
background: 'inherit',
color: '#88ba42',
// color: '#88ba42',
textDecoration: 'none',
},
'html[dir="rtl"] &' : {
......@@ -35,42 +35,19 @@ const styles = {
paddingRight: '16px !important',
},
},
menu: {
'& > div+div': {
top: '3.57rem !important',
'html[dir="ltr"] &' : {
left: 'auto !important',
right: '1.43rem',
},
'html[dir="rtl"] &' : {
right: 'auto !important',
left: '1.43rem',
},
},
'& ul': {
padding: '0.71rem 0',
'& a:focus': {
outline: 'none',
textDecoration: 'none',
background: '#e7e5df',
},
'& li': {
paddingLeft: '1.43rem',
fontFamily: 'Roboto-Regular',
fontSize: '1rem',
color: '#2B2924',
'&:hover, &:focus': {
background: '#e7e5df',
},
},
},
root: {
height: '100%',
position: 'relative' as 'relative',
overflowX: 'visible' as 'visible',
},
menuPosition: {
right: 0,
marginTop: 0,
'html[dir="rtl"] &' : {
left: 0,
right: 'auto',
},
}
};
class LanguageList extends React.Component<ILanguageListProps, any> {
......@@ -79,22 +56,24 @@ class LanguageList extends React.Component<ILanguageListProps, any> {
super(props);
this.state = {
anchorEl: null,
open: false,
};
}
public handleClick = (event) => {
this.setState({ open: true, anchorEl: event.currentTarget });
}
private toggleDrawer = (flag) => {
this.setState({open: flag});
};
private openMenu = () => this.toggleDrawer(true);
public handleRequestClose = () => {
this.setState({ open: false });
private closeMenu = () => this.toggleDrawer(false);
private handleClick = () => {
this.state.open ? this.closeMenu() : this.openMenu();
}
public render() {
const { classes, i18n, color, location } = this.props;
const { classes, i18n, color, location, theme } = this.props;
let currentLang = i18n.language;
languages.some((item, i, arr) => {
if (item.short === i18n.language) {
......@@ -108,31 +87,32 @@ class LanguageList extends React.Component<ILanguageListProps, any> {
};
return (
<div>
<div
className={classes.root}
onMouseEnter={ this.openMenu } onMouseLeave={ this.closeMenu }
onClick={ this.handleClick }
>
<Button
className={ classes.langMenuBtn }
color={ color ? color : 'secondary' }
aria-owns={ this.state.open ? 'lang-list' : null }
aria-haspopup="true"
onClick={ this.handleClick }
>
{ currentLang }
<ArrowDropDown style={ arrow } viewBox="0 0 16 24"/>
</Button>
<Menu
className={ classes.menu }
id="lang-list"
anchorEl={ this.state.anchorEl }
open={ this.state.open }
onClose={ this.handleRequestClose }
>
<CollapsibleMenu className={ classes.menuPosition } open={ this.state.open } theme={ theme }>
{
// Using <a href="ru/" will reload app from server
languages.map((lang, index) => (
<a key={ (lang.short) } href={ `${lang.short === 'en' ? '' : lang.short}${location.pathname}` }><MenuItem>{ `${lang.label}` }</MenuItem></a>
languages.map((lang) => (
<LinkMenuItem
key={ (lang.short) }
href={ `${lang.short === 'en' ? '' : lang.short}${location.pathname}` }
label={ lang.label }
theme={ theme }
/>
))
}
</Menu>
</CollapsibleMenu>
</div>
);
}
......
import * as React from 'react';
import {withStyles} from '@material-ui/core/styles';
import {translate} from 'react-i18next';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import { loginAction, googleLogin } from 'user/actions/public';
import { loginMenuFocus } from 'actions/layout';
import {Link} from 'react-router-dom';
import Button from '@material-ui/core/Button';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import ArrowDropDown from '@material-ui/icons/ArrowDropDown';
import { LinkMenuItem, CollapsibleMenu } from 'ui/layout/headers/v1/MenuItem';
import LoginForm from 'user/ui/c/LoginForm';
interface IUserLoginMenuProps extends React.ClassAttributes<any> {
classes: any;
t: any;
theme: any;
loginAction: (u, p) => Promise<any>;
googleLogin: (aT) => Promise<any>;
history: any;
googleClientId: string;
loginMenuIsFocused: boolean;
loginMenuFocus?: (isFocused: boolean) => void;
}
const styles = {
......@@ -18,7 +29,7 @@ const styles = {
userMenuBtn: {
padding: 0,
minWidth: '48px',
height: '100%',
'&:hover': {
background: 'inherit',
},
......@@ -32,94 +43,109 @@ const styles = {
textDecoration: 'none',
},
},
menu: {
'& > div+div': {
top: '3.57rem !important',
'html[dir="ltr"] &': {
left: 'auto !important',
right: '1.43rem',
},
'html[dir="rtl"] &': {
right: 'auto !important',
left: '1.43rem',
},
},
'& ul': {
padding: '0.71rem 0',
'& a:focus': {
outline: 'none',
textDecoration: 'none',
},
'& li': {
paddingLeft: '1.43rem',
fontFamily: 'Roboto-Regular',
fontSize: '1rem',
color: '#2B2924',
'&:hover, &:focus': {
background: '#E7E5DF',
},
},
},
root: {
height: '100%',
position: 'relative' as 'relative',
overflowX: 'visible' as 'visible',
},
menuPosition: {
right: 0,
marginTop: 0,
'html[dir="rtl"] &' : {
left: 0,
},
}
};
class UserLoginMenu extends React.Component<IUserLoginMenuProps, any> {
public handleClick = (event) => {
this.setState({open: true, anchorEl: event.currentTarget});
};
public handleRequestClose = () => {
this.setState({open: false});
};
public constructor(props: any) {
super(props);
this.state = {
anchorEl: null,
open: false,
mouseIn: false,
};
}
private toggleDrawer = (flag) => {
this.setState({open: flag});
}
private openMenu = () => this.toggleDrawer(true);
private closeMenu = () => this.toggleDrawer(false);
private handleClick = () => {
this.state.open ? this.closeMenu() : this.openMenu();
}
private onMouseLeave = () => {
this.setState({mouseIn: false});
if ( !this.props.loginMenuIsFocused) {
this.closeMenu();
}
}
private onMouseEnter = () => {
this.setState({mouseIn: true});
this.openMenu();
}
public render() {
const {classes, t} = this.props;
const { classes, t, theme, loginAction, googleLogin, loginMenuFocus, loginMenuIsFocused } = this.props;
const arrow = {
verticalAlign: 'middle',
};
return (
<div>
<div
className={classes.root}
onMouseEnter={ this.onMouseEnter }
onMouseLeave={ this.onMouseLeave }
>
<Button
className={ `${classes.userMenuBtn} ${classes.linkLogin} mr-10 ml-10` }
color="secondary"
aria-owns={this.state.open ? 'user-menu' : null}
aria-haspopup="true"
onClick={this.handleClick}
onClick={ this.handleClick }
>
{t('common.menu.login')}
<ArrowDropDown style={arrow} viewBox="0 0 16 24"/>
</Button>
<Menu
className={classes.menu}
id="user-menu"
anchorEl={this.state.anchorEl}
open={this.state.open}
onClose={this.handleRequestClose}
onClick={this.handleRequestClose}
<CollapsibleMenu
className={ classes.menuPosition }
open={ this.state.open && ( loginMenuIsFocused || this.state.mouseIn ) }
theme={ theme }
>
<Link to="/login"><MenuItem>{t('common.menu.login')}</MenuItem></Link>
<Link to="/registration"><MenuItem>{t('common.menu.register')}</MenuItem></Link>
</Menu>
<LoginForm
loginMenuFocus={ loginMenuFocus }
onTryLogin={ loginAction }
onTryGoogleLogin={ googleLogin }
googleClientId={ this.props.googleClientId }
theme={theme}
inMenu
/>
<LinkMenuItem label="common.menu.register" to="/registration" theme={ theme }/>
</CollapsibleMenu>
</div>
);
}
}
export default translate()(withStyles(styles)(UserLoginMenu));
const mapStateToProps = (state) => ({
login: state.login,
googleClientId: state.applicationConfig.googleClientId,
loginMenuIsFocused: state.user.public.loginMenuIsFocused,
});
const mapDispatchToProps = (dispatch) => bindActionCreators({
loginAction,
googleLogin,
loginMenuFocus
}, dispatch);
export default translate()(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(UserLoginMenu)));
......@@ -2,13 +2,11 @@ import * as React from 'react';
import { withStyles } from '@material-ui/core/styles';
import { translate } from 'react-i18next';
import { Link } from 'react-router-dom';
import Button from '@material-ui/core/Button';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import AccountCircle from '@material-ui/icons/AccountCircle';
import ArrowDropDown from '@material-ui/icons/ArrowDropDown';
import Authorize from 'ui/common/authorized/Authorize';
import { LinkMenuItem, CollapsibleMenu, ActionMenuItem } from 'ui/layout/headers/v1/MenuItem';
interface IUserMenuProps extends React.ClassAttributes<any> {
classes: any;
......@@ -16,53 +14,33 @@ interface IUserMenuProps extends React.ClassAttributes<any> {
userName: string;
t: any;
color?: any;
theme?: any;
}
const styles = {
/* tslint:disable */
userMenuBtn: {
padding: 0,
height: '100%',
minWidth: '48px',
'&:hover': {
background: 'inherit',
},
},
menu: {
'& > div+div': {
top: '3.57rem !important',
'html[dir="ltr"] &' : {
left: 'auto !important',
right: '1.43rem',
},
'html[dir="rtl"] &' : {
right: 'auto !important',
left: '1.43rem',
},
},
'& ul': {
padding: '0.71rem 0',
'& a:focus': {
outline: 'none',
textDecoration: 'none',
},
'& li': {
paddingLeft: '1.43rem',
fontFamily: 'Roboto-Regular',
fontSize: '1rem',
color: '#2B2924',
'&:hover, &:focus': {
background: '#E7E5DF',
},
},
},
root: {
height: '100%',
position: 'relative' as 'relative',
overflowX: 'visible' as 'visible',
},
menuPosition: {
right: 0,
marginTop: 0,
'html[dir="rtl"] &' : {
left: 0,
right: 'auto',
},
}
};
class UserMenu extends React.Component<IUserMenuProps, any> {
......@@ -71,52 +49,50 @@ class UserMenu extends React.Component<IUserMenuProps, any> {
super(props);
this.state = {
anchorEl: null,
open: false,
};
}
public handleClick = (event) => {
this.setState({ open: true, anchorEl: event.currentTarget });
}
private toggleDrawer = (flag) => {
this.setState({open: flag});
};
public handleRequestClose = () => {
this.setState({ open: false });
private openMenu = () => this.toggleDrawer(true);
private closeMenu = () => this.toggleDrawer(false);
private handleClick = () => {
this.state.open ? this.closeMenu() : this.openMenu();
}
public render() {
const { logoutRequest, classes, t, color } = this.props;
const { logoutRequest, classes, color, theme } = this.props;
const arrow = {
verticalAlign: 'middle',
};
return (
<div>
<div
className={classes.root}
onMouseEnter={ this.openMenu } onMouseLeave={ this.closeMenu }
onClick={ this.handleClick }
>
<Button
className={ classes.userMenuBtn }
color={ color ? color : 'secondary' }
aria-owns={ this.state.open ? 'user-menu' : null }
aria-haspopup="true"
onClick={ this.handleClick }
>
<AccountCircle/>
<ArrowDropDown style={ arrow } viewBox="0 0 16 24"/>
</Button>
<Menu
className={ classes.menu }
id="user-menu"
anchorEl={ this.state.anchorEl }
open={ this.state.open }
onClose={ this.handleRequestClose }
onClick={ this.handleRequestClose }
>
<CollapsibleMenu className={ classes.menuPosition } open={ this.state.open } theme={ theme }>
<Authorize role={ "ROLE_ADMINISTRATOR" }>
<Link to="/admin/"><MenuItem>{ t('common.menu.Admin') }</MenuItem></Link>
<LinkMenuItem label="common.menu.Admin" to="/admin/" theme={ theme }/>
</Authorize>
<Link to="/dashboard"><MenuItem>{ t('common.menu.My Dashboard') }</MenuItem></Link>
<MenuItem onClick={ logoutRequest } >{ t('common:action.logout') }</MenuItem>
</Menu>
<LinkMenuItem label="common.menu.My Dashboard" to="/dashboard" theme={ theme }/>
<ActionMenuItem label="common:action.logout" action={ logoutRequest } theme={ theme }/>
</CollapsibleMenu>
</div>
);
}
......
......@@ -39,15 +39,27 @@ const style = (theme) => ({
fontSize: '1.25rem',
fontWeight: 'bold' as 'bold',
},
action: {
display: 'flex',
alignItems: 'center',
padding: '0 1.42rem',
outline: 'none',
fontSize: '1.14rem',
fontWeight: 'bold' as 'bold',
cursor: 'pointer' as 'pointer',
userSelect: 'none' as 'none',
},
children: {
'& > div > a > div > span': {
fontSize: '1.14rem',
},
'& > div': {
backgroundColor: 'rgba(0, 0, 0, 0.07)', // '#eeede7',
},
'& > div, & > form > div': {
height: '3rem',
borderTop: 'solid 1px transparent',
borderBottom: 'solid 1px #929292',
backgroundColor: 'rgba(0, 0, 0, 0.07)', // '#eeede7',
transition: 'all 0.1s',
'&:hover': {
backgroundColor: 'rgba(0, 0, 0, 0.245)', //'#c3c0b0',
......@@ -120,11 +132,9 @@ class MenuItem extends React.Component<IMenuItemProps, any> {
</div>
</Link>
{ children &&
<Collapse className={ classes.collapsed } in={ this.state.open }>
<div className={ `${classes.children} ${this.state.open && classes.open}` } style={ {backgroundColor: `${theme.subItem}`, color: theme.subItemText} }>
{ children }
</div>
</Collapse>
<CollapsibleMenuWrapper classes={ classes } open={ this.state.open } theme={ theme }>
{ children }
</CollapsibleMenuWrapper>
}
</div>
</Authorize>
......@@ -132,4 +142,51 @@ class MenuItem extends React.Component<IMenuItemProps, any> {
}
}
const LinkItem = ({ classes, t, to, label, theme, href }: {classes: any, t: any, to?: string,