diff --git a/package-lock.json b/package-lock.json index 74bba9ec3..3fbd7724d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ZERO", - "version": "1.294.0", + "version": "1.296.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ZERO", - "version": "1.294.0", + "version": "1.296.0", "dependencies": { "@craco/craco": "^7.1.0", "@emotion/react": "^11.9.3", diff --git a/package.json b/package.json index f6577fd8f..e17d7ce86 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ZERO", - "version": "1.294.0", + "version": "1.296.0", "private": true, "main": "./public/electron.js", "engines": { diff --git a/src/apps/feed/components/feed-chat/index.test.tsx b/src/apps/feed/components/feed-chat/index.test.tsx index 40f282e3a..1bdd8abf8 100644 --- a/src/apps/feed/components/feed-chat/index.test.tsx +++ b/src/apps/feed/components/feed-chat/index.test.tsx @@ -7,6 +7,7 @@ import { validateFeedChat } from '../../../../store/chat'; import { send } from '../../../../store/messages'; import { config } from '../../../../config'; import { Spinner } from '@zero-tech/zui/components/LoadingIndicator'; +import { MembersSidekick } from '../../../../components/sidekick/variants/members-sidekick'; describe('FeedChatContainer', () => { const subject = (props: any = {}) => { @@ -135,6 +136,19 @@ describe('FeedChatContainer', () => { expect(validateFeedChat).toHaveBeenLastCalledWith(`new-zid:${config.matrixHomeServerName}`); }); + it('should render members sidekick when is secondary sidekick open', () => { + const wrapper = subject({ + zid: 'test-zid', + channel: { id: 'channel-id' }, + activeConversationId: 'conversation-id', + isJoiningConversation: true, + isConversationsLoaded: true, + isSecondarySidekickOpen: true, + }); + + expect(wrapper).toHaveElement(MembersSidekick); + }); + describe('mapState', () => { const getState = (state: any) => ({ diff --git a/src/apps/feed/components/feed-chat/index.tsx b/src/apps/feed/components/feed-chat/index.tsx index fb766979f..6df70e065 100644 --- a/src/apps/feed/components/feed-chat/index.tsx +++ b/src/apps/feed/components/feed-chat/index.tsx @@ -3,7 +3,7 @@ import { RootState } from '../../../../store/reducer'; import { connectContainer } from '../../../../store/redux-container'; import { ChatViewContainer } from '../../../../components/chat-view-container/chat-view-container'; import { validateFeedChat } from '../../../../store/chat'; -import { Channel, onRemoveReply } from '../../../../store/channels'; +import { Channel, denormalize, onRemoveReply } from '../../../../store/channels'; import { MessageInput } from '../../../../components/message-input/container'; import { send as sendMessage } from '../../../../store/messages'; import { SendPayload as PayloadSendMessage } from '../../../../store/messages/saga'; @@ -18,7 +18,6 @@ import { toggleSecondarySidekick } from '../../../../store/group-management'; import { MembersSidekick } from '../../../../components/sidekick/variants/members-sidekick'; import { Spinner } from '@zero-tech/zui/components/LoadingIndicator'; import { ConversationActionsContainer } from '../../../../components/messenger/conversation-actions/container'; -import { denormalizedChannelSelector } from '../../../../store/channels/selectors'; import classNames from 'classnames'; import styles from './styles.module.scss'; @@ -55,7 +54,7 @@ export class Container extends React.Component { groupManagement, } = state; - const channel = denormalizedChannelSelector(state, activeConversationId); + const channel = denormalize(activeConversationId, state); const rawChannel = rawChannelSelector(activeConversationId)(state); return { @@ -210,7 +209,7 @@ export class Container extends React.Component { {this.renderHeader()}{' '} {this.renderBody(this.props.isJoiningConversation || !this.props.isConversationsLoaded)} - + {this.props.isSecondarySidekickOpen && } )} diff --git a/src/apps/feed/components/sidekick/lib/selectors.ts b/src/apps/feed/components/sidekick/lib/selectors.ts index 1994dd1c9..06f3a0e64 100644 --- a/src/apps/feed/components/sidekick/lib/selectors.ts +++ b/src/apps/feed/components/sidekick/lib/selectors.ts @@ -1,22 +1,29 @@ import { createSelector } from '@reduxjs/toolkit'; +import { RootState } from '../../../../../store/reducer'; +import { denormalizeConversations } from '../../../../../store/channels-list'; import { UnreadCount } from './useSidekick'; import { DefaultRoomLabels } from '../../../../../store/channels'; -import { denormalizedConversationsSelector } from '../../../../../store/channels-list/selectors'; -export const selectSocialChannelsUnreadCounts = createSelector([denormalizedConversationsSelector], (conversations) => { - return conversations - .filter((c) => c.isSocialChannel && c.zid) - .reduce((acc, channel) => { - acc[channel.zid!] = { total: channel.unreadCount?.total || 0, highlight: channel.unreadCount?.highlight || 0 }; - return acc; - }, {} as { [zid: string]: UnreadCount }); -}); +export const selectSocialChannelsUnreadCounts = createSelector( + [(state: RootState) => denormalizeConversations(state)], + (conversations) => { + return conversations + .filter((c) => c.isSocialChannel && c.zid) + .reduce((acc, channel) => { + acc[channel.zid!] = { total: channel.unreadCount?.total || 0, highlight: channel.unreadCount?.highlight || 0 }; + return acc; + }, {} as { [zid: string]: UnreadCount }); + } +); -export const selectMutedChannels = createSelector([denormalizedConversationsSelector], (conversations) => { - return conversations - .filter((c) => c.isSocialChannel && c.zid) - .reduce((acc, channel) => { - acc[channel.zid!] = channel.labels?.includes(DefaultRoomLabels.MUTE); - return acc; - }, {} as { [zid: string]: boolean }); -}); +export const selectMutedChannels = createSelector( + [(state: RootState) => denormalizeConversations(state)], + (conversations) => { + return conversations + .filter((c) => c.isSocialChannel && c.zid) + .reduce((acc, channel) => { + acc[channel.zid!] = channel.labels?.includes(DefaultRoomLabels.MUTE); + return acc; + }, {} as { [zid: string]: boolean }); + } +); diff --git a/src/apps/messenger/Main.test.tsx b/src/apps/messenger/Main.test.tsx index 1e4cf7d97..09af1f90b 100644 --- a/src/apps/messenger/Main.test.tsx +++ b/src/apps/messenger/Main.test.tsx @@ -3,8 +3,8 @@ import { shallow } from 'enzyme'; import { Container as Main, Properties } from './Main'; import { MessengerChat } from '../../components/messenger/chat'; -import { MessengerFeed } from '../../components/messenger/feed'; import { JoiningConversationDialog } from '../../components/joining-conversation-dialog'; +import { MembersSidekick } from '../../components/sidekick/variants/members-sidekick'; jest.mock('../../lib/web3/thirdweb/client', () => ({ getThirdWebClient: jest.fn(), @@ -20,9 +20,9 @@ describe(Main, () => { isAuthenticated: false, }, isValidConversation: false, - isSocialChannel: false, isJoiningConversation: false, isConversationsLoaded: true, + isSecondarySidekickOpen: false, ...props, }; @@ -49,7 +49,7 @@ describe(Main, () => { expect(wrapper).not.toHaveElement(JoiningConversationDialog); }); - it('renders direct message chat component when not a social channel, conversations loaded and is valid', () => { + it('renders direct message chat component when conversations loaded and is valid', () => { const wrapper = subject({ context: { isAuthenticated: true }, isValidConversation: true }); expect(wrapper).toHaveElement(MessengerChat); @@ -58,7 +58,6 @@ describe(Main, () => { it('should not render messenger chat container when conversations have not loaded', () => { const wrapper = subject({ context: { isAuthenticated: true }, - isSocialChannel: true, isValidConversation: true, isConversationsLoaded: false, }); @@ -66,43 +65,13 @@ describe(Main, () => { expect(wrapper).not.toHaveElement(MessengerChat); }); - it('should not render messenger chat container when is not valid conversation', () => { + it('should render members sidekick when is secondary sidekick open', () => { const wrapper = subject({ context: { isAuthenticated: true }, - isSocialChannel: false, - isValidConversation: false, - isConversationsLoaded: false, - }); - - expect(wrapper).not.toHaveElement(MessengerFeed); - }); - - it('renders messenger feed container when is social channel, conversations loaded and is valid conversation', () => { - const wrapper = subject({ context: { isAuthenticated: true }, isSocialChannel: true, isValidConversation: true }); - - expect(wrapper).toHaveElement(MessengerFeed); - }); - - it('should not render messenger feed container when is not social channel ', () => { - const wrapper = subject({ context: { isAuthenticated: true }, isSocialChannel: false, isValidConversation: true }); - - expect(wrapper).not.toHaveElement(MessengerFeed); - }); - - it('should not render messenger feed container when conversations have not loaded', () => { - const wrapper = subject({ - context: { isAuthenticated: true }, - isSocialChannel: true, - isValidConversation: true, - isConversationsLoaded: false, + isSecondarySidekickOpen: true, + isConversationsLoaded: true, }); - expect(wrapper).not.toHaveElement(MessengerFeed); - }); - - it('should not render messenger feed container when is not valid conversation', () => { - const wrapper = subject({ context: { isAuthenticated: true }, isSocialChannel: true, isValidConversation: false }); - - expect(wrapper).not.toHaveElement(MessengerFeed); + expect(wrapper).toHaveElement(MembersSidekick); }); }); diff --git a/src/apps/messenger/Main.tsx b/src/apps/messenger/Main.tsx index 3618f9b37..60f6e2f75 100644 --- a/src/apps/messenger/Main.tsx +++ b/src/apps/messenger/Main.tsx @@ -4,13 +4,11 @@ import { connectContainer } from '../../store/redux-container'; import { withContext as withAuthenticationContext } from '../../components/authentication/context'; import { MessengerChat } from '../../components/messenger/chat'; -import { MessengerFeed } from '../../components/messenger/feed'; import { DevPanelContainer } from '../../components/dev-panel/container'; import { FeatureFlag } from '../../components/feature-flag'; import { JoiningConversationDialog } from '../../components/joining-conversation-dialog'; import { ConversationsSidekick } from '../../components/sidekick/variants/conversations-sidekick'; import { MembersSidekick } from '../../components/sidekick/variants/members-sidekick'; -import { denormalizedChannelSelector } from '../../store/channels/selectors'; import styles from './Main.module.scss'; @@ -19,24 +17,23 @@ export interface Properties { isAuthenticated: boolean; }; isValidConversation: boolean; - isSocialChannel: boolean; isJoiningConversation: boolean; isConversationsLoaded: boolean; + isSecondarySidekickOpen: boolean; } export class Container extends React.Component { static mapState(state: RootState): Partial { const { chat: { activeConversationId, isJoiningConversation, isConversationsLoaded }, + groupManagement: { isSecondarySidekickOpen }, } = state; - const currentChannel = denormalizedChannelSelector(state, activeConversationId) || null; - return { isValidConversation: !!activeConversationId, - isSocialChannel: currentChannel?.isSocialChannel, isJoiningConversation, isConversationsLoaded, + isSecondarySidekickOpen, }; } @@ -53,11 +50,9 @@ export class Container extends React.Component {
{this.props.isJoiningConversation && !this.props.isValidConversation && } - {this.props.isConversationsLoaded && - this.props.isValidConversation && - (this.props.isSocialChannel ? : )} + {this.props.isConversationsLoaded && this.props.isValidConversation && }
- {this.props.isConversationsLoaded && } + {this.props.isConversationsLoaded && this.props.isSecondarySidekickOpen && } diff --git a/src/components/app-bar/container.tsx b/src/components/app-bar/container.tsx index 27981b3e3..a7d863a70 100644 --- a/src/components/app-bar/container.tsx +++ b/src/components/app-bar/container.tsx @@ -1,9 +1,9 @@ import { useRouteMatch } from 'react-router-dom'; import { AppBar as AppBarComponent } from './'; +import { denormalizeConversations } from '../../store/channels-list'; import { useSelector } from 'react-redux'; import { RootState } from '../../store'; import { DefaultRoomLabels } from '../../store/channels'; -import { denormalizedConversationsSelector } from '../../store/channels-list/selectors'; import { activeZAppFeatureSelector } from '../../store/active-zapp/selectors'; export const AppBar = () => { @@ -23,7 +23,7 @@ const useAppBar = () => { const match = useRouteMatch('/:app'); const hasUnreadNotifications = useSelector((state: RootState) => { - const conversations = denormalizedConversationsSelector(state); + const conversations = denormalizeConversations(state); return conversations.some( (channel) => channel.unreadCount?.total > 0 && @@ -33,7 +33,7 @@ const useAppBar = () => { }); const hasUnreadHighlights = useSelector((state: RootState) => { - const conversations = denormalizedConversationsSelector(state); + const conversations = denormalizeConversations(state); return conversations.some( (channel) => channel.unreadCount?.highlight > 0 && diff --git a/src/components/chat-view-container/chat-view-container.tsx b/src/components/chat-view-container/chat-view-container.tsx index 7b4c81fb2..529fb2370 100644 --- a/src/components/chat-view-container/chat-view-container.tsx +++ b/src/components/chat-view-container/chat-view-container.tsx @@ -13,7 +13,7 @@ import { AdminMessageType, sendEmojiReaction, } from '../../store/messages'; -import { Channel, ConversationStatus, onReply } from '../../store/channels'; +import { Channel, ConversationStatus, denormalize, onReply } from '../../store/channels'; import { ChatView } from './chat-view'; import { AuthenticationState } from '../../store/authentication/types'; import { EditPayload, Payload as PayloadFetchMessages } from '../../store/messages/saga'; @@ -25,7 +25,6 @@ import { openMessageInfo } from '../../store/message-info'; import { toggleSecondarySidekick } from '../../store/group-management'; import { linkMessages, mapMessagesById, mapMessagesByRootId } from './utils'; import { openReportUserModal } from '../../store/report-user'; -import { denormalizedChannelSelector } from '../../store/channels/selectors'; export interface Properties extends PublicProperties { channel: Channel; @@ -64,7 +63,7 @@ export class Container extends React.Component { } static mapState(state: RootState, props: PublicProperties): Partial { - const channel = denormalizedChannelSelector(state, props.channelId) || null; + const channel = denormalize(props.channelId, state) || null; const { authentication: { user }, chat: { activeConversationId }, diff --git a/src/components/group-management/member-management-dialog/container.tsx b/src/components/group-management/member-management-dialog/container.tsx index 4041a7123..d6d707d88 100644 --- a/src/components/group-management/member-management-dialog/container.tsx +++ b/src/components/group-management/member-management-dialog/container.tsx @@ -5,6 +5,7 @@ import { RootState } from '../../../store/reducer'; import { ConfirmationDefinition, MemberManagementDialog } from '.'; import { denormalize as denormalizeUser } from '../../../store/users'; import { displayName } from '../../../lib/user'; +import { denormalize as denormalizeChannel } from '../../../store/channels'; import { cancelMemberManagement, removeMember, @@ -13,7 +14,6 @@ import { setMemberAsModerator, removeMemberAsModerator, } from '../../../store/group-management'; -import { denormalizedChannelSelector } from '../../../store/channels/selectors'; export interface PublicProperties {} @@ -38,7 +38,7 @@ export class Container extends React.Component { groupManagement: { memberManagement }, } = state; const user = denormalizeUser(memberManagement.userId, state); - const channel = denormalizedChannelSelector(state, memberManagement.roomId); + const channel = denormalizeChannel(memberManagement.roomId, state); return { type: memberManagement.type, diff --git a/src/components/messenger/chat/index.tsx b/src/components/messenger/chat/index.tsx index f7f8a8938..5343b40eb 100644 --- a/src/components/messenger/chat/index.tsx +++ b/src/components/messenger/chat/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import classNames from 'classnames'; import { RootState } from '../../../store/reducer'; import { connectContainer } from '../../../store/redux-container'; -import { Channel, onAddLabel, onRemoveLabel, onRemoveReply } from '../../../store/channels'; +import { Channel, denormalize, onAddLabel, onRemoveLabel, onRemoveReply } from '../../../store/channels'; import { ChatViewContainer } from '../../chat-view-container/chat-view-container'; import { send as sendMessage } from '../../../store/messages'; import { SendPayload as PayloadSendMessage } from '../../../store/messages/saga'; @@ -21,9 +21,9 @@ import { Media } from '../../message-input/utils'; import { ConversationHeaderContainer as ConversationHeader } from '../conversation-header/container'; import './styles.scss'; +import { rawChannelSelector } from '../../../store/channels/saga'; import { getOtherMembersTypingDisplayJSX } from '../lib/utils'; import { Panel, PanelBody } from '../../layout/panel'; -import { denormalizedChannelSelector } from '../../../store/channels/selectors'; export interface PublicProperties {} @@ -59,7 +59,8 @@ export class Container extends React.Component { groupManagement, } = state; - const directMessage = denormalizedChannelSelector(state, activeConversationId); + const directMessage = denormalize(activeConversationId, state); + const channel = rawChannelSelector(activeConversationId)(state); return { activeConversationId, @@ -67,7 +68,7 @@ export class Container extends React.Component { isJoiningConversation, isSecondarySidekickOpen: groupManagement.isSecondarySidekickOpen, leaveGroupDialogStatus: groupManagement.leaveGroupDialogStatus, - otherMembersTypingInRoom: directMessage?.otherMembersTyping || [], + otherMembersTypingInRoom: channel?.otherMembersTyping || [], }; } diff --git a/src/components/messenger/conversation-actions/container.tsx b/src/components/messenger/conversation-actions/container.tsx index 41538f2c0..37f8b7066 100644 --- a/src/components/messenger/conversation-actions/container.tsx +++ b/src/components/messenger/conversation-actions/container.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { RootState } from '../../../store/reducer'; import { connectContainer } from '../../../store/redux-container'; -import { Channel, DefaultRoomLabels, onAddLabel, onRemoveLabel } from '../../../store/channels'; +import { Channel, DefaultRoomLabels, denormalize, onAddLabel, onRemoveLabel } from '../../../store/channels'; import { currentUserSelector } from '../../../store/authentication/selectors'; import { startAddGroupMember, @@ -13,8 +13,6 @@ import { } from '../../../store/group-management'; import { ConversationActions } from '.'; import { openReportUserModal } from '../../../store/report-user'; -import { denormalizedChannelSelector } from '../../../store/channels/selectors'; - import './styles.scss'; export interface PublicProperties { @@ -50,7 +48,7 @@ export class Container extends React.Component { groupManagement, } = state; - const directMessage = denormalizedChannelSelector(state, activeConversationId); + const directMessage = denormalize(activeConversationId, state); const currentUser = currentUserSelector(state); const hasMultipleMembers = (directMessage?.otherMembers || []).length > 1; const isSocialChannel = directMessage?.isSocialChannel; diff --git a/src/components/messenger/conversation-header/container.tsx b/src/components/messenger/conversation-header/container.tsx index 9baf2117c..a27ffd653 100644 --- a/src/components/messenger/conversation-header/container.tsx +++ b/src/components/messenger/conversation-header/container.tsx @@ -1,12 +1,11 @@ import React from 'react'; import { RootState } from '../../../store/reducer'; import { connectContainer } from '../../../store/redux-container'; -import { Channel } from '../../../store/channels'; +import { Channel, denormalize } from '../../../store/channels'; import { toggleSecondarySidekick } from '../../../store/group-management'; import { ConversationHeader } from '.'; import { ConversationActionsContainer as ConversationActions } from '../conversation-actions/container'; import { PanelHeader } from '../../layout/panel'; -import { denormalizedChannelSelector } from '../../../store/channels/selectors'; import { bemClassName } from '../../../lib/bem'; import './styles.scss'; @@ -33,7 +32,7 @@ export class Container extends React.Component { groupManagement, } = state; - const directMessage = denormalizedChannelSelector(state, activeConversationId); + const directMessage = denormalize(activeConversationId, state); return { activeConversationId, diff --git a/src/components/messenger/feed/index.tsx b/src/components/messenger/feed/index.tsx index 91297b97a..48b59a2c8 100644 --- a/src/components/messenger/feed/index.tsx +++ b/src/components/messenger/feed/index.tsx @@ -2,13 +2,12 @@ import React from 'react'; import { RootState } from '../../../store/reducer'; import { connectContainer } from '../../../store/redux-container'; import { PostPayload as PayloadPostMessage } from '../../../store/posts/saga'; -import { Channel } from '../../../store/channels'; +import { Channel, denormalize } from '../../../store/channels'; import { sendPost } from '../../../store/posts'; import { ConversationHeaderContainer as ConversationHeader } from '../conversation-header/container'; import { LeaveGroupDialogContainer } from '../../group-management/leave-group-dialog/container'; import { LeaveGroupDialogStatus, setLeaveGroupStatus } from '../../../store/group-management'; import { Switch, Route } from 'react-router-dom'; -import { denormalizedChannelSelector } from '../../../store/channels/selectors'; import { bemClassName } from '../../../lib/bem'; import './styles.scss'; @@ -42,7 +41,7 @@ export class Container extends React.Component { posts, } = state; - const currentChannel = denormalizedChannelSelector(state, activeConversationId) || null; + const currentChannel = denormalize(activeConversationId, state) || null; return { channel: currentChannel, diff --git a/src/components/messenger/group-management/container.tsx b/src/components/messenger/group-management/container.tsx index c83fb6227..f79c09267 100644 --- a/src/components/messenger/group-management/container.tsx +++ b/src/components/messenger/group-management/container.tsx @@ -18,18 +18,17 @@ import { Option } from '../lib/types'; import { GroupManagement } from '.'; import { RootState } from '../../../store/reducer'; import { GroupManagementErrors, EditConversationState } from '../../../store/group-management/types'; -import { User, openConversation, Channel } from '../../../store/channels'; +import { User, denormalize as denormalizeChannel, openConversation, Channel } from '../../../store/channels'; import { currentUserSelector } from '../../../store/authentication/selectors'; import { MemberManagementDialogContainer } from '../../group-management/member-management-dialog/container'; import { getUserSubHandle } from '../../../lib/user'; import { MemberNetworks } from '../../../store/users/types'; import { searchMyNetworksByName } from '../../../platform-apps/channels/util/api'; import { receiveSearchResults } from '../../../store/users'; +import { denormalizeConversations } from '../../../store/channels-list'; import { CreateMessengerConversation } from '../../../store/channels-list/types'; import { createConversation } from '../../../store/create-conversation'; import { openUserProfile } from '../../../store/user-profile'; -import { denormalizedChannelSelector } from '../../../store/channels/selectors'; -import { denormalizedConversationsSelector } from '../../../store/channels-list/selectors'; export interface PublicProperties {} @@ -74,13 +73,13 @@ export class Container extends React.Component { chat: { activeConversationId }, } = state; - const conversation = denormalizedChannelSelector(state, activeConversationId); + const conversation = denormalizeChannel(activeConversationId, state); const currentUser = currentUserSelector(state); const conversationAdminIds = conversation?.adminMatrixIds; const conversationModeratorIds = conversation?.moderatorIds; const isCurrentUserRoomAdmin = conversationAdminIds?.includes(currentUser?.matrixId) ?? false; const isCurrentUserRoomModerator = conversationModeratorIds?.includes(currentUser?.id) ?? false; - const existingConversations = denormalizedConversationsSelector(state); + const existingConversations = denormalizeConversations(state); return { activeConversationId, diff --git a/src/components/messenger/group-management/member-management-menu/container.tsx b/src/components/messenger/group-management/member-management-menu/container.tsx index 79074fda5..1bf9803d1 100644 --- a/src/components/messenger/group-management/member-management-menu/container.tsx +++ b/src/components/messenger/group-management/member-management-menu/container.tsx @@ -3,12 +3,11 @@ import * as React from 'react'; import { RootState } from '../../../../store/reducer'; import { connectContainer } from '../../../../store/redux-container'; import { MemberManagementAction, openMemberManagement } from '../../../../store/group-management'; -import { User } from '../../../../store/channels'; +import { User, denormalize as denormalizeChannel } from '../../../../store/channels'; import { MemberManagementMenu } from '.'; import { isUserModerator } from '../../list/utils/utils'; import { currentUserSelector } from '../../../../store/authentication/selectors'; -import { denormalizedChannelSelector } from '../../../../store/channels/selectors'; export interface PublicProperties { user?: User; @@ -31,7 +30,7 @@ export class Container extends React.Component { chat: { activeConversationId }, } = state; - const conversation = denormalizedChannelSelector(state, activeConversationId); + const conversation = denormalizeChannel(activeConversationId, state); const conversationModeratorIds = conversation?.moderatorIds; const currentUser = currentUserSelector(state); diff --git a/src/components/messenger/list/index.tsx b/src/components/messenger/list/index.tsx index b39708254..28a7edfd6 100644 --- a/src/components/messenger/list/index.tsx +++ b/src/components/messenger/list/index.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { connectContainer } from '../../../store/redux-container'; import { RootState } from '../../../store/reducer'; import { Channel, onAddLabel, onRemoveLabel, openConversation, User } from '../../../store/channels'; +import { denormalizeConversations } from '../../../store/channels-list'; import { compareDatesDesc } from '../../../lib/date'; import { MemberNetworks } from '../../../store/users/types'; import { searchMyNetworksByName } from '../../../platform-apps/channels/util/api'; @@ -39,7 +40,6 @@ import { IconPlus } from '@zero-tech/zui/icons'; import { GroupTypeDialog } from './group-details-panel/group-type-dialog'; import { AdminMessageType } from '../../../store/messages'; import { Header } from '../../sidekick/components/header'; -import { denormalizedConversationsSelector } from '../../../store/channels-list/selectors'; import { bemClassName } from '../../../lib/bem'; import './styles.scss'; @@ -94,11 +94,10 @@ export class Container extends React.Component { rewards, } = state; - const conversations = denormalizedConversationsSelector(state) + const conversations = denormalizeConversations(state) .filter((c) => !c.isSocialChannel) .map(addLastMessageMeta(state)) .sort(byLastMessageOrCreation); - const userHandle = getUserSubHandle(user?.data?.primaryZID, user?.data?.primaryWalletAddress); return { conversations, diff --git a/src/components/messenger/message-info/container.tsx b/src/components/messenger/message-info/container.tsx index 091621835..5badd3b06 100644 --- a/src/components/messenger/message-info/container.tsx +++ b/src/components/messenger/message-info/container.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { connectContainer } from '../../../store/redux-container'; import { RootState } from '../../../store/reducer'; import { closeMessageInfo } from '../../../store/message-info'; +import { denormalize as denormalizeChannel } from '../../../store/channels'; import { User } from '../../../store/channels'; import { OverviewPanel } from './overview-panel'; -import { denormalizedChannelSelector } from '../../../store/channels/selectors'; export interface PublicProperties {} @@ -26,7 +26,7 @@ export class Container extends React.Component { messageInfo: { selectedMessageId }, } = state; - const channel = denormalizedChannelSelector(state, activeConversationId) || {}; + const channel = denormalizeChannel(activeConversationId, state) || {}; const messages = channel.messages || []; const selectedMessage = messages.find((msg) => msg.id === selectedMessageId) || {}; const sentBy = selectedMessage?.sender?.userId !== user.data?.id ? selectedMessage?.sender : null; diff --git a/src/components/messenger/user-profile/linked-accounts-panel/container.tsx b/src/components/messenger/user-profile/linked-accounts-panel/container.tsx index d653abbd3..ea03b0fbf 100644 --- a/src/components/messenger/user-profile/linked-accounts-panel/container.tsx +++ b/src/components/messenger/user-profile/linked-accounts-panel/container.tsx @@ -4,10 +4,10 @@ import { RootState } from '../../../../store/reducer'; import { connectContainer } from '../../../../store/redux-container'; import { openConversation } from '../../../../store/channels'; import { createConversation } from '../../../../store/create-conversation'; +import { denormalizeConversations } from '../../../../store/channels-list'; import { Channel } from '../../../../store/channels'; import { config } from '../../../../config'; import { LinkedAccountsPanel } from '.'; -import { denormalizedConversationsSelector } from '../../../../store/channels-list/selectors'; export interface PublicProperties { onClose?: () => void; @@ -24,7 +24,7 @@ export interface Properties extends PublicProperties { export class Container extends React.Component { static mapState(state: RootState) { const telegramBotUserId = config.telegramBotUserId; - const existingConversations = denormalizedConversationsSelector(state); + const existingConversations = denormalizeConversations(state); return { telegramBotUserId, existingConversations }; } diff --git a/src/components/notifications-feed/index.tsx b/src/components/notifications-feed/index.tsx index 5594b0ab2..0c5838def 100644 --- a/src/components/notifications-feed/index.tsx +++ b/src/components/notifications-feed/index.tsx @@ -2,13 +2,13 @@ import React from 'react'; import { RootState } from '../../store/reducer'; import { connectContainer } from '../../store/redux-container'; import { Channel, DefaultRoomLabels } from '../../store/channels'; +import { denormalizeConversations } from '../../store/channels-list'; import { IconBell1 } from '@zero-tech/zui/icons'; import { NotificationItem } from './notification-item'; import { Spinner } from '@zero-tech/zui/components/LoadingIndicator'; import { openNotificationConversation } from '../../store/notifications'; import { ToggleGroup } from '@zero-tech/zui/components/ToggleGroup'; import { Panel, PanelBody, PanelHeader, PanelTitle } from '../layout/panel'; -import { denormalizedConversationsSelector } from '../../store/channels-list/selectors'; import styles from './styles.module.scss'; @@ -53,7 +53,7 @@ export class Container extends React.Component { chat: { isConversationsLoaded }, } = state; - const conversations = denormalizedConversationsSelector(state).filter( + const conversations = denormalizeConversations(state).filter( (conversation) => (conversation.unreadCount.total > 0 || conversation.unreadCount?.highlight > 0) && !conversation.labels?.includes(DefaultRoomLabels.ARCHIVED) diff --git a/src/store/channels-list/selectors.ts b/src/store/channels-list/selectors.ts index cfde3de6c..4ef73c765 100644 --- a/src/store/channels-list/selectors.ts +++ b/src/store/channels-list/selectors.ts @@ -2,9 +2,6 @@ import getDeepProperty from 'lodash.get'; import { denormalize } from '../channels'; import { compareDatesDesc } from '../../lib/date'; import { AsyncListStatus } from '../normalized'; -import { createSelector } from 'reselect'; -import { denormalizeConversations } from '.'; -import { RootState } from '..'; export function channelListStatus(state) { return getDeepProperty(state, 'channelsList.status', AsyncListStatus.Idle); @@ -35,7 +32,3 @@ function byLastMessageOrCreation(a, b) { const bDate = b.lastMessage?.createdAt || b.createdAt; return compareDatesDesc(aDate, bDate); } - -export const denormalizedConversationsSelector = createSelector([(state: RootState) => state], (state) => { - return denormalizeConversations(state); -}); diff --git a/src/store/channels/selectors.ts b/src/store/channels/selectors.ts index 367dd76f9..a42c3412f 100644 --- a/src/store/channels/selectors.ts +++ b/src/store/channels/selectors.ts @@ -1,16 +1,6 @@ import { RootState } from '../reducer'; import getDeepProperty from 'lodash.get'; -import { createSelector } from 'reselect'; -import { denormalize as denormalizeChannel } from '../channels'; export const rawChannel = (state: RootState, channelId: string) => { return getDeepProperty(state, `normalized.channels['${channelId}']`, null); }; - -// Memoized selector for denormalized channel -export const denormalizedChannelSelector = createSelector( - [(state: RootState) => state, (_state: RootState, channelId: string) => channelId], - (state, channelId) => { - return denormalizeChannel(channelId, state); - } -); diff --git a/src/store/chat/saga.test.ts b/src/store/chat/saga.test.ts index 29864636b..2ffd55041 100644 --- a/src/store/chat/saga.test.ts +++ b/src/store/chat/saga.test.ts @@ -81,7 +81,7 @@ describe(performValidateActiveConversation, () => { .call(getRoomIdForAlias, '#' + alias) .not.call(apiJoinRoom, conversationId) .put(rawSetActiveConversationId(conversationId)) - .spawn(markConversationAsRead, conversationId) + .call(markConversationAsRead, conversationId) .run(); expect(storeState.chat.activeConversationId).toBe(conversationId); @@ -170,7 +170,7 @@ describe(performValidateActiveConversation, () => { [matchers.call.fn(markConversationAsRead), undefined], ]) .put(rawSetActiveConversationId('social-channel')) - .spawn(markConversationAsRead, 'social-channel') + .call(markConversationAsRead, 'social-channel') .not.call(openFirstConversation) .run(); }); @@ -193,7 +193,7 @@ describe(performValidateActiveConversation, () => { [matchers.call.fn(getHistory), history], ]) .put(rawSetActiveConversationId('convo-1')) - .spawn(markConversationAsRead, 'convo-1') + .call(markConversationAsRead, 'convo-1') .run(); }); @@ -229,7 +229,7 @@ describe(performValidateActiveConversation, () => { }, ]) .not.put(rawSetActiveConversationId('convo-1')) - .not.spawn(markConversationAsRead, 'convo-1') + .call(markConversationAsRead, 'convo-1') .run(); }); }); diff --git a/src/store/chat/saga.ts b/src/store/chat/saga.ts index 35979a23f..dbb45fccd 100644 --- a/src/store/chat/saga.ts +++ b/src/store/chat/saga.ts @@ -217,9 +217,10 @@ export function* performValidateActiveConversation(activeConversationId: string) // check if path has changed before setting active conversation if (currentPathNow === originalPath) { yield put(rawSetActiveConversationId(conversationId)); - // Mark conversation as read, now that it has been set as active - yield spawn(markConversationAsRead, conversationId); } + + // Mark conversation as read, now that it has been set as active + yield call(markConversationAsRead, conversationId); } export function* closeErrorDialog() {