chore: cleanup expireationTimerUpdate msg

pull/3281/head
Audric Ackermann 10 months ago
parent 35c77accac
commit fac7960cc9
No known key found for this signature in database

@ -2,7 +2,7 @@ import { useLayoutEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import useKey from 'react-use/lib/useKey';
import { PropsForExpirationTimer, PropsForGroupUpdate } from '../../state/ducks/conversations';
import { PropsForGroupUpdate } from '../../state/ducks/conversations';
import {
getOldBottomMessageId,
getOldTopMessageId,
@ -21,7 +21,6 @@ import { SessionLastSeenIndicator } from './SessionLastSeenIndicator';
import { TimerNotification } from './TimerNotification';
import { DataExtractionNotification } from './message/message-item/DataExtractionNotification';
import { InteractionNotification } from './message/message-item/InteractionNotification';
import { PropsForInteractionNotification } from '../../state/ducks/types';
function isNotTextboxEvent(e: KeyboardEvent) {
return (e?.target as any)?.type === undefined;
@ -138,9 +137,7 @@ export const SessionMessagesList = (props: {
}
if (messageProps.message?.messageType === 'timer-notification') {
const msgProps = messageProps.message.props as PropsForExpirationTimer;
return [<TimerNotification key={messageId} {...msgProps} />, ...componentToMerge];
return [<TimerNotification key={messageId} messageId={messageId} />, ...componentToMerge];
}
if (messageProps.message?.messageType === 'call-notification') {
@ -148,9 +145,10 @@ export const SessionMessagesList = (props: {
}
if (messageProps.message?.messageType === 'interaction-notification') {
const msgProps = messageProps.message.props as PropsForInteractionNotification;
return [<InteractionNotification key={messageId} {...msgProps} />, ...componentToMerge];
return [
<InteractionNotification key={messageId} messageId={messageId} />,
...componentToMerge,
];
}
if (!messageProps) {

@ -1,9 +1,8 @@
import { useDispatch } from 'react-redux';
import styled from 'styled-components';
import { PubkeyType } from 'libsession_util_nodejs';
import { PropsForExpirationTimer } from '../../state/ducks/conversations';
import { isNil } from 'lodash';
import { UserUtils } from '../../session/utils';
import {
useSelectedConversationDisappearingMode,
useSelectedConversationKey,
@ -27,35 +26,44 @@ import { SessionButtonColor } from '../basic/SessionButton';
import { SessionIcon } from '../icon';
import { getTimerNotificationStr } from '../../models/timerNotifications';
import type { LocalizerComponentPropsObject } from '../../localization/localeTools';
import type { WithMessageId } from '../../session/types/with';
import {
useMessageAuthor,
useMessageAuthorIsUs,
useMessageExpirationUpdateDisabled,
useMessageExpirationUpdateMode,
useMessageExpirationUpdateTimespanSeconds,
useMessageExpirationUpdateTimespanText,
} from '../../state/selectors';
const FollowSettingButton = styled.button`
color: var(--primary-color);
`;
function useFollowSettingsButtonClick(
props: Pick<
PropsForExpirationTimer,
'disabled' | 'expirationMode' | 'timespanText' | 'timespanSeconds'
>
) {
function useFollowSettingsButtonClick({ messageId }: WithMessageId) {
const selectedConvoKey = useSelectedConversationKey();
const timespanSeconds = useMessageExpirationUpdateTimespanSeconds(messageId) || 0;
const expirationMode = useMessageExpirationUpdateMode(messageId) || 'off';
const disabled = useMessageExpirationUpdateDisabled(messageId) || false;
const timespanText = useMessageExpirationUpdateTimespanText(messageId) || '';
const dispatch = useDispatch();
const onExit = () => dispatch(updateConfirmModal(null));
const doIt = () => {
const localizedMode =
props.expirationMode === 'deleteAfterRead'
expirationMode === 'deleteAfterRead'
? window.i18n('disappearingMessagesTypeRead')
: window.i18n('disappearingMessagesTypeSent');
const i18nMessage: LocalizerComponentPropsObject = props.disabled
const i18nMessage: LocalizerComponentPropsObject = disabled
? {
token: 'disappearingMessagesFollowSettingOff',
}
: {
token: 'disappearingMessagesFollowSettingOn',
args: {
time: props.timespanText,
time: timespanText,
disappearing_messages_type: localizedMode,
},
};
@ -79,16 +87,16 @@ function useFollowSettingsButtonClick(
if (!convo.isPrivate()) {
throw new Error('follow settings only work for private chats');
}
if (props.expirationMode === 'legacy') {
if (expirationMode === 'legacy') {
throw new Error('follow setting does not apply with legacy');
}
if (props.expirationMode !== 'off' && !props.timespanSeconds) {
if (expirationMode !== 'off' && !timespanSeconds) {
throw new Error('non-off mode requires seconds arg to be given');
}
await ConversationInteraction.setDisappearingMessagesByConvoId(
selectedConvoKey,
props.expirationMode,
props.timespanSeconds ?? undefined
expirationMode,
timespanSeconds ?? undefined
);
},
showExitIcon: false,
@ -99,36 +107,43 @@ function useFollowSettingsButtonClick(
return { doIt };
}
function useAreSameThanOurSide(
props: Pick<PropsForExpirationTimer, 'disabled' | 'expirationMode' | 'timespanSeconds'>
) {
function useAreSameThanOurSide({ messageId }: WithMessageId) {
const timespanSeconds = useMessageExpirationUpdateTimespanSeconds(messageId) || 0;
const expirationMode = useMessageExpirationUpdateMode(messageId) || 'off';
const disabled = useMessageExpirationUpdateDisabled(messageId) || false;
const selectedMode = useSelectedConversationDisappearingMode();
const selectedTimespan = useSelectedExpireTimer();
if (props.disabled && (selectedMode === 'off' || selectedMode === undefined)) {
if (disabled && (selectedMode === 'off' || selectedMode === undefined)) {
return true;
}
if (props.expirationMode === selectedMode && props.timespanSeconds === selectedTimespan) {
if (expirationMode === selectedMode && timespanSeconds === selectedTimespan) {
return true;
}
return false;
}
const FollowSettingsButton = (props: PropsForExpirationTimer) => {
const FollowSettingsButton = ({ messageId }: WithMessageId) => {
const v2Released = ReleasedFeatures.isUserConfigFeatureReleasedCached();
const isPrivateAndFriend = useSelectedIsPrivateFriend();
const click = useFollowSettingsButtonClick(props);
const areSameThanOurs = useAreSameThanOurSide(props);
const expirationMode = useMessageExpirationUpdateMode(messageId) || 'off';
const authorIsUs = useMessageAuthorIsUs(messageId);
const click = useFollowSettingsButtonClick({
messageId,
});
const areSameThanOurs = useAreSameThanOurSide({ messageId });
if (!v2Released || !isPrivateAndFriend) {
return null;
}
if (
props.type === 'fromMe' ||
props.type === 'fromSync' ||
props.pubkey === UserUtils.getOurPubKeyStrFromCache() ||
authorIsUs ||
areSameThanOurs ||
props.expirationMode === 'legacy' // we cannot follow settings with legacy mode
expirationMode === 'legacy' // we cannot follow settings with legacy mode
) {
return null;
}
@ -143,14 +158,18 @@ const FollowSettingsButton = (props: PropsForExpirationTimer) => {
);
};
export const TimerNotification = (props: PropsForExpirationTimer) => {
const { messageId, expirationMode, pubkey, timespanSeconds } = props;
export const TimerNotification = (props: WithMessageId) => {
const { messageId } = props;
const timespanSeconds = useMessageExpirationUpdateTimespanSeconds(messageId);
const expirationMode = useMessageExpirationUpdateMode(messageId);
const disabled = useMessageExpirationUpdateDisabled(messageId);
const pubkey = useMessageAuthor(messageId);
const convoId = useSelectedConversationKey();
const isGroupOrCommunity = useSelectedIsGroupOrCommunity();
const isGroupV2 = useSelectedIsGroupV2();
const isPublic = useSelectedIsPublic();
if (!convoId) {
if (!convoId || !messageId || isNil(timespanSeconds) || isNil(expirationMode)) {
return null;
}
@ -163,7 +182,7 @@ export const TimerNotification = (props: PropsForExpirationTimer) => {
});
// renderOff is true when the update is put to off, or when we have a legacy group control message (as they are not expiring at all)
const renderOffIcon = props.disabled || (isGroupOrCommunity && isPublic && !isGroupV2);
const renderOffIcon = disabled || (isGroupOrCommunity && isPublic && !isGroupV2);
return (
<ExpirableReadableMessage

@ -1,10 +1,6 @@
import { isEmpty } from 'lodash';
import styled from 'styled-components';
import {
useIsPrivate,
useIsPublic,
useNicknameOrProfileNameOrShortenedPubkey,
} from '../../../../hooks/useParamSelector';
import { useNicknameOrProfileNameOrShortenedPubkey } from '../../../../hooks/useParamSelector';
import { assertUnreachable } from '../../../../types/sqlSharedTypes';
import { Flex } from '../../../basic/Flex';
import { ReadableMessage } from './ReadableMessage';
@ -12,21 +8,37 @@ import {
ConversationInteractionStatus,
ConversationInteractionType,
} from '../../../../interactions/types';
import { PropsForInteractionNotification } from '../../../../state/ducks/types';
import {
useSelectedConversationKey,
useSelectedIsPrivate,
useSelectedIsPublic,
} from '../../../../state/selectors/selectedConversation';
import {
useMessageInteractionNotification,
useMessageIsUnread,
useMessageReceivedAt,
} from '../../../../state/selectors';
import type { WithMessageId } from '../../../../session/types/with';
const StyledFailText = styled.div`
color: var(--danger-color);
`;
export const InteractionNotification = (props: PropsForInteractionNotification) => {
const { notificationType, convoId, messageId, receivedAt, isUnread } = props;
const { interactionStatus, interactionType } = notificationType;
export const InteractionNotification = (props: WithMessageId) => {
const { messageId } = props;
const convoId = useSelectedConversationKey();
const displayName = useNicknameOrProfileNameOrShortenedPubkey(convoId);
const isGroup = !useSelectedIsPrivate();
const isCommunity = useSelectedIsPublic();
const isUnread = useMessageIsUnread(messageId) || false;
const receivedAt = useMessageReceivedAt(messageId);
const interactionNotification = useMessageInteractionNotification(messageId);
const isGroup = !useIsPrivate(convoId);
const isCommunity = useIsPublic(convoId);
if (!convoId || !messageId || !interactionNotification) {
return null;
}
const { interactionStatus, interactionType } = interactionNotification;
// NOTE at this time we don't show visible control messages in communities, that might change in future...
if (isCommunity) {

@ -141,7 +141,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
messageProps.propsForDataExtractionNotification = propsForDataExtractionNotification;
}
if (isMessageResponse) {
messageProps.propsForMessageRequestResponse = isMessageResponse;
messageProps.propsForMessageRequestResponse = {};
}
if (propsForGroupInvitation) {
messageProps.propsForGroupInvitation = propsForGroupInvitation;
@ -167,10 +167,6 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
if (interactionNotification) {
messageProps.propsForInteractionNotification = {
notificationType: interactionNotification,
convoId: this.get('conversationId'),
messageId: this.id,
receivedAt: this.get('received_at') || Date.now(),
isUnread: this.isUnread(),
};
}
@ -375,7 +371,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
expireTimer
);
const source = expireTimerUpdate?.source;
const source = this.get('source');
const i18nProps = getTimerNotificationStr({
convoId: convo.id,
author: source as PubkeyType,
@ -462,11 +458,11 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
const timerUpdate = this.getExpirationTimerUpdate();
const convo = this.getConversation();
if (!timerUpdate || !timerUpdate.source || !convo) {
if (!timerUpdate || !this.get('source') || !convo) {
return null;
}
const { expireTimer, fromSync, source } = timerUpdate;
const { expireTimer } = timerUpdate;
const expirationMode = DisappearingMessages.changeToDisappearingConversationMode(
convo,
timerUpdate?.expirationType || 'unknown',
@ -474,18 +470,11 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
);
const timespanText = TimerOptions.getName(expireTimer || 0);
const disabled = !expireTimer;
const basicProps: PropsForExpirationTimer = {
...findAndFormatContact(source),
timespanText,
timespanSeconds: expireTimer || 0,
disabled,
type: fromSync ? 'fromSync' : UserUtils.isUsFromCache(source) ? 'fromMe' : 'fromOther',
receivedAt: this.get('received_at'),
isUnread: this.isUnread(),
expirationMode: expirationMode || 'off',
...this.getPropsForExpiringMessage(),
};
return basicProps;

@ -20,9 +20,6 @@ export type DisappearingMessageConversationModeType =
export type ExpirationTimerUpdate = {
expirationType: DisappearingMessageType | undefined;
expireTimer: number;
source: string;
/** updated setting from another device */
fromSync?: boolean;
};
export type DisappearingMessageUpdate = {

@ -25,6 +25,7 @@ import {
LastMessageType,
PropsForCallNotification,
PropsForInteractionNotification,
type PropsForMessageRequestResponse,
} from './types';
import { AttachmentType } from '../../types/Attachment';
import { CONVERSATION_PRIORITIES, ConversationTypeEnum } from '../../models/types';
@ -32,14 +33,14 @@ import { WithConvoId, WithMessageHash, WithMessageId } from '../../session/types
export type MessageModelPropsWithoutConvoProps = {
propsForMessage: PropsForMessageWithoutConvoProps;
propsForGroupInvitation?: PropsForGroupInvitation;
propsForGroupInvitation?: PropsForGroupInvitation; // plop: cleaned up
propsForTimerNotification?: PropsForExpirationTimer;
propsForDataExtractionNotification?: PropsForDataExtractionNotification;
propsForDataExtractionNotification?: PropsForDataExtractionNotification; // plop: cleaned up
propsForGroupUpdateMessage?: PropsForGroupUpdate;
propsForCallNotification?: PropsForCallNotification;
propsForMessageRequestResponse?: boolean;
propsForCallNotification?: PropsForCallNotification; // plop: cleaned up
propsForMessageRequestResponse?: PropsForMessageRequestResponse; // plop: cleaned up
propsForQuote?: PropsForQuote;
propsForInteractionNotification?: PropsForInteractionNotification;
propsForInteractionNotification?: PropsForInteractionNotification; // plop: cleaned up
};
export type MessageModelPropsWithConvoProps = SortedMessageModelProps & {
@ -78,13 +79,6 @@ export type PropsForExpirationTimer = {
expirationMode: DisappearingMessageConversationModeType;
timespanText: string;
timespanSeconds: number | null;
disabled: boolean;
pubkey: string;
avatarPath: string | null;
name: string | null;
profileName: string | null;
type: 'fromMe' | 'fromSync' | 'fromOther';
messageId: string;
};
export type PropsForGroupUpdateAdd = {
@ -161,7 +155,6 @@ export type PropsForMessageWithoutConvoProps = {
sender: string; // this is the sender
convoId: string; // this is the conversation in which this message was sent
text?: string;
receivedAt?: number;
serverTimestamp?: number;
serverId?: number;

@ -10,6 +10,10 @@ export type PropsForCallNotification = {
notificationType: CallNotificationType;
};
export type PropsForMessageRequestResponse = {
// keeping this an object in case we need to add some details here
};
export type LastMessageStatusType = 'sending' | 'sent' | 'read' | 'error' | undefined;
export type LastMessageType = {
@ -26,8 +30,4 @@ export type InteractionNotificationType = {
export type PropsForInteractionNotification = {
notificationType: InteractionNotificationType;
convoId: string;
messageId: string;
receivedAt: number;
isUnread: boolean;
};

@ -188,7 +188,6 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
...common,
message: {
messageType: 'timer-notification',
props: { ...msg.propsForTimerNotification },
},
};
}
@ -198,9 +197,6 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
...common,
message: {
messageType: 'call-notification',
props: {
...msg.propsForCallNotification,
},
},
};
}
@ -210,9 +206,6 @@ export const getSortedMessagesTypesOfSelectedConversation = createSelector(
...common,
message: {
messageType: 'interaction-notification',
props: {
...msg.propsForInteractionNotification,
},
},
};
}

@ -216,3 +216,51 @@ export function useMessageCommunityInvitationCommunityName(messageId: string) {
export function useMessageCallNotificationType(messageId: string) {
return useMessagePropsByMessageId(messageId)?.propsForCallNotification?.notificationType;
}
/**
* ================================================
* Below are selectors for interaction notification
* ================================================
*/
/**
* Return the call notification type linked to the specified message
*/
export function useMessageInteractionNotification(messageId: string) {
return useMessagePropsByMessageId(messageId)?.propsForInteractionNotification?.notificationType;
}
/**
* ================================================
* Below are selectors for expiration timer updates
* ================================================
*/
/**
* Return the expiration update mode linked to the specified message
*/
export function useMessageExpirationUpdateMode(messageId: string) {
return useMessagePropsByMessageId(messageId)?.propsForTimerNotification?.expirationMode;
}
/**
* Return true if the message is disabling expiration timer update (timespanSeconds === 0)
*/
export function useMessageExpirationUpdateDisabled(messageId: string) {
const timespanSeconds = useMessageExpirationUpdateTimespanSeconds(messageId);
return timespanSeconds === 0;
}
/**
* Return the timespan in seconds to which this expiration timer update is sett
*/
export function useMessageExpirationUpdateTimespanSeconds(messageId: string) {
return useMessagePropsByMessageId(messageId)?.propsForTimerNotification?.timespanSeconds;
}
/**
* Return the timespan in text (localised) built from the field timespanSeconds
*/
export function useMessageExpirationUpdateTimespanText(messageId: string) {
return useMessagePropsByMessageId(messageId)?.propsForTimerNotification?.timespanText;
}

@ -392,7 +392,6 @@ describe('DisappearingMessage', () => {
expirationTimerUpdate: {
expirationType: 'deleteAfterSend',
expireTimer: 300,
source: testPubkey,
},
});
@ -426,7 +425,6 @@ describe('DisappearingMessage', () => {
expirationTimerUpdate: {
expirationType: 'deleteAfterSend',
expireTimer: 300,
source: testPubkey,
},
});
@ -631,7 +629,6 @@ describe('DisappearingMessage', () => {
const expirationTimerUpdateMessage = generateFakeExpirationTimerUpdate({
expirationType: 'deleteAfterSend',
expireTimer: 300,
source: testPubkey,
});
expect(expirationTimerUpdateMessage.get('flags'), 'flags should be 2').to.equal(2);

@ -171,11 +171,9 @@ export function generateDisappearingVisibleMessage({
export function generateFakeExpirationTimerUpdate({
expirationType,
expireTimer,
source = '',
}: {
expirationType: DisappearingMessageType;
expireTimer: number;
source?: string;
}): MessageModel {
const convoId = TestUtils.generateFakePubKeyStr();
return new MessageModel({
@ -187,7 +185,6 @@ export function generateFakeExpirationTimerUpdate({
expirationTimerUpdate: {
expirationType,
expireTimer,
source,
},
flags: 2,
});

Loading…
Cancel
Save