Implemented ability to quickly add a user to a group

This commit is contained in:
Alvaro 2022-09-26 10:24:52 -06:00 committed by GitHub
parent 190cd9408b
commit 22bf3ebcc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 855 additions and 70 deletions

View file

@ -43,6 +43,7 @@ type PropsActionType = {
showConversation: ShowConversationType;
toggleAdmin: (conversationId: string, contactId: string) => void;
toggleSafetyNumberModal: (conversationId: string) => unknown;
toggleAddUserToAnotherGroupModal: (conversationId: string) => void;
updateConversationModelSharedGroups: (conversationId: string) => void;
viewUserStories: ViewUserStoriesActionCreatorType;
};
@ -77,6 +78,7 @@ export const ContactModal = ({
theme,
toggleAdmin,
toggleSafetyNumberModal,
toggleAddUserToAnotherGroupModal,
updateConversationModelSharedGroups,
viewUserStories,
}: PropsType): JSX.Element => {
@ -242,6 +244,21 @@ export const ContactModal = ({
<span>{i18n('showSafetyNumber')}</span>
</button>
)}
{!contact.isMe && isMember && conversation?.id && (
<button
type="button"
className="ContactModal__button"
onClick={() => {
hideContactModal();
toggleAddUserToAnotherGroupModal(contact.id);
}}
>
<div className="ContactModal__bubble-icon">
<div className="ContactModal__add-to-another-group__bubble-icon" />
</div>
Add to another group
</button>
)}
{!contact.isMe && areWeAdmin && isMember && conversation?.id && (
<>
<button

View file

@ -41,6 +41,7 @@ const createProps = (hasGroupLink = false, expireTimer?: number): Props => ({
},
areWeASubscriber: false,
canEditGroupInfo: false,
canAddNewMembers: false,
conversation: expireTimer
? {
...conversation,
@ -50,6 +51,7 @@ const createProps = (hasGroupLink = false, expireTimer?: number): Props => ({
hasActiveCall: false,
hasGroupLink,
getPreferredBadge: () => undefined,
groupsInCommon: [],
i18n,
isAdmin: false,
isGroup: true,
@ -90,6 +92,7 @@ const createProps = (hasGroupLink = false, expireTimer?: number): Props => ({
setMuteExpiration: action('setMuteExpiration'),
userAvatarData: [],
toggleSafetyNumberModal: action('toggleSafetyNumberModal'),
toggleAddUserToAnotherGroupModal: action('toggleAddUserToAnotherGroup'),
onOutgoingAudioCallInConversation: action(
'onOutgoingAudioCallInConversation'
),

View file

@ -45,6 +45,7 @@ import type {
SaveAvatarToDiskActionType,
} from '../../../types/Avatar';
import { isConversationMuted } from '../../../util/isConversationMuted';
import { ConversationDetailsGroups } from './ConversationDetailsGroups';
enum ModalState {
NothingOpen,
@ -60,6 +61,7 @@ export type StateProps = {
areWeASubscriber: boolean;
badges?: ReadonlyArray<BadgeType>;
canEditGroupInfo: boolean;
canAddNewMembers: boolean;
conversation?: ConversationType;
hasGroupLink: boolean;
getPreferredBadge: PreferredBadgeSelectorType;
@ -68,6 +70,7 @@ export type StateProps = {
isAdmin: boolean;
isGroup: boolean;
loadRecentMediaItems: (limit: number) => void;
groupsInCommon: Array<ConversationType>;
memberships: Array<GroupV2Membership>;
pendingApprovalMemberships: ReadonlyArray<GroupV2RequestingMembership>;
pendingMemberships: ReadonlyArray<GroupV2PendingMembership>;
@ -112,6 +115,7 @@ type ActionProps = {
showContactModal: (contactId: string, conversationId?: string) => void;
toggleSafetyNumberModal: (conversationId: string) => unknown;
searchInConversation: (id: string) => unknown;
toggleAddUserToAnotherGroupModal: (contactId?: string) => void;
};
export type Props = StateProps & ActionProps;
@ -121,10 +125,12 @@ export const ConversationDetails: React.ComponentType<Props> = ({
areWeASubscriber,
badges,
canEditGroupInfo,
canAddNewMembers,
conversation,
deleteAvatarFromDisk,
hasGroupLink,
getPreferredBadge,
groupsInCommon,
hasActiveCall,
i18n,
isAdmin,
@ -155,6 +161,7 @@ export const ConversationDetails: React.ComponentType<Props> = ({
showPendingInvites,
theme,
toggleSafetyNumberModal,
toggleAddUserToAnotherGroupModal,
updateGroupAttributes,
userAvatarData,
}) => {
@ -454,7 +461,7 @@ export const ConversationDetails: React.ComponentType<Props> = ({
{isGroup && (
<ConversationDetailsMembershipList
canAddNewMembers={canEditGroupInfo}
canAddNewMembers={canAddNewMembers}
conversationId={conversation.id}
getPreferredBadge={getPreferredBadge}
i18n={i18n}
@ -516,6 +523,15 @@ export const ConversationDetails: React.ComponentType<Props> = ({
showLightboxForMedia={showLightboxForMedia}
/>
{!isGroup && !conversation.isMe && (
<ConversationDetailsGroups
contactId={conversation.id}
i18n={i18n}
groupsInCommon={groupsInCommon}
toggleAddUserToAnotherGroupModal={toggleAddUserToAnotherGroupModal}
/>
)}
{!conversation.isMe && (
<ConversationDetailsActions
cannotLeaveBecauseYouAreLastAdmin={cannotLeaveBecauseYouAreLastAdmin}

View file

@ -0,0 +1,73 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React from 'react';
import type { ConversationType } from '../../../state/ducks/conversations';
import type { LocalizerType } from '../../../types/Util';
import { Avatar } from '../../Avatar';
import { ConversationDetailsIcon, IconType } from './ConversationDetailsIcon';
import { PanelRow } from './PanelRow';
import { PanelSection } from './PanelSection';
type Props = {
contactId: string;
i18n: LocalizerType;
groupsInCommon: Array<ConversationType>;
toggleAddUserToAnotherGroupModal: (contactId?: string) => void;
};
export const ConversationDetailsGroups = ({
contactId,
i18n,
groupsInCommon,
toggleAddUserToAnotherGroupModal,
}: Props): JSX.Element => {
const [showAllGroups, setShowAllGroups] = React.useState(false);
const maxShownGroupCount = 5;
const isMoreThanMaxShown = groupsInCommon.length - maxShownGroupCount > 1;
const groupsToShow = showAllGroups
? groupsInCommon.length
: maxShownGroupCount;
return (
<PanelSection
title={i18n('ConversationDetailsGroups--title', {
number: groupsInCommon.length,
})}
>
<PanelRow
icon={<div className="ConversationDetails-groups__add-to-group-icon" />}
label={i18n('ConversationDetailsGroups--add-to-group')}
onClick={() => toggleAddUserToAnotherGroupModal(contactId)}
/>
{groupsInCommon.slice(0, groupsToShow).map(group => (
<PanelRow
key={group.id}
icon={
<Avatar
conversationType="group"
badge={undefined}
i18n={i18n}
size={32}
{...group}
/>
}
label={group.title}
/>
))}
{!showAllGroups && isMoreThanMaxShown && (
<PanelRow
icon={
<ConversationDetailsIcon
ariaLabel={i18n('ConversationDetailsGroups--show-all')}
icon={IconType.down}
/>
}
onClick={() => setShowAllGroups(true)}
label={i18n('ConversationDetailsGroups--show-all')}
/>
)}
</PanelSection>
);
};