Fix inaccurate numbers on group details screen
This commit is contained in:
parent
984b5e2b44
commit
a8346c490e
8 changed files with 324 additions and 52 deletions
|
@ -45,6 +45,13 @@ const createProps = (hasGroupLink = false): Props => ({
|
||||||
isMe: i === 2,
|
isMe: i === 2,
|
||||||
}),
|
}),
|
||||||
})),
|
})),
|
||||||
|
pendingApprovalMemberships: times(8, () => ({
|
||||||
|
member: getDefaultConversation(),
|
||||||
|
})),
|
||||||
|
pendingMemberships: times(5, () => ({
|
||||||
|
metadata: {},
|
||||||
|
member: getDefaultConversation(),
|
||||||
|
})),
|
||||||
setDisappearingMessages: action('setDisappearingMessages'),
|
setDisappearingMessages: action('setDisappearingMessages'),
|
||||||
showAllMedia: action('showAllMedia'),
|
showAllMedia: action('showAllMedia'),
|
||||||
showContactModal: action('showContactModal'),
|
showContactModal: action('showContactModal'),
|
||||||
|
|
|
@ -22,6 +22,10 @@ import {
|
||||||
ConversationDetailsMembershipList,
|
ConversationDetailsMembershipList,
|
||||||
GroupV2Membership,
|
GroupV2Membership,
|
||||||
} from './ConversationDetailsMembershipList';
|
} from './ConversationDetailsMembershipList';
|
||||||
|
import {
|
||||||
|
GroupV2PendingMembership,
|
||||||
|
GroupV2RequestingMembership,
|
||||||
|
} from './PendingInvites';
|
||||||
import { EditConversationAttributesModal } from './EditConversationAttributesModal';
|
import { EditConversationAttributesModal } from './EditConversationAttributesModal';
|
||||||
import { RequestState } from './util';
|
import { RequestState } from './util';
|
||||||
|
|
||||||
|
@ -41,6 +45,8 @@ export type StateProps = {
|
||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
loadRecentMediaItems: (limit: number) => void;
|
loadRecentMediaItems: (limit: number) => void;
|
||||||
memberships: Array<GroupV2Membership>;
|
memberships: Array<GroupV2Membership>;
|
||||||
|
pendingApprovalMemberships: ReadonlyArray<GroupV2RequestingMembership>;
|
||||||
|
pendingMemberships: ReadonlyArray<GroupV2PendingMembership>;
|
||||||
setDisappearingMessages: (seconds: number) => void;
|
setDisappearingMessages: (seconds: number) => void;
|
||||||
showAllMedia: () => void;
|
showAllMedia: () => void;
|
||||||
showContactModal: (conversationId: string) => void;
|
showContactModal: (conversationId: string) => void;
|
||||||
|
@ -77,6 +83,8 @@ export const ConversationDetails: React.ComponentType<Props> = ({
|
||||||
isAdmin,
|
isAdmin,
|
||||||
loadRecentMediaItems,
|
loadRecentMediaItems,
|
||||||
memberships,
|
memberships,
|
||||||
|
pendingApprovalMemberships,
|
||||||
|
pendingMemberships,
|
||||||
setDisappearingMessages,
|
setDisappearingMessages,
|
||||||
showAllMedia,
|
showAllMedia,
|
||||||
showContactModal,
|
showContactModal,
|
||||||
|
@ -108,9 +116,6 @@ export const ConversationDetails: React.ComponentType<Props> = ({
|
||||||
throw new Error('ConversationDetails rendered without a conversation');
|
throw new Error('ConversationDetails rendered without a conversation');
|
||||||
}
|
}
|
||||||
|
|
||||||
const pendingMemberships = conversation.pendingMemberships || [];
|
|
||||||
const pendingApprovalMemberships =
|
|
||||||
conversation.pendingApprovalMemberships || [];
|
|
||||||
const invitesCount =
|
const invitesCount =
|
||||||
pendingMemberships.length + pendingApprovalMemberships.length;
|
pendingMemberships.length + pendingApprovalMemberships.length;
|
||||||
|
|
||||||
|
@ -213,6 +218,7 @@ export const ConversationDetails: React.ComponentType<Props> = ({
|
||||||
canEdit={canEditGroupInfo}
|
canEdit={canEditGroupInfo}
|
||||||
conversation={conversation}
|
conversation={conversation}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
|
memberships={memberships}
|
||||||
startEditing={() => {
|
startEditing={() => {
|
||||||
setModalState(ModalState.EditingGroupAttributes);
|
setModalState(ModalState.EditingGroupAttributes);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -27,7 +27,6 @@ const createConversation = (): ConversationType =>
|
||||||
type: 'group',
|
type: 'group',
|
||||||
lastUpdated: 0,
|
lastUpdated: 0,
|
||||||
title: text('conversation title', 'Some Conversation'),
|
title: text('conversation title', 'Some Conversation'),
|
||||||
memberships: new Array(number('conversation members length', 0)),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||||
|
@ -35,6 +34,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||||
i18n,
|
i18n,
|
||||||
canEdit: false,
|
canEdit: false,
|
||||||
startEditing: action('startEditing'),
|
startEditing: action('startEditing'),
|
||||||
|
memberships: new Array(number('conversation members length', 0)),
|
||||||
...overrideProps,
|
...overrideProps,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,14 @@ import { Avatar } from '../../Avatar';
|
||||||
import { Emojify } from '../Emojify';
|
import { Emojify } from '../Emojify';
|
||||||
import { LocalizerType } from '../../../types/Util';
|
import { LocalizerType } from '../../../types/Util';
|
||||||
import { ConversationType } from '../../../state/ducks/conversations';
|
import { ConversationType } from '../../../state/ducks/conversations';
|
||||||
|
import { GroupV2Membership } from './ConversationDetailsMembershipList';
|
||||||
import { bemGenerator } from './util';
|
import { bemGenerator } from './util';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
canEdit: boolean;
|
canEdit: boolean;
|
||||||
conversation: ConversationType;
|
conversation: ConversationType;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
|
memberships: Array<GroupV2Membership>;
|
||||||
startEditing: () => void;
|
startEditing: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,10 +24,9 @@ export const ConversationDetailsHeader: React.ComponentType<Props> = ({
|
||||||
canEdit,
|
canEdit,
|
||||||
conversation,
|
conversation,
|
||||||
i18n,
|
i18n,
|
||||||
|
memberships,
|
||||||
startEditing,
|
startEditing,
|
||||||
}) => {
|
}) => {
|
||||||
const memberships = conversation.memberships || [];
|
|
||||||
|
|
||||||
const contents = (
|
const contents = (
|
||||||
<>
|
<>
|
||||||
<Avatar
|
<Avatar
|
||||||
|
|
|
@ -12,10 +12,9 @@ import {
|
||||||
getCandidateContactsForNewGroup,
|
getCandidateContactsForNewGroup,
|
||||||
getConversationByIdSelector,
|
getConversationByIdSelector,
|
||||||
} from '../selectors/conversations';
|
} from '../selectors/conversations';
|
||||||
import { GroupV2Membership } from '../../components/conversation/conversation-details/ConversationDetailsMembershipList';
|
import { getGroupMemberships } from '../../util/getGroupMemberships';
|
||||||
import { getIntl } from '../selectors/user';
|
import { getIntl } from '../selectors/user';
|
||||||
import { MediaItemType } from '../../components/LightboxGallery';
|
import { MediaItemType } from '../../components/LightboxGallery';
|
||||||
import { isConversationUnregistered } from '../../util/isConversationUnregistered';
|
|
||||||
import { assert } from '../../util/assert';
|
import { assert } from '../../util/assert';
|
||||||
|
|
||||||
export type SmartConversationDetailsProps = {
|
export type SmartConversationDetailsProps = {
|
||||||
|
@ -59,17 +58,6 @@ const mapStateToProps = (
|
||||||
? conversation.canEditGroupInfo
|
? conversation.canEditGroupInfo
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
const memberships = (conversation.memberships || []).reduce(
|
|
||||||
(result: Array<GroupV2Membership>, membership) => {
|
|
||||||
const member = conversationSelector(membership.conversationId);
|
|
||||||
if (!member || isConversationUnregistered(member)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return [...result, { isAdmin: membership.isAdmin, member }];
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const isAdmin = Boolean(conversation?.areWeAdmin);
|
const isAdmin = Boolean(conversation?.areWeAdmin);
|
||||||
const candidateContactsToAdd = getCandidateContactsForNewGroup(state);
|
const candidateContactsToAdd = getCandidateContactsForNewGroup(state);
|
||||||
|
|
||||||
|
@ -80,7 +68,7 @@ const mapStateToProps = (
|
||||||
conversation,
|
conversation,
|
||||||
i18n: getIntl(state),
|
i18n: getIntl(state),
|
||||||
isAdmin,
|
isAdmin,
|
||||||
memberships,
|
...getGroupMemberships(conversation, conversationSelector),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { mapDispatchToProps } from '../actions';
|
import { mapDispatchToProps } from '../actions';
|
||||||
import {
|
import {
|
||||||
GroupV2PendingMembership,
|
|
||||||
GroupV2RequestingMembership,
|
|
||||||
PendingInvites,
|
PendingInvites,
|
||||||
PropsType,
|
PropsType,
|
||||||
} from '../../components/conversation/conversation-details/PendingInvites';
|
} from '../../components/conversation/conversation-details/PendingInvites';
|
||||||
|
@ -13,7 +11,7 @@ import { StateType } from '../reducer';
|
||||||
|
|
||||||
import { getIntl } from '../selectors/user';
|
import { getIntl } from '../selectors/user';
|
||||||
import { getConversationByIdSelector } from '../selectors/conversations';
|
import { getConversationByIdSelector } from '../selectors/conversations';
|
||||||
import { isConversationUnregistered } from '../../util/isConversationUnregistered';
|
import { getGroupMemberships } from '../../util/getGroupMemberships';
|
||||||
import { assert } from '../../util/assert';
|
import { assert } from '../../util/assert';
|
||||||
|
|
||||||
export type SmartPendingInvitesProps = {
|
export type SmartPendingInvitesProps = {
|
||||||
|
@ -35,39 +33,11 @@ const mapStateToProps = (
|
||||||
'<SmartPendingInvites> expected a conversation to be found'
|
'<SmartPendingInvites> expected a conversation to be found'
|
||||||
);
|
);
|
||||||
|
|
||||||
const pendingApprovalMemberships = (
|
|
||||||
conversation.pendingApprovalMemberships || []
|
|
||||||
).reduce((result: Array<GroupV2RequestingMembership>, membership) => {
|
|
||||||
const member = conversationSelector(membership.conversationId);
|
|
||||||
if (!member || isConversationUnregistered(member)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return [...result, { member }];
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const pendingMemberships = (conversation.pendingMemberships || []).reduce(
|
|
||||||
(result: Array<GroupV2PendingMembership>, membership) => {
|
|
||||||
const member = conversationSelector(membership.conversationId);
|
|
||||||
if (!member || isConversationUnregistered(member)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
...result,
|
|
||||||
{
|
|
||||||
member,
|
|
||||||
metadata: { addedByUserId: membership.addedByUserId },
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...props,
|
...props,
|
||||||
|
...getGroupMemberships(conversation, conversationSelector),
|
||||||
conversation,
|
conversation,
|
||||||
i18n: getIntl(state),
|
i18n: getIntl(state),
|
||||||
pendingApprovalMemberships,
|
|
||||||
pendingMemberships,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
235
ts/test-both/util/getGroupMemberships_test.ts
Normal file
235
ts/test-both/util/getGroupMemberships_test.ts
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import { assert } from 'chai';
|
||||||
|
import { ConversationType } from '../../state/ducks/conversations';
|
||||||
|
import { getDefaultConversation } from '../helpers/getDefaultConversation';
|
||||||
|
|
||||||
|
import { getGroupMemberships } from '../../util/getGroupMemberships';
|
||||||
|
|
||||||
|
describe('getGroupMemberships', () => {
|
||||||
|
const normalConversation1 = getDefaultConversation();
|
||||||
|
const normalConversation2 = getDefaultConversation();
|
||||||
|
const unregisteredConversation = getDefaultConversation({
|
||||||
|
discoveredUnregisteredAt: Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
|
function getConversationById(id: string): undefined | ConversationType {
|
||||||
|
return [
|
||||||
|
normalConversation1,
|
||||||
|
normalConversation2,
|
||||||
|
unregisteredConversation,
|
||||||
|
].find(conversation => conversation.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('memberships', () => {
|
||||||
|
it('returns an empty array if passed undefined', () => {
|
||||||
|
const conversation = {};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.memberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an empty array if passed an empty array', () => {
|
||||||
|
const conversation = { memberships: [] };
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.memberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("filters out conversation IDs that don't exist", () => {
|
||||||
|
const conversation = {
|
||||||
|
memberships: [
|
||||||
|
{
|
||||||
|
conversationId: 'garbage',
|
||||||
|
isAdmin: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.memberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('filters out unregistered conversations', () => {
|
||||||
|
const conversation = {
|
||||||
|
memberships: [
|
||||||
|
{
|
||||||
|
conversationId: unregisteredConversation.id,
|
||||||
|
isAdmin: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.memberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('hydrates memberships', () => {
|
||||||
|
const conversation = {
|
||||||
|
memberships: [
|
||||||
|
{
|
||||||
|
conversationId: normalConversation2.id,
|
||||||
|
isAdmin: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conversationId: normalConversation1.id,
|
||||||
|
isAdmin: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.memberships;
|
||||||
|
|
||||||
|
assert.lengthOf(result, 2);
|
||||||
|
assert.deepEqual(result[0], {
|
||||||
|
isAdmin: false,
|
||||||
|
member: normalConversation2,
|
||||||
|
});
|
||||||
|
assert.deepEqual(result[1], {
|
||||||
|
isAdmin: true,
|
||||||
|
member: normalConversation1,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('pendingApprovalMemberships', () => {
|
||||||
|
it('returns an empty array if passed undefined', () => {
|
||||||
|
const conversation = {};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.pendingApprovalMemberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an empty array if passed an empty array', () => {
|
||||||
|
const conversation = { pendingApprovalMemberships: [] };
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.pendingApprovalMemberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("filters out conversation IDs that don't exist", () => {
|
||||||
|
const conversation = {
|
||||||
|
pendingApprovalMemberships: [{ conversationId: 'garbage' }],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.pendingApprovalMemberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('filters out unregistered conversations', () => {
|
||||||
|
const conversation = {
|
||||||
|
pendingApprovalMemberships: [
|
||||||
|
{ conversationId: unregisteredConversation.id },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.pendingApprovalMemberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('hydrates pending-approval memberships', () => {
|
||||||
|
const conversation = {
|
||||||
|
pendingApprovalMemberships: [
|
||||||
|
{ conversationId: normalConversation2.id },
|
||||||
|
{ conversationId: normalConversation1.id },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.pendingApprovalMemberships;
|
||||||
|
|
||||||
|
assert.lengthOf(result, 2);
|
||||||
|
assert.deepEqual(result[0], { member: normalConversation2 });
|
||||||
|
assert.deepEqual(result[1], { member: normalConversation1 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('pendingMemberships', () => {
|
||||||
|
it('returns an empty array if passed undefined', () => {
|
||||||
|
const conversation = {};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.pendingMemberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns an empty array if passed an empty array', () => {
|
||||||
|
const conversation = { pendingMemberships: [] };
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.pendingMemberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("filters out conversation IDs that don't exist", () => {
|
||||||
|
const conversation = {
|
||||||
|
pendingMemberships: [
|
||||||
|
{ conversationId: 'garbage', addedByUserId: normalConversation1.id },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.pendingMemberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('filters out unregistered conversations', () => {
|
||||||
|
const conversation = {
|
||||||
|
pendingMemberships: [
|
||||||
|
{
|
||||||
|
conversationId: unregisteredConversation.id,
|
||||||
|
addedByUserId: normalConversation1.id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.pendingMemberships;
|
||||||
|
|
||||||
|
assert.isEmpty(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('hydrates pending memberships', () => {
|
||||||
|
const conversation = {
|
||||||
|
pendingMemberships: [
|
||||||
|
{ conversationId: normalConversation2.id, addedByUserId: 'abc' },
|
||||||
|
{ conversationId: normalConversation1.id, addedByUserId: 'xyz' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getGroupMemberships(conversation, getConversationById)
|
||||||
|
.pendingMemberships;
|
||||||
|
|
||||||
|
assert.lengthOf(result, 2);
|
||||||
|
assert.deepEqual(result[0], {
|
||||||
|
member: normalConversation2,
|
||||||
|
metadata: { addedByUserId: 'abc' },
|
||||||
|
});
|
||||||
|
assert.deepEqual(result[1], {
|
||||||
|
member: normalConversation1,
|
||||||
|
metadata: { addedByUserId: 'xyz' },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
65
ts/util/getGroupMemberships.ts
Normal file
65
ts/util/getGroupMemberships.ts
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import { GroupV2Membership } from '../components/conversation/conversation-details/ConversationDetailsMembershipList';
|
||||||
|
import {
|
||||||
|
GroupV2PendingMembership,
|
||||||
|
GroupV2RequestingMembership,
|
||||||
|
} from '../components/conversation/conversation-details/PendingInvites';
|
||||||
|
import { ConversationType } from '../state/ducks/conversations';
|
||||||
|
import { isConversationUnregistered } from './isConversationUnregistered';
|
||||||
|
|
||||||
|
export const getGroupMemberships = (
|
||||||
|
{
|
||||||
|
memberships = [],
|
||||||
|
pendingApprovalMemberships = [],
|
||||||
|
pendingMemberships = [],
|
||||||
|
}: Readonly<
|
||||||
|
Pick<
|
||||||
|
ConversationType,
|
||||||
|
'memberships' | 'pendingApprovalMemberships' | 'pendingMemberships'
|
||||||
|
>
|
||||||
|
>,
|
||||||
|
getConversationById: (conversationId: string) => undefined | ConversationType
|
||||||
|
): {
|
||||||
|
memberships: Array<GroupV2Membership>;
|
||||||
|
pendingApprovalMemberships: Array<GroupV2RequestingMembership>;
|
||||||
|
pendingMemberships: Array<GroupV2PendingMembership>;
|
||||||
|
} => ({
|
||||||
|
memberships: memberships.reduce(
|
||||||
|
(result: Array<GroupV2Membership>, membership) => {
|
||||||
|
const member = getConversationById(membership.conversationId);
|
||||||
|
if (!member || isConversationUnregistered(member)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return [...result, { isAdmin: membership.isAdmin, member }];
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
pendingApprovalMemberships: pendingApprovalMemberships.reduce(
|
||||||
|
(result: Array<GroupV2RequestingMembership>, membership) => {
|
||||||
|
const member = getConversationById(membership.conversationId);
|
||||||
|
if (!member || isConversationUnregistered(member)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return [...result, { member }];
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
pendingMemberships: pendingMemberships.reduce(
|
||||||
|
(result: Array<GroupV2PendingMembership>, membership) => {
|
||||||
|
const member = getConversationById(membership.conversationId);
|
||||||
|
if (!member || isConversationUnregistered(member)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
...result,
|
||||||
|
{
|
||||||
|
member,
|
||||||
|
metadata: { addedByUserId: membership.addedByUserId },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue