chore: cleanup requestresponse & communityinvitation control msg

pull/3281/head
Audric Ackermann 3 months ago
parent a80bbb00eb
commit f3cfe57764
No known key found for this signature in database

@ -2,15 +2,8 @@ import { useLayoutEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import useKey from 'react-use/lib/useKey';
import {
PropsForDataExtractionNotification,
PropsForMessageRequestResponse,
} from '../../models/messageType';
import {
PropsForExpirationTimer,
PropsForGroupInvitation,
PropsForGroupUpdate,
} from '../../state/ducks/conversations';
import { PropsForDataExtractionNotification } from '../../models/messageType';
import { PropsForExpirationTimer, PropsForGroupUpdate } from '../../state/ducks/conversations';
import {
getOldBottomMessageId,
getOldTopMessageId,
@ -18,7 +11,7 @@ import {
} from '../../state/selectors/conversations';
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
import { MessageDateBreak } from './message/message-item/DateBreak';
import { GroupInvitation } from './message/message-item/GroupInvitation';
import { CommunityInvitation } from './message/message-item/GroupInvitation';
import { GroupUpdateMessage } from './message/message-item/GroupUpdateMessage';
import { Message } from './message/message-item/Message';
import { MessageRequestResponse } from './message/message-item/MessageRequestResponse';
@ -127,14 +120,17 @@ export const SessionMessagesList = (props: {
}
if (messageProps.message?.messageType === 'group-invitation') {
const msgProps = messageProps.message.props as PropsForGroupInvitation;
return [<GroupInvitation key={messageId} {...msgProps} />, ...componentToMerge];
return [
<CommunityInvitation key={messageId} messageId={messageId} />,
...componentToMerge,
];
}
if (messageProps.message?.messageType === 'message-request-response') {
const msgProps = messageProps.message.props as PropsForMessageRequestResponse;
return [<MessageRequestResponse key={messageId} {...msgProps} />, ...componentToMerge];
return [
<MessageRequestResponse key={messageId} messageId={messageId} />,
...componentToMerge,
];
}
if (messageProps.message?.messageType === 'data-extraction') {

@ -2,12 +2,18 @@ import classNames from 'classnames';
import styled from 'styled-components';
import { useMemo } from 'react';
import { acceptOpenGroupInvitation } from '../../../../interactions/messageInteractions';
import { PropsForGroupInvitation } from '../../../../state/ducks/conversations';
import { SessionIconButton } from '../../../icon';
import { ExpirableReadableMessage } from './ExpirableReadableMessage';
const StyledGroupInvitation = styled.div`
import {
useMessageCommunityInvitationFullUrl,
useMessageCommunityInvitationCommunityName,
useMessageDirection,
} from '../../../../state/selectors';
import type { WithMessageId } from '../../../../session/types/with';
const StyledCommunityInvitation = styled.div`
background-color: var(--message-bubbles-received-background-color);
&.invitation-outgoing {
@ -67,14 +73,30 @@ const StyledIconContainer = styled.div`
border-radius: 100%;
`;
export const GroupInvitation = (props: PropsForGroupInvitation) => {
const { messageId } = props;
export const CommunityInvitation = ({ messageId }: WithMessageId) => {
const messageDirection = useMessageDirection(messageId);
const classes = ['group-invitation'];
if (props.direction === 'outgoing') {
const fullUrl = useMessageCommunityInvitationFullUrl(messageId);
const communityName = useMessageCommunityInvitationCommunityName(messageId);
const hostname = useMemo(() => {
try {
const url = new URL(fullUrl || '');
return url.origin;
} catch (e) {
window?.log?.warn('failed to get hostname from open groupv2 invitation', fullUrl);
return '';
}
}, [fullUrl]);
if (messageDirection === 'outgoing') {
classes.push('invitation-outgoing');
}
const openGroupInvitation = window.i18n('communityInvitation');
if (!fullUrl || !hostname) {
return null;
}
return (
<ExpirableReadableMessage
@ -82,29 +104,29 @@ export const GroupInvitation = (props: PropsForGroupInvitation) => {
key={`readable-message-${messageId}`}
dataTestId="control-message"
>
<StyledGroupInvitation className={classNames(classes)}>
<StyledCommunityInvitation className={classNames(classes)}>
<div className="contents">
<StyledIconContainer>
<SessionIconButton
iconColor={
props.direction === 'outgoing'
messageDirection === 'outgoing'
? 'var(--message-bubbles-sent-text-color)'
: 'var(--message-bubbles-received-text-color)'
}
iconType={props.direction === 'outgoing' ? 'communities' : 'plus'}
iconType={messageDirection === 'outgoing' ? 'communities' : 'plus'}
iconSize={'large'}
onClick={() => {
acceptOpenGroupInvitation(props.acceptUrl, props.serverName);
acceptOpenGroupInvitation(fullUrl, communityName);
}}
/>
</StyledIconContainer>
<span className="group-details">
<span className="group-name">{props.serverName}</span>
<span className="group-type">{openGroupInvitation}</span>
<span className="group-address">{props.url}</span>
<span className="group-name">{communityName}</span>
<span className="group-type">{window.i18n('communityInvitation')}</span>
<span className="group-address">{hostname}</span>
</span>
</div>
</StyledGroupInvitation>
</StyledCommunityInvitation>
</ExpirableReadableMessage>
);
};

@ -1,17 +1,28 @@
import { useNicknameOrProfileNameOrShortenedPubkey } from '../../../../hooks/useParamSelector';
import { PropsForMessageRequestResponse } from '../../../../models/messageType';
import { UserUtils } from '../../../../session/utils';
import type { WithMessageId } from '../../../../session/types/with';
import {
useMessageAuthorIsUs,
useMessageIsUnread,
useMessageReceivedAt,
} from '../../../../state/selectors';
import { useSelectedConversationKey } from '../../../../state/selectors/selectedConversation';
import { Flex } from '../../../basic/Flex';
import { Localizer } from '../../../basic/Localizer';
import { SpacerSM, TextWithChildren } from '../../../basic/Text';
import { ReadableMessage } from './ReadableMessage';
// Note this should not respond to the disappearing message conversation setting so we use the ReadableMessage
export const MessageRequestResponse = (props: PropsForMessageRequestResponse) => {
const { messageId, isUnread, receivedAt, conversationId } = props;
// Note: this should not respond to the disappearing message conversation setting so we use the ReadableMessage directly
export const MessageRequestResponse = ({ messageId }: WithMessageId) => {
const conversationId = useSelectedConversationKey();
const receivedAt = useMessageReceivedAt(messageId);
const isUnread = useMessageIsUnread(messageId) || false;
const isUs = useMessageAuthorIsUs(messageId);
const name = useNicknameOrProfileNameOrShortenedPubkey(conversationId);
const isFromSync = props.source === UserUtils.getOurPubKeyStrFromCache();
if (!conversationId || !messageId) {
return null;
}
return (
<ReadableMessage
@ -31,7 +42,7 @@ export const MessageRequestResponse = (props: PropsForMessageRequestResponse) =>
>
<SpacerSM />
<TextWithChildren subtle={true} ellipsisOverflow={false} textAlign="center">
{isFromSync ? (
{isUs ? (
<Localizer
token="messageRequestYouHaveAccepted"
args={{

@ -2853,6 +2853,7 @@ async function cleanUpExpireHistoryFromConvo(conversationId: string, isPrivate:
conversationId,
isPrivate
);
window?.inboxStore?.dispatch(
messagesDeleted(updateIdsRemoved.map(m => ({ conversationId, messageId: m })))
);

@ -25,7 +25,6 @@ import {
MessageGroupUpdate,
MessageModelType,
PropsForDataExtractionNotification,
PropsForMessageRequestResponse,
fillMessageAttributesWithDefaults,
} from './messageType';
@ -87,7 +86,7 @@ import { Storage } from '../util/storage';
import { ConversationModel } from './conversation';
import { READ_MESSAGE_STATE } from './conversationAttributes';
import { ConversationInteractionStatus, ConversationInteractionType } from '../interactions/types';
import { LastMessageStatusType } from '../state/ducks/types';
import { LastMessageStatusType, type PropsForCallNotification } from '../state/ducks/types';
import {
getGroupDisplayPictureChangeStr,
getGroupNameChangeStr,
@ -132,8 +131,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
const propsForGroupInvitation = this.getPropsForGroupInvitation();
const propsForGroupUpdateMessage = this.getPropsForGroupUpdateMessage();
const propsForTimerNotification = this.getPropsForTimerNotification();
const propsForExpiringMessage = this.getPropsForExpiringMessage();
const propsForMessageRequestResponse = this.getPropsForMessageRequestResponse();
const isMessageResponse = this.isMessageRequestResponse();
const propsForQuote = this.getPropsForQuote();
const callNotificationType = this.get('callNotificationType');
const interactionNotification = this.getInteractionNotification();
@ -144,8 +142,8 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
if (propsForDataExtractionNotification) {
messageProps.propsForDataExtractionNotification = propsForDataExtractionNotification;
}
if (propsForMessageRequestResponse) {
messageProps.propsForMessageRequestResponse = propsForMessageRequestResponse;
if (isMessageResponse) {
messageProps.propsForMessageRequestResponse = isMessageResponse;
}
if (propsForGroupInvitation) {
messageProps.propsForGroupInvitation = propsForGroupInvitation;
@ -160,17 +158,12 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
messageProps.propsForQuote = propsForQuote;
}
if (propsForExpiringMessage) {
messageProps.propsForExpiringMessage = propsForExpiringMessage;
}
if (callNotificationType) {
messageProps.propsForCallNotification = {
const propsForCallNotification: PropsForCallNotification = {
messageId: this.id,
notificationType: callNotificationType,
receivedAt: this.get('received_at') || Date.now(),
isUnread: this.isUnread(),
...this.getPropsForExpiringMessage(),
};
messageProps.propsForCallNotification = propsForCallNotification;
}
if (interactionNotification) {
@ -449,7 +442,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
}
}
public getPropsForExpiringMessage(): PropsForExpiringMessage {
private getPropsForExpiringMessage(): PropsForExpiringMessage {
const expirationType = this.getExpirationType();
const expirationDurationMs = this.getExpireTimerSeconds()
? this.getExpireTimerSeconds() * DURATION.SECONDS
@ -477,7 +470,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
};
}
public getPropsForTimerNotification(): PropsForExpirationTimer | null {
private getPropsForTimerNotification(): PropsForExpirationTimer | null {
if (!this.isExpirationTimerUpdate()) {
return null;
}
@ -514,31 +507,19 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
return basicProps;
}
public getPropsForGroupInvitation(): PropsForGroupInvitation | null {
private getPropsForGroupInvitation(): PropsForGroupInvitation | null {
const invitation = this.getCommunityInvitation();
if (!invitation || !invitation.url) {
return null;
}
let serverAddress = '';
try {
const url = new URL(invitation.url);
serverAddress = url.origin;
} catch (e) {
window?.log?.warn('failed to get hostname from open groupv2 invitation', invitation);
}
return {
serverName: invitation.name,
url: serverAddress,
acceptUrl: invitation.url,
receivedAt: this.get('received_at'),
isUnread: this.isUnread(),
...this.getPropsForExpiringMessage(),
fullUrl: invitation.url,
};
}
public getPropsForDataExtractionNotification(): PropsForDataExtractionNotification | null {
private getPropsForDataExtractionNotification(): PropsForDataExtractionNotification | null {
if (!this.isDataExtractionNotification()) {
return null;
}
@ -560,31 +541,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
};
}
public getPropsForMessageRequestResponse(): PropsForMessageRequestResponse | null {
if (!this.isMessageRequestResponse()) {
return null;
}
const messageRequestResponse = this.get('messageRequestResponse');
if (!messageRequestResponse) {
window.log.warn('messageRequestResponse should not happen');
return null;
}
const contact = findAndFormatContact(messageRequestResponse.source);
return {
...messageRequestResponse,
name: contact.profileName || contact.name || messageRequestResponse.source,
messageId: this.id,
receivedAt: this.get('received_at'),
isUnread: this.isUnread(),
conversationId: this.get('conversationId'),
source: this.get('source'),
};
}
public getPropsForGroupUpdateMessage(): PropsForGroupUpdate | null {
private getPropsForGroupUpdateMessage(): PropsForGroupUpdate | null {
const groupUpdate = this.getGroupUpdateAsArray();
if (!groupUpdate || isEmpty(groupUpdate)) {
return null;
@ -782,7 +739,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
return props;
}
public getPropsForPreview(): Array<any> | null {
private getPropsForPreview(): Array<any> | null {
const previews = this.get('preview') || null;
if (!previews || previews.length === 0) {
@ -807,11 +764,11 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
});
}
public getPropsForReacts(): ReactionList | null {
private getPropsForReacts(): ReactionList | null {
return this.get('reacts') || null;
}
public getPropsForQuote(): PropsForQuote | null {
private getPropsForQuote(): PropsForQuote | null {
return this.get('quote') || null;
}

@ -1205,6 +1205,7 @@ function cleanUpExpirationTimerUpdateHistory(
)
.all({ conversationId });
// we keep at most one, so if we have <= 1, we can just return that nothing was removed.
if (rows.length <= 1) {
return [];
}

@ -458,7 +458,7 @@ export class SwarmPolling {
resultsFromAllNamespaces
);
window.log.debug(
`SwarmPolling: received confMessages:${confMessages?.length || 0}, revokedMessages:${revokedMessages?.length || 0}, , otherMessages:${otherMessages?.length || 0}, `
`SwarmPolling: received for ${ed25519Str(pubkey)} confMessages:${confMessages?.length || 0}, revokedMessages:${revokedMessages?.length || 0}, , otherMessages:${otherMessages?.length || 0}, `
);
// We always handle the config messages first (for groups 03 or our own messages)
await this.handleUserOrGroupConfMessages({ confMessages, pubkey, type });

@ -11,11 +11,7 @@ import {
ConversationAttributes,
ConversationNotificationSettingType,
} from '../../models/conversationAttributes';
import {
MessageModelType,
PropsForDataExtractionNotification,
PropsForMessageRequestResponse,
} from '../../models/messageType';
import { MessageModelType, PropsForDataExtractionNotification } from '../../models/messageType';
import { ConvoHub } from '../../session/conversations';
import { DisappearingMessages } from '../../session/disappearing_messages';
import {
@ -36,13 +32,12 @@ import { WithConvoId, WithMessageHash, WithMessageId } from '../../session/types
export type MessageModelPropsWithoutConvoProps = {
propsForMessage: PropsForMessageWithoutConvoProps;
propsForExpiringMessage?: PropsForExpiringMessage;
propsForGroupInvitation?: PropsForGroupInvitation;
propsForTimerNotification?: PropsForExpirationTimer;
propsForDataExtractionNotification?: PropsForDataExtractionNotification;
propsForGroupUpdateMessage?: PropsForGroupUpdate;
propsForCallNotification?: PropsForCallNotification;
propsForMessageRequestResponse?: PropsForMessageRequestResponse;
propsForMessageRequestResponse?: boolean;
propsForQuote?: PropsForQuote;
propsForInteractionNotification?: PropsForInteractionNotification;
};
@ -137,10 +132,7 @@ export type PropsForGroupUpdate = {
export type PropsForGroupInvitation = {
serverName: string;
url: string;
direction: MessageModelType;
acceptUrl: string;
messageId: string;
fullUrl: string;
};
export type PropsForAttachment = AttachmentType & {

@ -6,8 +6,8 @@ import {
export type CallNotificationType = 'missed-call' | 'started-call' | 'answered-a-call';
export type PropsForCallNotification = {
notificationType: CallNotificationType;
messageId: string;
notificationType: CallNotificationType;
};
export type LastMessageStatusType = 'sending' | 'sent' | 'read' | 'error' | undefined;

@ -141,13 +141,14 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
: undefined;
const common = { showUnreadIndicator: isFirstUnread, showDateBreak };
const messageIdProps = { messageId: msg.propsForMessage.id };
if (msg.propsForDataExtractionNotification) {
return {
...common,
message: {
messageType: 'data-extraction',
props: { ...msg.propsForDataExtractionNotification, messageId: msg.propsForMessage.id },
props: { ...msg.propsForDataExtractionNotification, ...messageIdProps },
},
};
}
@ -157,7 +158,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
...common,
message: {
messageType: 'message-request-response',
props: { ...msg.propsForMessageRequestResponse, messageId: msg.propsForMessage.id },
props: messageIdProps,
},
};
}
@ -167,7 +168,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
...common,
message: {
messageType: 'group-invitation',
props: { ...msg.propsForGroupInvitation, messageId: msg.propsForMessage.id },
props: messageIdProps,
},
};
}
@ -177,7 +178,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
...common,
message: {
messageType: 'group-notification',
props: { ...msg.propsForGroupUpdateMessage, messageId: msg.propsForMessage.id },
props: { ...msg.propsForGroupUpdateMessage, ...messageIdProps },
},
};
}
@ -187,7 +188,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
...common,
message: {
messageType: 'timer-notification',
props: { ...msg.propsForTimerNotification, messageId: msg.propsForMessage.id },
props: { ...msg.propsForTimerNotification, ...messageIdProps },
},
};
}
@ -199,7 +200,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
messageType: 'call-notification',
props: {
...msg.propsForCallNotification,
messageId: msg.propsForMessage.id,
...messageIdProps,
},
},
};
@ -212,7 +213,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
messageType: 'interaction-notification',
props: {
...msg.propsForInteractionNotification,
messageId: msg.propsForMessage.id,
...messageIdProps,
},
},
};
@ -223,7 +224,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
showDateBreak,
message: {
messageType: 'regular-message',
props: { messageId: msg.propsForMessage.id },
props: messageIdProps,
},
};
});

@ -12,6 +12,7 @@ import { useSelectedIsPrivate } from './selectedConversation';
import { LastMessageStatusType } from '../ducks/types';
import { PubKey } from '../../session/types';
import { useIsMe } from '../../hooks/useParamSelector';
import { UserUtils } from '../../session/utils';
function useMessagePropsByMessageId(messageId: string | undefined) {
return useSelector((state: StateType) => getMessagePropsByMessageId(state, messageId));
@ -83,6 +84,10 @@ export const useMessageAuthor = (messageId: string | undefined): string | undefi
return useMessagePropsByMessageId(messageId)?.propsForMessage.sender;
};
export const useMessageAuthorIsUs = (messageId: string | undefined): boolean => {
return UserUtils.isUsFromCache(useMessagePropsByMessageId(messageId)?.propsForMessage.sender);
};
export const useMessageDirection = (
messageId: string | undefined
): MessageModelType | undefined => {
@ -129,6 +134,10 @@ export function useMessageReceivedAt(messageId: string | undefined) {
return useMessagePropsByMessageId(messageId)?.propsForMessage.receivedAt;
}
export function useMessageIsUnread(messageId: string | undefined) {
return useMessagePropsByMessageId(messageId)?.propsForMessage.isUnread;
}
export function useMessageTimestamp(messageId: string | undefined) {
return useMessagePropsByMessageId(messageId)?.propsForMessage.timestamp;
}
@ -174,3 +183,23 @@ export function useHideAvatarInMsgList(messageId?: string, isDetailView?: boolea
export function useMessageSelected(messageId?: string) {
return useSelector((state: StateType) => getIsMessageSelected(state, messageId));
}
/**
* ==================================================
* Below are selectors for community invitation props
* ==================================================
*/
/**
* Return the full url needed to join a community through a community invitation message
*/
export function useMessageCommunityInvitationFullUrl(messageId: string) {
return useMessagePropsByMessageId(messageId)?.propsForGroupInvitation?.fullUrl;
}
/**
* Return the community display name to have a guess of what a community is about
*/
export function useMessageCommunityInvitationCommunityName(messageId: string) {
return useMessagePropsByMessageId(messageId)?.propsForGroupInvitation?.serverName;
}

Loading…
Cancel
Save