refactor EditGroupMembersDialog

This commit is contained in:
namushka 2024-02-29 11:48:14 +03:00
parent 2798591800
commit 89235ef2d2
8 changed files with 373 additions and 43 deletions

View File

@ -0,0 +1,89 @@
import styled, { css } from "styled-components";
import { Base } from "@docspace/shared/themes";
export const GroupMember = styled.div<{ isExpect: boolean }>`
display: flex;
align-items: center;
gap: 8px;
padding: 8px 0;
.avatar {
min-width: 32px;
min-height: 32px;
}
.user_body-wrapper {
overflow: auto;
}
.name-wrapper,
.role-email {
display: flex;
}
.name {
font-weight: 600;
font-size: ${(props) => props.theme.getCorrectFontSize("14px")};
line-height: ${({ theme }) =>
theme.interfaceDirection === "rtl" ? `20px` : `16px`};
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
${(props) =>
props.isExpect && `color: ${props.theme.infoPanel.members.isExpectName}`};
}
.me-label {
font-weight: 600;
font-size: ${(props) => props.theme.getCorrectFontSize("14px")};
line-height: ${({ theme }) =>
theme.interfaceDirection === "rtl" ? `20px` : `16px`};
color: ${(props) => props.theme.infoPanel.members.meLabelColor};
padding-inline-start: 8px;
margin-inline-start: -8px;
}
.role-wrapper {
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
padding-right: 8px;
margin-right: auto;
`
: css`
padding-left: 8px;
margin-left: auto;
`}
font-weight: 600;
font-size: ${(props) => props.theme.getCorrectFontSize("13px")};
line-height: 20px;
white-space: nowrap;
.disabled-role-combobox {
color: ${(props) =>
props.theme.infoPanel.members.disabledRoleSelectorColor};
margin-inline-end: 16px;
}
}
.role-view_remove-icon {
cursor: pointer;
svg {
path {
fill: ${(props) => props.theme.iconButton.color};
}
}
:hover {
svg {
path {
fill: ${(props) => props.theme.iconButton.hoverColor};
}
}
}
}
`;
GroupMember.defaultProps = { theme: Base };

View File

@ -0,0 +1,111 @@
import { inject, observer } from "mobx-react";
import AtReactSvgUrl from "PUBLIC_DIR/images/@.react.svg?url";
// import { StyledUser } from "../../styles/members";
import { Avatar } from "@docspace/shared/components/avatar";
import { ComboBox } from "@docspace/shared/components/combobox";
import DefaultUserPhotoUrl from "PUBLIC_DIR/images/default_user_photo_size_82-82.png";
import { isMobileOnly, isMobile } from "react-device-detect";
import { decode } from "he";
import { filterUserRoleOptions } from "SRC_DIR/helpers";
import { Text } from "@docspace/shared/components/text";
import * as Styled from "./index.styled";
import { getUserRoleOptionsByUserAccess } from "@docspace/shared/utils/room-members/getUserRoleOptionsByUserAccess";
import { getUserRoleOptionsByRoomType } from "@docspace/shared/utils/room-members/getUserRoleOptionsByRoomType";
interface GroupMemberProps {
t: any;
user: any;
infoPanelSelection: any;
}
const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
const { roomType } = infoPanelSelection;
const fullRoomRoleOptions = getUserRoleOptionsByRoomType(
t,
roomType,
user.canEditAccess,
);
const selectedUserRoleCBOption = getUserRoleOptionsByUserAccess(
t,
user.userAccess || user.groupAccess,
);
const availableUserRoleCBOptions = filterUserRoleOptions(
fullRoomRoleOptions,
user,
);
console.log(
"GroupMember",
user,
selectedUserRoleCBOption,
availableUserRoleCBOptions,
fullRoomRoleOptions,
);
return (
<Styled.GroupMember isExpect={user.isExpect} key={user.id}>
<Avatar
role={selectedUserRoleCBOption?.type}
className="avatar"
size="min"
userName={user.isExpect ? "" : user.displayName || user.name}
source={
user.isExpect
? AtReactSvgUrl
: user.hasAvatar
? user.avatar
: DefaultUserPhotoUrl
}
//
tooltipContent={undefined}
hideRoleIcon={false}
withTooltip={false}
/>
<div className="user_body-wrapper">
<div className="name-wrapper">
<Text
className="name"
data-tooltip-id={`userTooltip_${Math.random()}`}
>
{decode(user.displayName)}
</Text>
</div>
</div>
{selectedUserRoleCBOption && availableUserRoleCBOptions && (
<div className="role-wrapper">
{user.canEditAccess ? (
<ComboBox
className="role-combobox"
selectedOption={selectedUserRoleCBOption}
options={availableUserRoleCBOptions}
scaled={false}
withBackdrop={isMobile}
size="content"
modernView
title={t("Common:Role")}
manualWidth={"fit-content"}
isMobileView={isMobileOnly}
directionY="both"
displaySelectedOption
//
onSelect={() => {}}
isLoading={false}
onToggle={() => {}}
/>
) : (
<div className="disabled-role-combobox" title={t("Common:Role")}>
{selectedUserRoleCBOption.label}
</div>
)}
</div>
)}
</Styled.GroupMember>
);
};
export default inject(({ infoPanelStore }) => ({
infoPanelSelection: infoPanelStore.infoPanelSelection,
}))(observer(GroupMember));

View File

@ -5,27 +5,25 @@ import {
import { observer, inject } from "mobx-react";
import { useState, useEffect, useTransition } from "react";
import { getGroupMembersInRoom } from "@docspace/shared/api/groups";
import User from "SRC_DIR/pages/Home/InfoPanel/Body/views/Members/User";
import MembersHelper from "SRC_DIR/pages/Home/InfoPanel/Body/helpers/MembersHelper";
import { useTranslation } from "react-i18next";
import { InputSize } from "@docspace/shared/components/text-input";
import { SearchInput } from "@docspace/shared/components/search-input";
import GroupMember from "./GroupMember";
interface EditGroupMembersProps {
selfId: string;
visible: boolean;
setVisible: (visible: boolean) => void;
group: any;
infoPanelSelection: any;
}
const EditGroupMembers = ({
infoPanelSelection,
selfId,
groupId,
group,
visible,
setVisible,
}: EditGroupMembersProps) => {
const { t } = useTranslation(["Common"]);
const membersHelper = new MembersHelper({ t });
const [searchValue, setSearchValue] = useState<string>("");
const onChangeSearchValue = (newValue: string) => {
@ -37,27 +35,20 @@ const EditGroupMembers = ({
const filteredGroupMembers = groupMembers?.filter((groupMember) =>
groupMember.user.displayName.includes(searchValue),
);
const [isLoading, setIsLoading] = useState(false);
const [, startTransition] = useTransition();
const onClose = () => setVisible(false);
useEffect(() => {
const fetchGroup = async () => {
if (!groupId) return;
setIsLoading(true);
if (!group) return;
console.log("infoPanelSelection", infoPanelSelection);
getGroupMembersInRoom(infoPanelSelection.id, groupId)!
.then((data: any) => {
startTransition(() => setGroupMembers(data.items));
console.log(data);
})
.catch((err: any) => console.error(err))
.finally(() => setIsLoading(false));
getGroupMembersInRoom(infoPanelSelection.id, group.id)!
.then((data: any) => startTransition(() => setGroupMembers(data.items)))
.catch((err: any) => console.error(err));
};
fetchGroup();
}, [groupId]);
}, [group, infoPanelSelection.id]);
return (
<ModalDialog
@ -65,13 +56,13 @@ const EditGroupMembers = ({
onClose={onClose}
displayType={ModalDialogType.aside}
>
<ModalDialog.Header>EditGroupMembers</ModalDialog.Header>
<ModalDialog.Header>{group.name}</ModalDialog.Header>
<ModalDialog.Body>
<SearchInput
className="search-input"
placeholder={"Search by group members"}
value={""}
placeholder={t("Search by group members")}
value={searchValue}
onChange={onChangeSearchValue}
onClearSearch={onClearSearch}
size={InputSize.base}
@ -80,16 +71,8 @@ const EditGroupMembers = ({
<div style={{ height: "12px", width: "100%" }} />
{filteredGroupMembers &&
filteredGroupMembers.map(({ user, groupAccess, canEditAccess }) => (
<div key={user.id} style={{ paddingRight: "12px" }}>
<User
t={t}
key={user.id}
user={{ ...user, access: groupAccess, canEditAccess }}
membersHelper={membersHelper}
currentMember={{ id: selfId }}
/>
</div>
filteredGroupMembers.map(({ user, ...rest }) => (
<GroupMember t={t} key={user.id} user={{ ...user, ...rest }} />
))}
</ModalDialog.Body>
</ModalDialog>
@ -99,7 +82,7 @@ const EditGroupMembers = ({
export default inject(({ infoPanelStore, userStore, dialogsStore }) => ({
infoPanelSelection: infoPanelStore.infoPanelSelection,
selfId: userStore.user.id,
groupId: dialogsStore.editMembersGroupId,
group: dialogsStore.editMembersGroup,
visible: dialogsStore.editGroupMembersDialogVisible,
setVisible: dialogsStore.setEditGroupMembersDialogVisible,
}))(observer(EditGroupMembers));

View File

@ -36,10 +36,9 @@ const User = ({
setInfoPanelMembers,
searchValue,
resendEmailInvitations,
setEditMembersGroupId,
setEditMembersGroup,
setEditGroupMembersDialogVisible,
}) => {
console.log(user);
if (!infoPanelSelection) return null;
if (!user.displayName && !user.name && !user.email) return null;
@ -58,7 +57,6 @@ const User = ({
);
const userRole = membersHelper.getOptionByUserAccess(user.access, user);
console.log("userRole", userRole);
const userRoleOptions = user.isGroup
? filterGroupRoleOptions(fullRoomRoleOptions)
: filterUserRoleOptions(fullRoomRoleOptions, user);
@ -239,8 +237,8 @@ const User = ({
</div>
);
const onOpenGroup = (groupId) => {
setEditMembersGroupId(groupId);
const onOpenGroup = (group) => {
setEditMembersGroup(group);
setEditGroupMembersDialogVisible(true);
};
@ -292,7 +290,7 @@ const User = ({
<Link
className="name"
type="action"
onClick={() => onOpenGroup(user.id)}
onClick={() => onOpenGroup(user)}
>
{decode(user.name)}
</Link>
@ -382,7 +380,7 @@ export default inject(
const { changeType: changeUserType } = peopleStore;
const { setEditMembersGroupId, setEditGroupMembersDialogVisible } =
const { setEditMembersGroup, setEditGroupMembersDialogVisible } =
dialogsStore;
return {
@ -397,7 +395,7 @@ export default inject(
setInfoPanelMembers,
fetchMembers,
searchValue,
setEditMembersGroupId,
setEditMembersGroup,
setEditGroupMembersDialogVisible,
};
},

View File

@ -79,7 +79,7 @@ class DialogsStore {
leaveRoomDialogVisible = false;
changeRoomOwnerIsVisible = false;
changeRoomOwnerData = null;
editMembersGroupId = null;
editMembersGroup = null;
shareFolderDialogVisible = false;
@ -290,8 +290,8 @@ class DialogsStore {
this.editGroupMembersDialogVisible = editGroupMembersDialogVisible;
};
setEditMembersGroupId = (editMembersGroupId) => {
this.editMembersGroupId = editMembersGroupId;
setEditMembersGroup = (editMembersGroup) => {
this.editMembersGroup = editMembersGroup;
};
setConflictResolveDialogVisible = (conflictResolveDialogVisible) => {

View File

@ -0,0 +1,52 @@
import { ShareAccessRights } from "@docspace/shared/enums";
export const getUserRoleOptions = (t: any) => ({
docSpaceAdmin: {
key: "owner",
label: t("Common:Owner"),
access: ShareAccessRights.FullAccess,
type: "admin",
},
roomAdmin: {
key: "roomAdmin",
label: t("Common:RoomAdmin"),
access: ShareAccessRights.RoomManager,
type: "manager",
},
collaborator: {
key: "collaborator",
label: t("Common:PowerUser"),
access: ShareAccessRights.Collaborator,
type: "collaborator",
},
viewer: {
key: "viewer",
label: t("Translations:RoleViewer"),
access: ShareAccessRights.ReadOnly,
type: "user",
},
editor: {
key: "editor",
label: t("Translations:RoleEditor"),
access: ShareAccessRights.Editing,
type: "user",
},
formFiller: {
key: "formFiller",
label: t("Translations:RoleFormFiller"),
access: ShareAccessRights.FormFilling,
type: "user",
},
reviewer: {
key: "reviewer",
label: t("Translations:RoleReviewer"),
access: ShareAccessRights.Review,
type: "user",
},
commentator: {
key: "commentator",
label: t("Translations:RoleCommentator"),
access: ShareAccessRights.Comment,
type: "user",
},
});

View File

@ -0,0 +1,81 @@
import { RoomsType, ShareAccessRights } from "@docspace/shared/enums";
import { getUserRoleOptions } from "./getUserRoleOptions";
export const getUserRoleOptionsByRoomType = (
t: any,
roomType: RoomsType,
canChangeUserRole: boolean = false,
) => {
if (!roomType) return;
const options = getUserRoleOptions(t);
const deleteOption = canChangeUserRole
? [
{ key: "s2", isSeparator: true },
{
key: "remove",
label: t("Common:Remove"),
access: ShareAccessRights.None,
},
]
: [];
switch (roomType) {
case RoomsType.FillingFormsRoom:
return [
options.roomAdmin,
options.collaborator,
options.formFiller,
options.viewer,
...deleteOption,
];
case RoomsType.EditingRoom:
return [
options.roomAdmin,
options.collaborator,
options.editor,
options.viewer,
...deleteOption,
];
case RoomsType.ReviewRoom:
return [
options.roomAdmin,
options.collaborator,
options.reviewer,
options.commentator,
options.viewer,
...deleteOption,
];
case RoomsType.ReadOnlyRoom:
return [
options.roomAdmin,
options.collaborator,
options.viewer,
...deleteOption,
];
case RoomsType.CustomRoom:
return [
options.roomAdmin,
options.collaborator,
options.editor,
options.formFiller,
options.reviewer,
options.commentator,
options.viewer,
...deleteOption,
];
case RoomsType.FormRoom:
return [
options.roomAdmin,
options.collaborator,
options.viewer,
options.formFiller,
...deleteOption,
];
case RoomsType.PublicRoom:
return [options.roomAdmin, options.collaborator, ...deleteOption];
default:
return [];
}
};

View File

@ -0,0 +1,16 @@
import { ShareAccessRights } from "enums";
import { getUserRoleOptions } from "./getUserRoleOptions";
export const getUserRoleOptionsByUserAccess = (
t: any,
access: ShareAccessRights,
) => {
if (!access) return;
const options = getUserRoleOptions(t);
const [userOption] = Object.values(options).filter(
(opt) => opt.access === access,
);
return userOption;
};