diff --git a/web/modals/components/add-members-item.react.js b/web/modals/components/add-members-item.react.js
index 407094031..e9d80ed70 100644
--- a/web/modals/components/add-members-item.react.js
+++ b/web/modals/components/add-members-item.react.js
@@ -1,51 +1,55 @@
// @flow
import * as React from 'react';
import type { UserListItem } from 'lib/types/user-types.js';
import css from './add-members.css';
import Button from '../../components/button.react.js';
+import UserAvatar from '../../components/user-avatar.react.js';
type AddMembersItemProps = {
+userInfo: UserListItem,
+onClick: (userID: string) => void,
+userAdded: boolean,
};
function AddMemberItem(props: AddMembersItemProps): React.Node {
const { userInfo, onClick, userAdded = false } = props;
const canBeAdded = !userInfo.alertText;
const onClickCallback = React.useCallback(() => {
if (!canBeAdded) {
return;
}
onClick(userInfo.id);
}, [canBeAdded, onClick, userInfo.id]);
const action = React.useMemo(() => {
if (!canBeAdded) {
return userInfo.alertTitle;
}
if (userAdded) {
return Remove;
} else {
return 'Add';
}
}, [canBeAdded, userAdded, userInfo.alertTitle]);
return (
);
}
export default AddMemberItem;
diff --git a/web/modals/components/add-members.css b/web/modals/components/add-members.css
index 96498af39..984e8a79a 100644
--- a/web/modals/components/add-members.css
+++ b/web/modals/components/add-members.css
@@ -1,36 +1,47 @@
div.addMemberItemsGroupHeader {
font-size: var(--s-font-14);
color: var(--add-members-group-header-color);
margin: 16px;
}
button.addMemberItem {
justify-content: space-between;
color: var(--add-members-item-color);
font-size: var(--l-font-18);
width: 100%;
}
button.addMemberItem:hover {
color: var(--add-members-item-color-hover);
}
button.addMemberItem:disabled {
color: var(--add-members-item-disabled-color);
cursor: not-allowed;
}
button.addMemberItem:hover:disabled {
color: var(--add-members-item-disabled-color-hover);
}
button.addMemberItem .label {
padding: 8px 16px;
}
button.addMemberItem .danger {
color: var(--add-members-remove-pending-color);
}
button.addMemberItem:hover .danger {
color: var(--add-members-remove-pending-color-hover);
}
+
+div.userInfoContainer {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ padding-left: 16px;
+}
+
+div.username {
+ margin-left: 8px;
+}
diff --git a/web/modals/threads/members/member.react.js b/web/modals/threads/members/member.react.js
index e8f6ea7d7..fc8467ce4 100644
--- a/web/modals/threads/members/member.react.js
+++ b/web/modals/threads/members/member.react.js
@@ -1,166 +1,169 @@
// @flow
import classNames from 'classnames';
import * as React from 'react';
import {
removeUsersFromThread,
changeThreadMemberRoles,
} from 'lib/actions/thread-actions.js';
import SWMansionIcon from 'lib/components/SWMansionIcon.react.js';
import {
memberIsAdmin,
memberHasAdminPowers,
removeMemberFromThread,
switchMemberAdminRoleInThread,
getAvailableThreadMemberActions,
} from 'lib/shared/thread-utils.js';
import { stringForUser } from 'lib/shared/user-utils.js';
import type { SetState } from 'lib/types/hook-types.js';
import {
type RelativeMemberInfo,
type ThreadInfo,
} from 'lib/types/thread-types.js';
import {
useDispatchActionPromise,
useServerCall,
} from 'lib/utils/action-utils.js';
import css from './members-modal.css';
import Label from '../../../components/label.react.js';
import MenuItem from '../../../components/menu-item.react.js';
import Menu from '../../../components/menu.react.js';
+import UserAvatar from '../../../components/user-avatar.react.js';
type Props = {
+memberInfo: RelativeMemberInfo,
+threadInfo: ThreadInfo,
+setOpenMenu: SetState,
+isMenuOpen: boolean,
};
function ThreadMember(props: Props): React.Node {
const { memberInfo, threadInfo, setOpenMenu, isMenuOpen } = props;
const userName = stringForUser(memberInfo);
const onMenuChange = React.useCallback(
menuOpen => {
if (menuOpen) {
setOpenMenu(() => memberInfo.id);
} else {
setOpenMenu(menu => (menu === memberInfo.id ? null : menu));
}
},
[memberInfo.id, setOpenMenu],
);
const dispatchActionPromise = useDispatchActionPromise();
const boundRemoveUsersFromThread = useServerCall(removeUsersFromThread);
const onClickRemoveUser = React.useCallback(
() =>
removeMemberFromThread(
threadInfo,
memberInfo,
dispatchActionPromise,
boundRemoveUsersFromThread,
),
[boundRemoveUsersFromThread, dispatchActionPromise, memberInfo, threadInfo],
);
const isCurrentlyAdmin = memberIsAdmin(memberInfo, threadInfo);
const boundChangeThreadMemberRoles = useServerCall(changeThreadMemberRoles);
const onMemberAdminRoleToggled = React.useCallback(
() =>
switchMemberAdminRoleInThread(
threadInfo,
memberInfo,
isCurrentlyAdmin,
dispatchActionPromise,
boundChangeThreadMemberRoles,
),
[
boundChangeThreadMemberRoles,
dispatchActionPromise,
isCurrentlyAdmin,
memberInfo,
threadInfo,
],
);
const menuItems = React.useMemo(
() =>
getAvailableThreadMemberActions(memberInfo, threadInfo).map(action => {
if (action === 'remove_admin') {
return (
);
}
if (action === 'make_admin') {
return (
);
}
if (action === 'remove_user') {
return (
);
}
return null;
}),
[memberInfo, onClickRemoveUser, onMemberAdminRoleToggled, threadInfo],
);
const userSettingsIcon = React.useMemo(
() =>