chore: cleanup requestresponse & communityinvitation control msg

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

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

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

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

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

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

@ -458,7 +458,7 @@ export class SwarmPolling {
resultsFromAllNamespaces resultsFromAllNamespaces
); );
window.log.debug( 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) // We always handle the config messages first (for groups 03 or our own messages)
await this.handleUserOrGroupConfMessages({ confMessages, pubkey, type }); await this.handleUserOrGroupConfMessages({ confMessages, pubkey, type });

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

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

@ -141,13 +141,14 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
: undefined; : undefined;
const common = { showUnreadIndicator: isFirstUnread, showDateBreak }; const common = { showUnreadIndicator: isFirstUnread, showDateBreak };
const messageIdProps = { messageId: msg.propsForMessage.id };
if (msg.propsForDataExtractionNotification) { if (msg.propsForDataExtractionNotification) {
return { return {
...common, ...common,
message: { message: {
messageType: 'data-extraction', messageType: 'data-extraction',
props: { ...msg.propsForDataExtractionNotification, messageId: msg.propsForMessage.id }, props: { ...msg.propsForDataExtractionNotification, ...messageIdProps },
}, },
}; };
} }
@ -157,7 +158,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
...common, ...common,
message: { message: {
messageType: 'message-request-response', messageType: 'message-request-response',
props: { ...msg.propsForMessageRequestResponse, messageId: msg.propsForMessage.id }, props: messageIdProps,
}, },
}; };
} }
@ -167,7 +168,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
...common, ...common,
message: { message: {
messageType: 'group-invitation', messageType: 'group-invitation',
props: { ...msg.propsForGroupInvitation, messageId: msg.propsForMessage.id }, props: messageIdProps,
}, },
}; };
} }
@ -177,7 +178,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
...common, ...common,
message: { message: {
messageType: 'group-notification', messageType: 'group-notification',
props: { ...msg.propsForGroupUpdateMessage, messageId: msg.propsForMessage.id }, props: { ...msg.propsForGroupUpdateMessage, ...messageIdProps },
}, },
}; };
} }
@ -187,7 +188,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
...common, ...common,
message: { message: {
messageType: 'timer-notification', 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', messageType: 'call-notification',
props: { props: {
...msg.propsForCallNotification, ...msg.propsForCallNotification,
messageId: msg.propsForMessage.id, ...messageIdProps,
}, },
}, },
}; };
@ -212,7 +213,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
messageType: 'interaction-notification', messageType: 'interaction-notification',
props: { props: {
...msg.propsForInteractionNotification, ...msg.propsForInteractionNotification,
messageId: msg.propsForMessage.id, ...messageIdProps,
}, },
}, },
}; };
@ -223,7 +224,7 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
showDateBreak, showDateBreak,
message: { message: {
messageType: 'regular-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 { LastMessageStatusType } from '../ducks/types';
import { PubKey } from '../../session/types'; import { PubKey } from '../../session/types';
import { useIsMe } from '../../hooks/useParamSelector'; import { useIsMe } from '../../hooks/useParamSelector';
import { UserUtils } from '../../session/utils';
function useMessagePropsByMessageId(messageId: string | undefined) { function useMessagePropsByMessageId(messageId: string | undefined) {
return useSelector((state: StateType) => getMessagePropsByMessageId(state, messageId)); return useSelector((state: StateType) => getMessagePropsByMessageId(state, messageId));
@ -83,6 +84,10 @@ export const useMessageAuthor = (messageId: string | undefined): string | undefi
return useMessagePropsByMessageId(messageId)?.propsForMessage.sender; return useMessagePropsByMessageId(messageId)?.propsForMessage.sender;
}; };
export const useMessageAuthorIsUs = (messageId: string | undefined): boolean => {
return UserUtils.isUsFromCache(useMessagePropsByMessageId(messageId)?.propsForMessage.sender);
};
export const useMessageDirection = ( export const useMessageDirection = (
messageId: string | undefined messageId: string | undefined
): MessageModelType | undefined => { ): MessageModelType | undefined => {
@ -129,6 +134,10 @@ export function useMessageReceivedAt(messageId: string | undefined) {
return useMessagePropsByMessageId(messageId)?.propsForMessage.receivedAt; return useMessagePropsByMessageId(messageId)?.propsForMessage.receivedAt;
} }
export function useMessageIsUnread(messageId: string | undefined) {
return useMessagePropsByMessageId(messageId)?.propsForMessage.isUnread;
}
export function useMessageTimestamp(messageId: string | undefined) { export function useMessageTimestamp(messageId: string | undefined) {
return useMessagePropsByMessageId(messageId)?.propsForMessage.timestamp; return useMessagePropsByMessageId(messageId)?.propsForMessage.timestamp;
} }
@ -174,3 +183,23 @@ export function useHideAvatarInMsgList(messageId?: string, isDetailView?: boolea
export function useMessageSelected(messageId?: string) { export function useMessageSelected(messageId?: string) {
return useSelector((state: StateType) => getIsMessageSelected(state, messageId)); 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