diff --git a/ts/components/ConversationListItem.tsx b/ts/components/ConversationListItem.tsx index ebdd01aee..b17f00bbd 100644 --- a/ts/components/ConversationListItem.tsx +++ b/ts/components/ConversationListItem.tsx @@ -66,6 +66,8 @@ const ConversationListItem = (props: Props) => { type, lastMessage, memberAvatars, + notificationForConvo, + currentNotificationSetting, } = props; const triggerId: string = `conversation-item-${phoneNumber}-ctxmenu`; const key: string = `conversation-item-${phoneNumber}`; @@ -119,7 +121,14 @@ const ConversationListItem = (props: Props) => { - + ); diff --git a/ts/components/conversation/ConversationHeader.tsx b/ts/components/conversation/ConversationHeader.tsx index f18548455..45af09034 100644 --- a/ts/components/conversation/ConversationHeader.tsx +++ b/ts/components/conversation/ConversationHeader.tsx @@ -16,17 +16,13 @@ import { import { contextMenu } from 'react-contexify'; import { DefaultTheme, withTheme } from 'styled-components'; import { ConversationNotificationSettingType } from '../../models/conversation'; +import { NotificationForConvoOption } from '../../state/ducks/conversations'; export interface TimerOption { name: string; value: number; } -export interface NotificationForConvoOption { - name: string; - value: ConversationNotificationSettingType; -} - interface Props { id: string; name?: string; diff --git a/ts/components/session/conversation/SessionConversation.tsx b/ts/components/session/conversation/SessionConversation.tsx index dddb87f62..82bdb317e 100644 --- a/ts/components/session/conversation/SessionConversation.tsx +++ b/ts/components/session/conversation/SessionConversation.tsx @@ -352,13 +352,7 @@ export class SessionConversation extends React.Component { const members = conversation.get('members') || []; - // exclude mentions_only settings for private chats as this does not make much sense - const notificationForConvo = ConversationNotificationSetting.filter(n => - conversation.isPrivate() ? n !== 'mentions_only' : true - ).map((n: ConversationNotificationSettingType) => { - // this link to the notificationForConvo_all, notificationForConvo_mentions_only, ... - return { value: n, name: window.i18n(`notificationForConvo_${n}`) }; - }); + const notificationForConvo = conversation.getConversationNotificationSettingType(); const headerProps = { id: conversation.id, diff --git a/ts/components/session/menu/ConversationHeaderMenu.tsx b/ts/components/session/menu/ConversationHeaderMenu.tsx index 40b9f97c8..662379c36 100644 --- a/ts/components/session/menu/ConversationHeaderMenu.tsx +++ b/ts/components/session/menu/ConversationHeaderMenu.tsx @@ -13,11 +13,13 @@ import { getLeaveGroupMenuItem, getMarkAllReadMenuItem, getNotificationForConvoMenuItem, + getPinConversationMenuItem, getRemoveModeratorsMenuItem, getUpdateGroupNameMenuItem, } from './Menu'; -import { NotificationForConvoOption, TimerOption } from '../../conversation/ConversationHeader'; +import { TimerOption } from '../../conversation/ConversationHeader'; import { ConversationNotificationSettingType } from '../../../models/conversation'; +import { NotificationForConvoOption } from '../../../state/ducks/conversations'; export type PropsConversationHeaderMenu = { conversationId: string; @@ -74,6 +76,7 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => { currentNotificationSetting, conversationId )} + {getPinConversationMenuItem(conversationId)} {getBlockMenuItem(isMe, isPrivate, isBlocked, conversationId)} {getCopyMenuItem(isPublic, isGroup, conversationId)} diff --git a/ts/components/session/menu/ConversationListItemContextMenu.tsx b/ts/components/session/menu/ConversationListItemContextMenu.tsx index 740eacfa1..17f5821cb 100644 --- a/ts/components/session/menu/ConversationListItemContextMenu.tsx +++ b/ts/components/session/menu/ConversationListItemContextMenu.tsx @@ -1,6 +1,10 @@ import React from 'react'; import { animation, Menu } from 'react-contexify'; -import { ConversationTypeEnum } from '../../../models/conversation'; +import { + ConversationNotificationSettingType, + ConversationTypeEnum, +} from '../../../models/conversation'; +import { NotificationForConvoOption } from '../../../state/ducks/conversations'; import { getBlockMenuItem, @@ -12,6 +16,7 @@ import { getInviteContactMenuItem, getLeaveGroupMenuItem, getMarkAllReadMenuItem, + getNotificationForConvoMenuItem, getPinConversationMenuItem, } from './Menu'; @@ -26,6 +31,8 @@ export type PropsContextConversationItem = { isKickedFromGroup?: boolean; left?: boolean; theme?: any; + notificationForConvo: Array; + currentNotificationSetting: ConversationNotificationSettingType; }; export const ConversationListItemContextMenu = (props: PropsContextConversationItem) => { @@ -39,6 +46,8 @@ export const ConversationListItemContextMenu = (props: PropsContextConversationI type, left, isKickedFromGroup, + notificationForConvo, + currentNotificationSetting, } = props; const isGroup = type === 'group'; @@ -46,6 +55,14 @@ export const ConversationListItemContextMenu = (props: PropsContextConversationI return ( <> + {getNotificationForConvoMenuItem( + isKickedFromGroup, + left, + isBlocked, + notificationForConvo, + currentNotificationSetting, + conversationId + )} {getPinConversationMenuItem(conversationId)} {getBlockMenuItem(isMe, type === ConversationTypeEnum.PRIVATE, isBlocked, conversationId)} {getCopyMenuItem(isPublic, isGroup, conversationId)} diff --git a/ts/components/session/menu/Menu.tsx b/ts/components/session/menu/Menu.tsx index 9c4886aab..bdfb16a62 100644 --- a/ts/components/session/menu/Menu.tsx +++ b/ts/components/session/menu/Menu.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { getNumberOfPinnedConversations } from '../../../state/selectors/conversations'; import { getFocusedSection } from '../../../state/selectors/section'; -import { NotificationForConvoOption, TimerOption } from '../../conversation/ConversationHeader'; +import { TimerOption } from '../../conversation/ConversationHeader'; import { Item, Submenu } from 'react-contexify'; import { ConversationNotificationSettingType } from '../../../models/conversation'; import { useDispatch, useSelector } from 'react-redux'; @@ -26,6 +26,7 @@ import { } from '../../../interactions/conversationInteractions'; import { SessionButtonColor } from '../SessionButton'; import { ToastUtils } from '../../../session/utils'; +import { NotificationForConvoOption } from '../../../state/ducks/conversations'; const maxNumberOfPinnedConversations = 5; diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index 5dae6d3c5..5110bad0f 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -25,6 +25,7 @@ import { actions as conversationActions, ConversationType as ReduxConversationType, LastMessageStatusType, + NotificationForConvoOption, } from '../state/ducks/conversations'; import { ExpirationTimerUpdateMessage } from '../session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage'; import { TypingMessage } from '../session/messages/outgoing/controlMessage/TypingMessage'; @@ -35,7 +36,6 @@ import { import { GroupInvitationMessage } from '../session/messages/outgoing/visibleMessage/GroupInvitationMessage'; import { ReadReceiptMessage } from '../session/messages/outgoing/controlMessage/receipt/ReadReceiptMessage'; import { OpenGroupUtils } from '../opengroup/utils'; -import { ConversationInteraction } from '../interactions'; import { OpenGroupVisibleMessage } from '../session/messages/outgoing/visibleMessage/OpenGroupVisibleMessage'; import { OpenGroupRequestCommonType } from '../opengroup/opengroupV2/ApiUtil'; import { getOpenGroupV2FromConversationId } from '../opengroup/utils/OpenGroupUtils'; @@ -408,9 +408,21 @@ export class ConversationModel extends Backbone.Model { groupAdmins, members, isPinned: this.isPinned(), + notificationForConvo: this.getConversationNotificationSettingType(), + currentNotificationSetting: this.get('triggerNotificationsFor'), }; } + public getConversationNotificationSettingType(): Array { + // exclude mentions_only settings for private chats as this does not make much sense + return ConversationNotificationSetting.filter(n => + this.isPrivate() ? n !== 'mentions_only' : true + ).map((n: ConversationNotificationSettingType) => { + // this link to the notificationForConvo_all, notificationForConvo_mentions_only, ... + return { value: n, name: window.i18n(`notificationForConvo_${n}`) }; + }); + } + public async updateGroupAdmins(groupAdmins: Array) { const existingAdmins = _.uniq(_.sortBy(this.getGroupAdmins())); const newAdmins = _.uniq(_.sortBy(groupAdmins)); diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index eb20669f9..7ea92c9d9 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -5,7 +5,10 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; import { getConversationController } from '../../session/conversations'; import { MessageModel } from '../../models/message'; import { getMessagesByConversation } from '../../data/data'; -import { ConversationTypeEnum } from '../../models/conversation'; +import { + ConversationNotificationSettingType, + ConversationTypeEnum, +} from '../../models/conversation'; import { MessageDeliveryStatus } from '../../models/messageType'; // State @@ -83,6 +86,13 @@ export interface ConversationType { groupAdmins?: Array; // admins for closed groups and moderators for open groups members?: Array; // members for closed groups only isPinned: boolean; + notificationForConvo: Array; + currentNotificationSetting: ConversationNotificationSettingType; +} + +export interface NotificationForConvoOption { + name: string; + value: ConversationNotificationSettingType; } export type ConversationLookupType = { diff --git a/ts/test/session/unit/selectors/conversations_test.ts b/ts/test/session/unit/selectors/conversations_test.ts index 06b494aa5..ea673cdf3 100644 --- a/ts/test/session/unit/selectors/conversations_test.ts +++ b/ts/test/session/unit/selectors/conversations_test.ts @@ -1,5 +1,8 @@ import { assert } from 'chai'; -import { ConversationTypeEnum } from '../../../../models/conversation'; +import { + ConversationNotificationSetting, + ConversationTypeEnum, +} from '../../../../models/conversation'; import { ConversationLookupType } from '../../../../state/ducks/conversations'; import { @@ -28,6 +31,8 @@ describe('state/selectors/conversations', () => { isKickedFromGroup: false, left: false, isPinned: false, + notificationForConvo: [], + currentNotificationSetting: ConversationNotificationSetting[0], }, id2: { id: 'id2', @@ -45,13 +50,14 @@ describe('state/selectors/conversations', () => { isKickedFromGroup: false, left: false, isPinned: false, + notificationForConvo: [], + currentNotificationSetting: ConversationNotificationSetting[0], }, id3: { id: 'id3', activeAt: 20, name: 'C', phoneNumber: 'notused', - type: ConversationTypeEnum.PRIVATE, isMe: false, unreadCount: 1, @@ -62,6 +68,8 @@ describe('state/selectors/conversations', () => { isKickedFromGroup: false, left: false, isPinned: false, + notificationForConvo: [], + currentNotificationSetting: ConversationNotificationSetting[0], }, id4: { id: 'id4', @@ -78,6 +86,8 @@ describe('state/selectors/conversations', () => { isKickedFromGroup: false, left: false, isPinned: false, + notificationForConvo: [], + currentNotificationSetting: ConversationNotificationSetting[0], }, id5: { id: 'id5', @@ -94,6 +104,8 @@ describe('state/selectors/conversations', () => { isKickedFromGroup: false, left: false, isPinned: false, + notificationForConvo: [], + currentNotificationSetting: ConversationNotificationSetting[0], }, }; const comparator = _getConversationComparator(i18n); @@ -126,6 +138,8 @@ describe('state/selectors/conversations', () => { isKickedFromGroup: false, left: false, isPinned: false, + notificationForConvo: [], + currentNotificationSetting: ConversationNotificationSetting[0], }, id2: { id: 'id2', @@ -143,6 +157,8 @@ describe('state/selectors/conversations', () => { isKickedFromGroup: false, left: false, isPinned: false, + notificationForConvo: [], + currentNotificationSetting: ConversationNotificationSetting[0], }, id3: { id: 'id3', @@ -160,6 +176,8 @@ describe('state/selectors/conversations', () => { isKickedFromGroup: false, left: false, isPinned: true, + notificationForConvo: [], + currentNotificationSetting: ConversationNotificationSetting[0], }, id4: { id: 'id4', @@ -176,6 +194,8 @@ describe('state/selectors/conversations', () => { isKickedFromGroup: false, left: false, isPinned: true, + notificationForConvo: [], + currentNotificationSetting: ConversationNotificationSetting[0], }, id5: { id: 'id5', @@ -192,6 +212,8 @@ describe('state/selectors/conversations', () => { isKickedFromGroup: false, left: false, isPinned: false, + notificationForConvo: [], + currentNotificationSetting: ConversationNotificationSetting[0], }, }; const comparator = _getConversationComparator(i18n);