Implemented ability to quickly add a user to a group
This commit is contained in:
parent
190cd9408b
commit
22bf3ebcc0
30 changed files with 855 additions and 70 deletions
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
),
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue