signal-desktop/ts/components/conversation/conversation-details/ConversationDetailsMembershipList.tsx

143 lines
4.2 KiB
TypeScript
Raw Normal View History

2021-03-11 21:29:31 +00:00
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
2021-11-02 23:01:13 +00:00
import type { LocalizerType, ThemeType } from '../../../types/Util';
import { Avatar } from '../../Avatar';
2021-05-10 22:38:18 +00:00
import { Emojify } from '../Emojify';
import { ConversationDetailsIcon, IconType } from './ConversationDetailsIcon';
import type { ConversationType } from '../../../state/ducks/conversations';
2021-11-17 21:11:21 +00:00
import type { PreferredBadgeSelectorType } from '../../../state/selectors/badges';
import { PanelRow } from './PanelRow';
import { PanelSection } from './PanelSection';
export type GroupV2Membership = {
isAdmin: boolean;
member: ConversationType;
};
export type Props = {
2021-03-11 21:29:31 +00:00
canAddNewMembers: boolean;
2021-09-21 22:37:10 +00:00
conversationId: string;
2021-11-17 21:11:21 +00:00
getPreferredBadge: PreferredBadgeSelectorType;
2021-06-17 21:15:09 +00:00
i18n: LocalizerType;
maxShownMemberCount?: number;
memberships: Array<GroupV2Membership>;
showContactModal: (contactId: string, conversationId?: string) => void;
2021-06-17 21:15:09 +00:00
startAddingNewMembers?: () => void;
2021-11-02 23:01:13 +00:00
theme: ThemeType;
};
2021-03-02 16:27:11 +00:00
const collator = new Intl.Collator(undefined, { sensitivity: 'base' });
function sortConversationTitles(
left: GroupV2Membership,
right: GroupV2Membership
) {
const leftTitle = left.member.title;
const rightTitle = right.member.title;
return collator.compare(leftTitle, rightTitle);
}
function sortMemberships(
memberships: ReadonlyArray<GroupV2Membership>
): Array<GroupV2Membership> {
let you: undefined | GroupV2Membership;
const admins: Array<GroupV2Membership> = [];
const nonAdmins: Array<GroupV2Membership> = [];
memberships.forEach(membershipInfo => {
const { isAdmin, member } = membershipInfo;
if (member.isMe) {
you = membershipInfo;
} else if (isAdmin) {
admins.push(membershipInfo);
} else {
nonAdmins.push(membershipInfo);
}
});
admins.sort(sortConversationTitles);
nonAdmins.sort(sortConversationTitles);
const sortedMemberships = [];
if (you) {
sortedMemberships.push(you);
}
sortedMemberships.push(...admins);
sortedMemberships.push(...nonAdmins);
return sortedMemberships;
}
export const ConversationDetailsMembershipList: React.ComponentType<Props> = ({
2021-03-11 21:29:31 +00:00
canAddNewMembers,
2021-09-21 22:37:10 +00:00
conversationId,
2021-11-17 21:11:21 +00:00
getPreferredBadge,
2021-06-17 21:15:09 +00:00
i18n,
maxShownMemberCount = 5,
memberships,
showContactModal,
2021-03-11 21:29:31 +00:00
startAddingNewMembers,
2021-11-02 23:01:13 +00:00
theme,
}) => {
const [showAllMembers, setShowAllMembers] = React.useState<boolean>(false);
2021-03-02 16:27:11 +00:00
const sortedMemberships = sortMemberships(memberships);
2021-06-17 21:15:09 +00:00
const shouldHideRestMembers =
sortedMemberships.length - maxShownMemberCount > 1;
const membersToShow =
shouldHideRestMembers && !showAllMembers
2021-06-17 21:15:09 +00:00
? maxShownMemberCount
2021-03-02 16:27:11 +00:00
: sortedMemberships.length;
return (
<PanelSection
title={i18n('ConversationDetailsMembershipList--title', [
2021-03-02 16:27:11 +00:00
sortedMemberships.length.toString(),
])}
>
2021-03-11 21:29:31 +00:00
{canAddNewMembers && (
<PanelRow
icon={
<div className="ConversationDetails-membership-list__add-members-icon" />
2021-03-11 21:29:31 +00:00
}
label={i18n('ConversationDetailsMembershipList--add-members')}
2021-06-17 21:15:09 +00:00
onClick={() => startAddingNewMembers?.()}
2021-03-11 21:29:31 +00:00
/>
)}
2021-03-02 16:27:11 +00:00
{sortedMemberships.slice(0, membersToShow).map(({ isAdmin, member }) => (
<PanelRow
key={member.id}
2021-09-21 22:37:10 +00:00
onClick={() => showContactModal(member.id, conversationId)}
icon={
<Avatar
conversationType="direct"
2021-11-17 21:11:21 +00:00
badge={getPreferredBadge(member.badges)}
i18n={i18n}
size={32}
2021-11-02 23:01:13 +00:00
theme={theme}
{...member}
/>
}
2021-05-10 22:38:18 +00:00
label={<Emojify text={member.isMe ? i18n('you') : member.title} />}
right={isAdmin ? i18n('GroupV2--admin') : ''}
/>
))}
{showAllMembers === false && shouldHideRestMembers && (
<PanelRow
className="ConversationDetails-membership-list--show-all"
icon={
<ConversationDetailsIcon
ariaLabel={i18n('ConversationDetailsMembershipList--show-all')}
icon={IconType.down}
/>
}
onClick={() => setShowAllMembers(true)}
label={i18n('ConversationDetailsMembershipList--show-all')}
/>
)}
</PanelSection>
);
};