diff --git a/web/modals/threads/members/members-list.react.js b/web/modals/threads/members/members-list.react.js new file mode 100644 --- /dev/null +++ b/web/modals/threads/members/members-list.react.js @@ -0,0 +1,76 @@ +// @flow + +import classNames from 'classnames'; +import _groupBy from 'lodash/fp/groupBy'; +import _toPairs from 'lodash/fp/toPairs'; +import * as React from 'react'; + +import { stringForUser } from 'lib/shared/user-utils'; +import { + type ThreadInfo, + type RelativeMemberInfo, +} from 'lib/types/thread-types'; + +import ThreadMember from './member.react'; +import css from './members-modal.css'; + +type Props = { + +threadInfo: ThreadInfo, + +threadMembers: $ReadOnlyArray, +}; + +function ThreadMembersList(props: Props): React.Node { + const { threadMembers, threadInfo } = props; + const [openMenu, setOpenMenu] = React.useState(null); + const hasMembers = threadMembers.length > 0; + + const groupedByFirstLetterMembers = React.useMemo( + () => _groupBy(member => stringForUser(member)[0])(threadMembers), + [threadMembers], + ); + + const groupedMembersList = React.useMemo( + () => + _toPairs(groupedByFirstLetterMembers) + .sort((a, b) => a[0].localeCompare(b[0])) + .map(([letter, users]) => { + const userList = users + .sort((a, b) => stringForUser(a).localeCompare(stringForUser(b))) + .map((user: RelativeMemberInfo) => ( + + )); + const letterHeader = ( +
+ {letter.toUpperCase()} +
+ ); + return ( + + {letterHeader} + {userList} + + ); + }), + [groupedByFirstLetterMembers, openMenu, threadInfo], + ); + let content = groupedMembersList; + if (!hasMembers) { + content = ( +
+ No matching users were found in the thread! +
+ ); + } + const membersListClasses = classNames(css.membersList, { + [css.noScroll]: !!openMenu, + }); + return
{content}
; +} + +export default ThreadMembersList; diff --git a/web/modals/threads/members/members-modal.css b/web/modals/threads/members/members-modal.css --- a/web/modals/threads/members/members-modal.css +++ b/web/modals/threads/members/members-modal.css @@ -1,3 +1,13 @@ +div.membersList { + overflow: scroll; + padding: 8px 0; + color: var(--members-modal-member-text); +} + +div.noScroll { + overflow: hidden; +} + div.memberContainer { display: flex; flex-direction: row; @@ -23,3 +33,14 @@ div.memberAction { position: relative; } + +h5.memberletterHeader { + margin: 16px; + color: var(--members-modal-member-text); + font-size: var(--s-font-14); +} + +div.noUsers { + padding-top: 16px; + text-align: center; +} diff --git a/web/theme.css b/web/theme.css --- a/web/theme.css +++ b/web/theme.css @@ -132,6 +132,8 @@ --tabs-header-background-border: var(--shades-black-80); --tabs-header-background-color-hover: var(--shades-white-80); --tabs-header-background-border-hover: var(--shades-black-70); + --members-modal-member-text: var(--shades-black-60); + --members-modal-member-text-hover: var(--shades-white-100); --label-default-bg: var(--violet-dark-80); --label-default-color: var(--shades-white-80); }