Skip to content

Commit 8c1e2e8

Browse files
committed
feat: add collaborator avatar group component
Signed-off-by: amitamrutiya <amitamrutiya2210@gmail.com>
1 parent fa3c00f commit 8c1e2e8

3 files changed

Lines changed: 168 additions & 0 deletions

File tree

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { ExpandMore } from '@mui/icons-material';
2+
import { MouseEvent, useState } from 'react';
3+
import { Avatar, AvatarGroup, Popover, Typography } from '../../base';
4+
import { CLOUD_URL } from '../../constants/constants';
5+
import { styled } from '../../theme';
6+
import { CustomTooltip } from '../CustomTooltip';
7+
8+
interface User {
9+
name: string;
10+
avatar_url: string;
11+
border_color: string;
12+
user_id: string;
13+
}
14+
15+
interface Users {
16+
[clientID: string]: User;
17+
}
18+
19+
interface CollaboratorAvatarGroupProps {
20+
users: Users;
21+
}
22+
23+
interface StyledAvatarProps {
24+
borderColor: string;
25+
}
26+
const StyledAvatar = styled(Avatar)<StyledAvatarProps>(({ theme, borderColor }) => {
27+
return {
28+
width: theme.spacing(4),
29+
height: theme.spacing(4),
30+
cursor: 'pointer',
31+
border: `1.25px solid ${borderColor} !important`
32+
};
33+
});
34+
35+
const MoreAvatarButton = styled('div')(({ theme }) => ({
36+
width: theme.spacing(4.25),
37+
height: theme.spacing(4.25),
38+
border: '1px solid #fff',
39+
borderRadius: '50%',
40+
background: 'rgba(57, 102, 121, .9)',
41+
display: 'flex',
42+
justifyContent: 'center',
43+
alignItems: 'center',
44+
marginLeft: '-10px',
45+
zIndex: 0,
46+
'&:hover': {
47+
cursor: 'pointer'
48+
}
49+
}));
50+
51+
const PopupAvatarWrapper = styled('div')({
52+
display: 'flex',
53+
alignItems: 'center',
54+
padding: '5px 15px 5px 10px',
55+
'&:hover': {
56+
cursor: 'pointer',
57+
background: '#cecece80 !important'
58+
}
59+
});
60+
61+
const UserName = styled(Typography)({
62+
marginLeft: '10px',
63+
fontWeight: 600
64+
});
65+
66+
const StyledPopover = styled(Popover)(() => ({
67+
'& .MuiPopover-paper': {
68+
marginTop: '10px',
69+
maxHeight: '331px'
70+
}
71+
}));
72+
73+
const CollaboratorAvatarGroup = ({ users }: CollaboratorAvatarGroupProps): JSX.Element => {
74+
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
75+
76+
const openInNewTab = (url: string): void => {
77+
window.open(url, '_blank', 'noreferrer');
78+
};
79+
80+
const handleClick = (event: MouseEvent<HTMLDivElement>): void => {
81+
setAnchorEl(event.currentTarget);
82+
};
83+
84+
const handleClose = (): void => {
85+
setAnchorEl(null);
86+
};
87+
88+
const totalUsers = Object.entries(users).length;
89+
const visibleAvatars = 4;
90+
91+
return (
92+
<AvatarGroup max={visibleAvatars + 1}>
93+
{Object.entries(users)
94+
.slice(0, visibleAvatars)
95+
.map(([clientID, user]) => {
96+
return (
97+
<CustomTooltip key={clientID} title={user.name} arrow>
98+
<StyledAvatar
99+
key={clientID}
100+
alt={user.name}
101+
src={user.avatar_url}
102+
borderColor={user.border_color}
103+
style={{
104+
border: `1.25px solid ${user.border_color} !important`
105+
}}
106+
imgProps={{ referrerPolicy: 'no-referrer' }}
107+
onClick={() => openInNewTab(`https://${CLOUD_URL}/user/${user.user_id}`)}
108+
/>
109+
</CustomTooltip>
110+
);
111+
})}
112+
{totalUsers > visibleAvatars && (
113+
<>
114+
<MoreAvatarButton onClick={handleClick} aria-describedby="user-popover">
115+
{anchorEl ? (
116+
<ExpandMore fill="#fff" width={20} height={20} style={{ marginLeft: '4px' }} />
117+
) : (
118+
<Typography variant="body2" style={{ color: '#fff', fontSize: '12px' }}>
119+
{`+${totalUsers - visibleAvatars}`}
120+
</Typography>
121+
)}
122+
</MoreAvatarButton>
123+
<StyledPopover
124+
id="user-popover"
125+
open={Boolean(anchorEl)}
126+
anchorEl={anchorEl}
127+
onClose={handleClose}
128+
anchorOrigin={{
129+
vertical: 'bottom',
130+
horizontal: 'left'
131+
}}
132+
transformOrigin={{
133+
vertical: 'top',
134+
horizontal: 'left'
135+
}}
136+
>
137+
{Object.entries(users)
138+
.slice(visibleAvatars, totalUsers)
139+
.map(([clientID, user]) => (
140+
<PopupAvatarWrapper
141+
key={clientID}
142+
onClick={() => openInNewTab(`https://${CLOUD_URL}/user/${user.user_id}`)}
143+
>
144+
<StyledAvatar
145+
alt={user.name}
146+
src={user.avatar_url}
147+
borderColor={user.border_color}
148+
style={{
149+
border: `1.25px solid ${user.border_color} !important`
150+
}}
151+
imgProps={{ referrerPolicy: 'no-referrer' }}
152+
/>
153+
<UserName variant="body1">{user.name}</UserName>
154+
</PopupAvatarWrapper>
155+
))}
156+
</StyledPopover>
157+
</>
158+
)}
159+
</AvatarGroup>
160+
);
161+
};
162+
163+
export default CollaboratorAvatarGroup;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import CollaboratorAvatarGroup from './CollaboratorAvatarGroup';
2+
3+
export { CollaboratorAvatarGroup };

src/custom/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { BBChart } from './BBChart';
33
import { BookmarkNotification } from './BookmarkNotification';
44
import CatalogFilter, { CatalogFilterProps } from './CatalogFilter/CatalogFilter';
55
import { ChapterCard } from './ChapterCard';
6+
import { CollaboratorAvatarGroup } from './CollaboratorAvatarGroup';
67
import { ConnectionChip } from './ConnectionChip';
78
import { CatalogCardDesignLogo, CustomCatalogCard, EmptyStateCard } from './CustomCatalog';
89
import {
@@ -74,6 +75,7 @@ export {
7475
CatalogCardDesignLogo,
7576
CatalogFilter,
7677
ChapterCard,
78+
CollaboratorAvatarGroup,
7779
ConnectionChip,
7880
CustomCatalogCard,
7981
CustomColumnVisibilityControl,

0 commit comments

Comments
 (0)