Skip to content

Commit

Permalink
feat: user profile preview (#7150)
Browse files Browse the repository at this point in the history
  • Loading branch information
kwasniew authored May 27, 2024
1 parent e5aa1a8 commit 02c0744
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ const ShowHide: FC<{ mode: 'full' | 'mini'; onChange: () => void }> = ({
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
margin: theme.spacing(2, 1, 0, 2),
margin: theme.spacing(2, 1, 0, mode === 'mini' ? 1 : 2),
})}
>
{mode === 'full' && (
Expand Down
15 changes: 14 additions & 1 deletion frontend/src/component/menu/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import { useState, type VFC } from 'react';
import useMediaQuery from '@mui/material/useMediaQuery';
import { useTheme } from '@mui/material/styles';
import { Link } from 'react-router-dom';
import { AppBar, Box, IconButton, styled, Tooltip } from '@mui/material';
import {
AppBar,
Box,
Divider,
IconButton,
styled,
Tooltip,
} from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu';
import UserProfile from 'component/user/UserProfile';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
Expand Down Expand Up @@ -226,6 +233,12 @@ const Header: VFC = () => {
<MenuBookIcon />
</StyledIconButton>
</Tooltip>
<Divider
orientation='vertical'
variant='middle'
flexItem
sx={{ ml: 1 }}
/>
<UserProfile />
</StyledUserContainer>
</StyledNav>
Expand Down
83 changes: 48 additions & 35 deletions frontend/src/component/user/UserProfile/UserProfile.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,72 @@
import { useState } from 'react';
import { ClickAwayListener, IconButton, Tooltip, styled } from '@mui/material';
import {
Box,
Button,
ClickAwayListener,
styled,
Typography,
} from '@mui/material';
import { UserProfileContent } from './UserProfileContent/UserProfileContent';
import type { IUser } from 'interfaces/user';
import { HEADER_USER_AVATAR } from 'utils/testIds';
import { useId } from 'hooks/useId';
import { UserAvatar } from 'component/common/UserAvatar/UserAvatar';
import { flexRow, itemsCenter } from 'themes/themeStyles';

const StyledUserAvatar = styled(UserAvatar)(({ theme }) => ({
width: theme.spacing(4.5),
height: theme.spacing(4.5),
}));
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import { HEADER_USER_AVATAR } from 'utils/testIds';

const StyledProfileContainer = styled('div')(({ theme }) => ({
position: 'relative',
}));

const StyledIconButton = styled(IconButton)(({ theme }) => ({
...flexRow,
...itemsCenter,
color: 'inherit',
padding: theme.spacing(1),
'&:focus-visible': {
outlineStyle: 'solid',
outlineWidth: 2,
outlineColor: theme.palette.primary.main,
borderRadius: '100%',
},
marginLeft: theme.spacing(2),
cursor: 'pointer',
}));

interface IUserProfileProps {
profile: IUser;
}

const StyledUserAvatar = styled(UserAvatar)(({ theme }) => ({
width: theme.spacing(4.75),
height: theme.spacing(4.75),
marginRight: theme.spacing(1.5),
}));

const StyledSubtitle = styled(Typography)(({ theme }) => ({
color: theme.palette.text.secondary,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
maxWidth: theme.spacing(35),
}));

const UserProfile = ({ profile }: IUserProfileProps) => {
const [showProfile, setShowProfile] = useState(false);
const modalId = useId();

return (
<ClickAwayListener onClickAway={() => setShowProfile(false)}>
<StyledProfileContainer>
<Tooltip title='Profile' arrow>
<StyledIconButton
onClick={() => setShowProfile((prev) => !prev)}
aria-controls={showProfile ? modalId : undefined}
aria-expanded={showProfile}
color='secondary'
size='large'
>
<StyledUserAvatar
user={profile}
data-testid={HEADER_USER_AVATAR}
/>
</StyledIconButton>
</Tooltip>
<Button
component={Box}
sx={{ display: 'flex', alignItems: 'center' }}
aria-controls={showProfile ? modalId : undefined}
aria-expanded={showProfile}
onClick={() => setShowProfile((prev) => !prev)}
>
<StyledUserAvatar
user={profile}
data-testid={HEADER_USER_AVATAR}
/>
<Box sx={{ mr: 3 }}>
<Typography>
{profile.name || profile.username}
</Typography>
<StyledSubtitle variant='body2' title={profile.email}>
{profile.email}
</StyledSubtitle>
</Box>
{showProfile ? <ExpandLessIcon /> : <ExpandMoreIcon />}
</Button>

<UserProfileContent
id={modalId}
showProfile={showProfile}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { Button, Paper, Typography, styled, Link } from '@mui/material';
import { Button, Link, Paper, styled } from '@mui/material';
import { basePath } from 'utils/formatPath';
import type { IUser } from 'interfaces/user';
import OpenInNew from '@mui/icons-material/OpenInNew';
import { Link as RouterLink } from 'react-router-dom';
import { UserAvatar } from 'component/common/UserAvatar/UserAvatar';

const StyledPaper = styled(Paper)(({ theme }) => ({
display: 'flex',
Expand All @@ -15,35 +14,15 @@ const StyledPaper = styled(Paper)(({ theme }) => ({
boxShadow: theme.boxShadows.popup,
position: 'absolute',
zIndex: 5000,
minWidth: theme.spacing(37.5),
minWidth: theme.spacing(34),
right: 0,
marginTop: theme.spacing(0.25),
[theme.breakpoints.down('md')]: {
width: '100%',
padding: '1rem',
},
}));

const StyledProfileInfo = styled('div')(({ theme }) => ({
alignSelf: 'flex-start',
display: 'flex',
alignItems: 'center',
marginBottom: theme.spacing(2),
}));

const StyledUserAvatar = styled(UserAvatar)(({ theme }) => ({
width: theme.spacing(4.75),
height: theme.spacing(4.75),
marginRight: theme.spacing(1.5),
}));

const StyledSubtitle = styled(Typography)(({ theme }) => ({
color: theme.palette.text.secondary,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
maxWidth: theme.spacing(35),
}));

const StyledLink = styled(Link<typeof RouterLink | 'a'>)(({ theme }) => ({
display: 'flex',
alignItems: 'center',
Expand Down Expand Up @@ -88,18 +67,6 @@ export const UserProfileContent = ({
condition={showProfile}
show={
<StyledPaper className='dropdown-outline' id={id}>
<StyledProfileInfo>
<StyledUserAvatar user={profile} />
<div>
<Typography>
{profile.name || profile.username}
</Typography>
<StyledSubtitle variant='body2' title={profile.email}>
{profile.email}
</StyledSubtitle>
</div>
</StyledProfileInfo>

<StyledLink
component={RouterLink}
to='/profile'
Expand Down

0 comments on commit 02c0744

Please sign in to comment.