Skip to content

Commit 404356c

Browse files
committed
feat: implement help menu and some changes on user info menu
1 parent 634e524 commit 404356c

File tree

5 files changed

+197
-83
lines changed

5 files changed

+197
-83
lines changed

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ export {
1515
UploadFile,
1616
UPLOAD_FILE_STATUS_KEY,
1717
} from './inputs';
18-
export { UserInfo } from './menus';
18+
export { UserInfo, HelpMenu } from './menus';
1919
export { PrivateRoute, PublicRoute } from './misc';

src/menus/HelpMenu/HelpMenu.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import React, { useState } from 'react';
2+
import PropTypes from 'prop-types';
3+
import { Box, Menu, MenuItem, makeStyles, ClickAwayListener } from '@material-ui/core';
4+
import HelpOutlineIcon from '@material-ui/icons/HelpOutline';
5+
6+
const useStyles = makeStyles((theme) => ({
7+
menuTrigger: {
8+
backgroundRepeat: 'no-repeat',
9+
minWidth: '32px',
10+
height: '32px',
11+
backgroundSize: '32px',
12+
borderRadius: '50%',
13+
flexShrink: 0,
14+
transition: 'box-shadow ease-in-out 0.2s',
15+
'&:hover': {
16+
cursor: 'pointer',
17+
},
18+
display: 'flex',
19+
flexDirection: 'row',
20+
flexWrap: 'nowrap',
21+
justifyContent: 'center',
22+
alignItems: 'stretch',
23+
},
24+
menu: {
25+
transform: 'translate3d(0,30px,0) !important',
26+
},
27+
menuContainer: {
28+
display: 'flex',
29+
flexDirection: 'row',
30+
justifyContent: 'space-between',
31+
},
32+
link: {
33+
color: theme.palette.text.primary,
34+
},
35+
menuIcon: {
36+
color: theme.palette.primary.main,
37+
fontSize: 32,
38+
},
39+
}));
40+
41+
export const HelpMenu = (props) => {
42+
const classes = useStyles();
43+
const [isMenuOpen, setMenuOpen] = useState(false);
44+
const [anchorEl, setAnchorEl] = useState(null);
45+
46+
const handleClose = () => {
47+
setMenuOpen(false);
48+
};
49+
50+
const handleClick = (event) => {
51+
setAnchorEl(event.target);
52+
setMenuOpen(!isMenuOpen);
53+
};
54+
55+
const { documentationUrl, supportUrl, labels } = props;
56+
57+
return (
58+
<ClickAwayListener onClickAway={handleClose}>
59+
<div>
60+
<Box
61+
data-cy="help-menu"
62+
aria-haspopup="true"
63+
onClick={handleClick}
64+
className={`${classes.menuTrigger} ${isMenuOpen ? 'active' : ''}`}
65+
>
66+
<HelpOutlineIcon className={classes.menuIcon} />
67+
</Box>
68+
<Menu className={classes.menu} keepMounted anchorEl={anchorEl} open={isMenuOpen} onClose={handleClick}>
69+
{documentationUrl && (
70+
<MenuItem data-cy="download-documentation" className={classes.link} onClick={handleClick}>
71+
<a href={documentationUrl} className={classes.link} target="_blank" rel="noreferrer">
72+
{labels.documentation}
73+
</a>
74+
</MenuItem>
75+
)}
76+
{supportUrl && (
77+
<MenuItem data-cy="support" className={classes.link} onClick={handleClick}>
78+
<a href={supportUrl} className={classes.link} target="_blank" rel="noreferrer">
79+
{labels.support}
80+
</a>
81+
</MenuItem>
82+
)}
83+
</Menu>
84+
</div>
85+
</ClickAwayListener>
86+
);
87+
};
88+
89+
HelpMenu.propTypes = {
90+
/**
91+
* Documentation url
92+
*/
93+
documentationUrl: PropTypes.string,
94+
/**
95+
* Support page url
96+
*/
97+
supportUrl: PropTypes.string,
98+
/**
99+
* Component's labels:
100+
* Structure:
101+
* <pre>
102+
{
103+
documentation: 'string',
104+
suuport: 'string',
105+
}
106+
* </pre>
107+
*/
108+
labels: PropTypes.shape({
109+
documentation: PropTypes.string.isRequired,
110+
support: PropTypes.string,
111+
}),
112+
};
113+
114+
HelpMenu.defaultProps = {
115+
supportUrl: null,
116+
labels: {
117+
documentation: 'Documentation',
118+
support: 'Contact support',
119+
},
120+
};

src/menus/HelpMenu/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Copyright (c) Cosmo Tech.
2+
// Licensed under the MIT license.
3+
4+
export { HelpMenu } from './HelpMenu';

src/menus/UserInfo/UserInfo.js

Lines changed: 71 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import React, { useState } from 'react';
55
import PropTypes from 'prop-types';
6-
import { Box, Menu, MenuItem, makeStyles } from '@material-ui/core';
6+
import { Box, Menu, MenuItem, makeStyles, ClickAwayListener } from '@material-ui/core';
77
import { ArrowRight as ArrowRightIcon, Check as CheckIcon } from '@material-ui/icons';
88

99
const useStyles = makeStyles((theme) => ({
@@ -47,114 +47,106 @@ const useStyles = makeStyles((theme) => ({
4747
menuIcon: {
4848
marginLeft: '20px',
4949
},
50-
docLink: {
51-
color: theme.palette.primary.contrastText,
52-
},
5350
}));
5451

5552
export const UserInfo = (props) => {
5653
const classes = useStyles();
57-
const [isMenuOpened, setIsMenuOpened] = useState(false);
58-
const [isLangMenuOpened, setLangIsMenuOpened] = useState(false);
54+
const [isMenuOpen, setMenuOpen] = useState(false);
55+
const [isLanguageMenuOpen, setLanguangeMenuOpen] = useState(false);
5956
const [anchorEl, setAnchorEl] = useState(null);
6057
const [langAnchorEl, setLangAnchorEl] = useState(null);
6158

59+
const handleClose = () => {
60+
setMenuOpen(false);
61+
setLanguangeMenuOpen(false);
62+
};
63+
6264
const handleClick = (e) => {
6365
setAnchorEl(e.target);
64-
setIsMenuOpened(!isMenuOpened);
66+
setMenuOpen(!isMenuOpen);
6567
};
6668

6769
const handleLanguageMenuClick = (e) => {
6870
setLangAnchorEl(e.target);
69-
setLangIsMenuOpened(!isLangMenuOpened);
71+
setLanguangeMenuOpen(!isLanguageMenuOpen);
7072
};
7173

7274
const setLanguage = (lang) => {
73-
setIsMenuOpened(false);
74-
setLangIsMenuOpened(false);
7575
changeLanguage(lang);
76+
handleClose();
7677
};
7778

78-
const { userName, profilePlaceholder, languages, documentationUrl, onLogout, changeLanguage, language, labels } =
79-
props;
79+
const { userName, profilePlaceholder, languages, onLogout, changeLanguage, language, labels } = props;
8080

8181
return (
82-
<React.Fragment>
83-
<Box
84-
data-cy="user-profile-menu"
85-
aria-controls="user-profile-button"
86-
aria-haspopup="true"
87-
onClick={handleClick}
88-
className={`${classes.menuTrigger} ${isMenuOpened ? 'active' : ''}`}
89-
>
90-
<img className={classes.profilePic} src={profilePlaceholder} />
91-
<span className={classes.userName}>{userName}</span>
92-
</Box>
93-
<Menu
94-
className={classes.menu}
95-
data-cy="main-menu"
96-
keepMounted
97-
anchorEl={anchorEl}
98-
open={isMenuOpened}
99-
onClose={handleClick}
100-
>
101-
{languages && (
102-
<MenuItem data-cy="change-language" onClick={handleLanguageMenuClick} className={classes.menuContainer}>
103-
{labels.language}
104-
<ArrowRightIcon className={classes.menuIcon} />
105-
</MenuItem>
106-
)}
107-
{documentationUrl && (
108-
<MenuItem data-cy="download-documentation">
109-
<a href={documentationUrl} className={classes.docLink} target="_blank" rel="noreferrer">
110-
{labels.documentation}
111-
</a>
112-
</MenuItem>
113-
)}
114-
<MenuItem data-cy="logout" onClick={onLogout}>
115-
{labels.logOut}
116-
</MenuItem>
117-
</Menu>
118-
{languages && (
82+
<ClickAwayListener onClickAway={handleClose}>
83+
<div>
84+
<Box
85+
data-cy="user-profile-menu"
86+
aria-controls="user-profile-button"
87+
aria-haspopup="true"
88+
onClick={handleClick}
89+
className={`${classes.menuTrigger} ${isMenuOpen ? 'active' : ''}`}
90+
>
91+
<img className={classes.profilePic} src={profilePlaceholder} />
92+
<span className={classes.userName}>{userName}</span>
93+
</Box>
94+
11995
<Menu
12096
className={classes.menu}
121-
id="simple-menu"
97+
data-cy="main-menu"
12298
keepMounted
123-
anchorEl={langAnchorEl}
124-
getContentAnchorEl={null}
125-
anchorOrigin={{ vertical: 'top', horizontal: 'left' }}
126-
transformOrigin={{ vertical: 'center', horizontal: 'right' }}
127-
open={isLangMenuOpened}
128-
onClose={handleLanguageMenuClick}
99+
anchorEl={anchorEl}
100+
open={isMenuOpen}
101+
onClose={handleClick}
129102
>
130-
{
131-
// Language menu items
132-
Object.entries(languages).map(([langKey, langLabel]) => (
133-
<MenuItem
134-
data-cy={'set-lang-' + langKey}
135-
key={langKey}
136-
onClick={() => setLanguage(langKey)}
137-
className={classes.menuContainer}
138-
>
139-
{langLabel}
140-
{
141-
// Add a check mark for the currently selected language
142-
langKey === language && <CheckIcon className={classes.menuIcon} />
143-
}
144-
</MenuItem>
145-
))
146-
}
103+
{languages && (
104+
<MenuItem data-cy="change-language" onClick={handleLanguageMenuClick} className={classes.menuContainer}>
105+
{labels.language}
106+
<ArrowRightIcon className={classes.menuIcon} />
107+
</MenuItem>
108+
)}
109+
<MenuItem data-cy="logout" onClick={onLogout}>
110+
{labels.logOut}
111+
</MenuItem>
147112
</Menu>
148-
)}
149-
</React.Fragment>
113+
{languages && (
114+
<Menu
115+
className={classes.menu}
116+
id="simple-menu"
117+
keepMounted
118+
anchorEl={langAnchorEl}
119+
getContentAnchorEl={null}
120+
anchorOrigin={{ vertical: 'top', horizontal: 'left' }}
121+
transformOrigin={{ vertical: 'center', horizontal: 'right' }}
122+
open={isLanguageMenuOpen}
123+
onClose={handleLanguageMenuClick}
124+
>
125+
{
126+
// Language menu items
127+
Object.entries(languages).map(([langKey, langLabel]) => (
128+
<MenuItem
129+
data-cy={'set-lang-' + langKey}
130+
key={langKey}
131+
onClick={() => setLanguage(langKey)}
132+
className={classes.menuContainer}
133+
>
134+
{langLabel}
135+
{
136+
// Add a check mark for the currently selected language
137+
langKey === language && <CheckIcon className={classes.menuIcon} />
138+
}
139+
</MenuItem>
140+
))
141+
}
142+
</Menu>
143+
)}
144+
</div>
145+
</ClickAwayListener>
150146
);
151147
};
152148

153149
UserInfo.propTypes = {
154-
/**
155-
* Documentation url
156-
*/
157-
documentationUrl: PropTypes.string,
158150
/**
159151
* List of available languages
160152
*/
@@ -185,14 +177,12 @@ UserInfo.propTypes = {
185177
* <pre>
186178
{
187179
language: 'string',
188-
documentation: 'string',
189180
logOut: 'string'
190181
}
191182
* </pre>
192183
*/
193184
labels: PropTypes.shape({
194185
language: PropTypes.string.isRequired,
195-
documentation: PropTypes.string.isRequired,
196186
logOut: PropTypes.string.isRequired,
197187
}),
198188
};
@@ -201,7 +191,6 @@ UserInfo.defaultProps = {
201191
profilePictureUrl: '../../assets/profile_placeholder.png',
202192
labels: {
203193
language: 'Change language',
204-
documentation: 'Download documentation',
205194
logOut: 'Log out',
206195
},
207196
};

src/menus/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
// Licensed under the MIT license.
33

44
export { UserInfo } from './UserInfo';
5+
export { HelpMenu } from './HelpMenu';

0 commit comments

Comments
 (0)