Skip to content

Commit

Permalink
Fix 'Additional Users' Popover Display Logic for Profile Clicks (#270)
Browse files Browse the repository at this point in the history
* Modify profile click functionality to only show 'Additional Users' popover when more than 4 users are present

* Separate UserPresence component from DocumentHeader component

* Fix code format
  • Loading branch information
choidabom authored Aug 6, 2024
1 parent 108e7e3 commit 72c4030
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 78 deletions.
87 changes: 9 additions & 78 deletions frontend/src/components/headers/DocumentHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,15 @@ import VerticalSplitIcon from "@mui/icons-material/VerticalSplit";
import VisibilityIcon from "@mui/icons-material/Visibility";
import {
AppBar,
Avatar,
AvatarGroup,
IconButton,
Paper,
Stack,
ToggleButton,
ToggleButtonGroup,
Toolbar,
Tooltip,
Popover,
Typography,
List,
ListItem,
ListItemAvatar,
ListItemText,
} from "@mui/material";
import { useEffect, useState } from "react";
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { useList } from "react-use";
Expand All @@ -31,6 +23,12 @@ import { YorkieCodeMirrorPresenceType } from "../../utils/yorkie/yorkieSync";
import DownloadMenu from "../common/DownloadMenu";
import ShareButton from "../common/ShareButton";
import ThemeButton from "../common/ThemeButton";
import UserPresence from "./UserPresence";

export type Presence = {
clientID: ActorID;
presence: YorkieCodeMirrorPresenceType;
};

function DocumentHeader() {
const dispatch = useDispatch();
Expand All @@ -46,12 +44,7 @@ function DocumentHeader() {
clear: clearPresenceList,
filter: filterPresenceList,
},
] = useList<{
clientID: ActorID;
presence: YorkieCodeMirrorPresenceType;
}>([]);

const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
] = useList<Presence>([]);

useEffect(() => {
if (editorState.shareRole === "READ") {
Expand Down Expand Up @@ -96,20 +89,6 @@ function DocumentHeader() {
navigate(`/${workspaceState.data?.slug}`);
};

// Display additional users in a popover when there are more than 4 users
const handleOpenPopover = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};

// Display None additional users in a popover when there are more than 4 users
const handleClosePopover = () => {
setAnchorEl(null);
};

const popoverOpen = Boolean(anchorEl);

const hiddenAvatars = presenceList.slice(3);

return (
<AppBar position="static" sx={{ zIndex: 100 }}>
<Toolbar>
Expand Down Expand Up @@ -151,55 +130,7 @@ function DocumentHeader() {
<DownloadMenu />
</Stack>
<Stack direction="row" alignItems="center" gap={1}>
<AvatarGroup max={4} onClick={handleOpenPopover}>
{presenceList?.map((presence) => (
<Tooltip key={presence.clientID} title={presence.presence.name}>
<Avatar
alt={presence.presence.name}
sx={{ bgcolor: presence.presence.color }}
>
{presence.presence.name[0]}
</Avatar>
</Tooltip>
))}
</AvatarGroup>
<Popover
open={popoverOpen}
anchorEl={anchorEl}
onClose={handleClosePopover}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
>
<Paper sx={{ padding: 2 }}>
<Typography variant="subtitle2">Additional Users</Typography>
<List>
{hiddenAvatars.map((presence) => (
<ListItem key={presence.clientID} sx={{ paddingY: 0.5 }}>
<ListItemAvatar>
<Avatar
sx={{
bgcolor: presence.presence.color,
width: 24,
height: 24,
fontSize: 12,
}}
>
{presence.presence.name[0]}
</Avatar>
</ListItemAvatar>
<ListItemText
primary={presence.presence.name}
primaryTypographyProps={{
variant: "body2",
}}
/>
</ListItem>
))}
</List>
</Paper>
</Popover>
<UserPresence presenceList={presenceList} />
{!editorState.shareRole && <ShareButton />}
<ThemeButton />
</Stack>
Expand Down
92 changes: 92 additions & 0 deletions frontend/src/components/headers/UserPresence.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import {
Avatar,
AvatarGroup,
ListItem,
ListItemAvatar,
ListItemText,
Paper,
Popover,
Tooltip,
Typography,
} from "@mui/material";
import { useState } from "react";
import { Presence } from "./DocumentHeader";

interface UserPresenceProps {
presenceList: Presence[];
}

function UserPresence(props: UserPresenceProps) {
const { presenceList } = props;
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
const popoverOpen = Boolean(anchorEl);

const handleOpenPopover = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};

const handleClosePopover = () => {
setAnchorEl(null);
};

const MAX_VISIBLE_AVATARS = 4;
const hiddenAvatars = presenceList.slice(MAX_VISIBLE_AVATARS);

const renderAvatar = (presence: Presence) => (
<Tooltip key={presence.clientID} title={presence.presence.name}>
<Avatar alt={presence.presence.name} sx={{ bgcolor: presence.presence.color }}>
{presence.presence.name[0]}
</Avatar>
</Tooltip>
);

return (
<>
<AvatarGroup>
{presenceList.slice(0, MAX_VISIBLE_AVATARS).map(renderAvatar)}
{presenceList.length > MAX_VISIBLE_AVATARS && (
<Avatar onClick={handleOpenPopover}>
+{presenceList.length - MAX_VISIBLE_AVATARS}
</Avatar>
)}
</AvatarGroup>
<Popover
open={popoverOpen}
anchorEl={anchorEl}
onClose={handleClosePopover}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
>
<Paper sx={{ padding: 2 }}>
<Typography variant="subtitle2">Additional Users</Typography>
{hiddenAvatars.map((presence) => (
<ListItem key={presence.clientID} sx={{ paddingY: 1 }}>
<ListItemAvatar>
<Avatar
sx={{
bgcolor: presence.presence.color,
width: 24,
height: 24,
fontSize: 12,
}}
>
{presence.presence.name[0]}
</Avatar>
</ListItemAvatar>
<ListItemText
primary={presence.presence.name}
primaryTypographyProps={{
variant: "body2",
}}
/>
</ListItem>
))}
</Paper>
</Popover>
</>
);
}

export default UserPresence;

0 comments on commit 72c4030

Please sign in to comment.