Skip to content

Commit

Permalink
(FE) Retrieve Workspace Members (#84)
Browse files Browse the repository at this point in the history
* Add members button

* Add MemberModal

* Remove unused code

* Attach Member modal to drawer
  • Loading branch information
devleejb authored Jan 22, 2024
1 parent 5a30d6e commit dd45874
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 0 deletions.
18 changes: 18 additions & 0 deletions frontend/src/components/drawers/WorkspaceDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ListItem,
ListItemAvatar,
ListItemButton,
ListItemIcon,
ListItemSecondaryAction,
ListItemText,
Stack,
Expand All @@ -25,6 +26,8 @@ import AddIcon from "@mui/icons-material/Add";
import CreateModal from "../modals/CreateModal";
import { useCreateDocumentMutation } from "../../hooks/api/workspaceDocument";
import ThemeButton from "../common/ThemeButton";
import PeopleIcon from "@mui/icons-material/People";
import MemberModal from "../modals/MemberModal";

const DRAWER_WIDTH = 240;

Expand All @@ -38,6 +41,7 @@ function WorkspaceDrawer() {
(EventTarget & Element) | null
>(null);
const [createWorkspaceModalOpen, setCreateWorkspaceModalOpen] = useState(false);
const [memberModalOpen, setMemberModalOpen] = useState(false);

const handleOpenProfilePopover: MouseEventHandler = (event) => {
setProfileAnchorEl(event.currentTarget);
Expand All @@ -63,6 +67,10 @@ function WorkspaceDrawer() {
setCreateWorkspaceModalOpen((prev) => !prev);
};

const handleMemberModalOpen = () => {
setMemberModalOpen((prev) => !prev);
};

return (
<Drawer
sx={{
Expand Down Expand Up @@ -117,6 +125,15 @@ function WorkspaceDrawer() {
</Button>
</ListItem>
<Divider />
<ListItem disablePadding>
<ListItemButton onClick={handleMemberModalOpen}>
<ListItemIcon>
<PeopleIcon />
</ListItemIcon>
<ListItemText primary="Members" />
</ListItemButton>
</ListItem>
<Divider />
<ListItem sx={{ mt: "auto" }}>
<Stack width={1} alignItems="center" justifyContent="flex-end" direction="row">
<ThemeButton />
Expand Down Expand Up @@ -145,6 +162,7 @@ function WorkspaceDrawer() {
onSuccess={handleCreateWorkspace}
onClose={handleCreateWorkspaceModalOpen}
/>
<MemberModal open={memberModalOpen} onClose={handleMemberModalOpen} />
</Drawer>
);
}
Expand Down
102 changes: 102 additions & 0 deletions frontend/src/components/modals/MemberModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import {
Avatar,
Box,
CircularProgress,
IconButton,
Modal,
Paper,
Stack,
Typography,
} from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { useGetWorkspaceUserListQuery } from "../../hooks/api/workspaceUser";
import { useParams } from "react-router-dom";
import { useGetWorkspaceQuery } from "../../hooks/api/workspace";
import { useMemo } from "react";
import { User } from "../../hooks/api/types/user";
import InfiniteScroll from "react-infinite-scroller";

interface MemeberModalProps {
open: boolean;
onClose: () => void;
}

function MemeberModal(props: MemeberModalProps) {
const { open, onClose } = props;
const params = useParams();
const { data: workspace } = useGetWorkspaceQuery(params.workspaceSlug);
const {
data: workspaceUserPageList,
fetchNextPage,
hasNextPage,
} = useGetWorkspaceUserListQuery(workspace?.id);
const userList = useMemo(() => {
return (
workspaceUserPageList?.pages.reduce((prev, page) => {
return prev.concat(page.workspaceUsers);
}, [] as Array<User>) ?? []
);
}, [workspaceUserPageList?.pages]);

return (
<Modal open={open} disableAutoFocus onClose={onClose}>
<Paper
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
p: 4,
width: 400,
}}
>
<IconButton
sx={{
position: "absolute",
top: 28,
right: 28,
}}
onClick={onClose}
>
<CloseIcon />
</IconButton>
<Stack gap={4}>
<Typography variant="h5">Members</Typography>
<Box
style={{
height: 300,
maxHeight: "100%",
overflow: "auto",
}}
width={1}
>
<InfiniteScroll
pageStart={0}
loadMore={() => fetchNextPage()}
hasMore={hasNextPage}
loader={
<Box className="loader" key={0}>
<CircularProgress size="sm" />
</Box>
}
useWindow={false}
>
<Stack gap={2}>
{userList.map((user) => (
<Stack key={user.id} direction="row" alignItems="center">
<Stack direction="row" alignItems="center" gap={1}>
<Avatar>{user.nickname?.[0]}</Avatar>
<Typography>{user.nickname}</Typography>
</Stack>
</Stack>
))}
</Stack>
</InfiniteScroll>
</Box>
</Stack>
</Paper>
</Modal>
);
}

export default MemeberModal;
6 changes: 6 additions & 0 deletions frontend/src/hooks/api/types/workspaceUser.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { User } from "./user";

export class GetWorkspaceUserListResponse {
cursor: string | null;
workspaceUsers: Array<User>;
}
28 changes: 28 additions & 0 deletions frontend/src/hooks/api/workspaceUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useInfiniteQuery } from "@tanstack/react-query";
import axios from "axios";
import { GetWorkspaceUserListResponse } from "./types/workspaceUser";

export const generateGetWorkspaceUserListQueryKey = (workspaceId: string) => {
return ["workspaces", workspaceId, "users"];
};

export const useGetWorkspaceUserListQuery = (workspaceId?: string) => {
return useInfiniteQuery<GetWorkspaceUserListResponse>({
queryKey: generateGetWorkspaceUserListQueryKey(workspaceId || ""),
queryFn: async ({ pageParam }) => {
const res = await axios.get<GetWorkspaceUserListResponse>(
`/workspaces/${workspaceId}/users`,
{
params: {
cursor: pageParam,
},
}
);
return res.data;
},
enabled: Boolean(workspaceId),
initialPageParam: undefined,
getPreviousPageParam: (firstPage) => firstPage.cursor ?? undefined,
getNextPageParam: (lastPage) => lastPage.cursor ?? undefined,
});
};

0 comments on commit dd45874

Please sign in to comment.