mirror of
https://github.com/oxen-io/session-desktop.git
synced 2023-12-14 02:12:57 +01:00
chore: move selected convo selectors to another file
This commit is contained in:
parent
c3e9d503e4
commit
0050352470
|
@ -3,7 +3,6 @@ import { useSelector } from 'react-redux';
|
|||
import Draggable, { DraggableData, DraggableEvent } from 'react-draggable';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import { getSelectedConversationKey } from '../../state/selectors/conversations';
|
||||
import { getHasOngoingCall, getHasOngoingCallWith } from '../../state/selectors/call';
|
||||
import { openConversationWithMessages } from '../../state/ducks/conversations';
|
||||
import { Avatar, AvatarSize } from '../avatar/Avatar';
|
||||
|
@ -11,6 +10,7 @@ import { useVideoCallEventsListener } from '../../hooks/useVideoEventListener';
|
|||
import { VideoLoadingSpinner } from './InConversationCallContainer';
|
||||
import { getSection } from '../../state/selectors/section';
|
||||
import { SectionType } from '../../state/ducks/section';
|
||||
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
|
||||
|
||||
export const DraggableCallWindow = styled.div`
|
||||
position: absolute;
|
||||
|
@ -58,7 +58,7 @@ const CenteredAvatarInDraggable = styled.div`
|
|||
|
||||
export const DraggableCallContainer = () => {
|
||||
const ongoingCallProps = useSelector(getHasOngoingCallWith);
|
||||
const selectedConversationKey = useSelector(getSelectedConversationKey);
|
||||
const selectedConversationKey = useSelectedConversationKey();
|
||||
const hasOngoingCall = useSelector(getHasOngoingCall);
|
||||
const selectedSection = useSelector(getSection);
|
||||
|
||||
|
|
|
@ -6,15 +6,6 @@ import { contextMenu } from 'react-contexify';
|
|||
import styled from 'styled-components';
|
||||
import { ConversationNotificationSettingType } from '../../models/conversationAttributes';
|
||||
import {
|
||||
getConversationHeaderTitleProps,
|
||||
getCurrentNotificationSettingText,
|
||||
getCurrentSubscriberCount,
|
||||
getIsSelectedActive,
|
||||
getIsSelectedBlocked,
|
||||
getIsSelectedNoteToSelf,
|
||||
getIsSelectedPrivate,
|
||||
getSelectedConversationIsPublic,
|
||||
getSelectedConversationKey,
|
||||
getSelectedMessageIds,
|
||||
isMessageDetailView,
|
||||
isMessageSelectionMode,
|
||||
|
@ -50,6 +41,19 @@ import { SessionIconButton } from '../icon';
|
|||
import { ConversationHeaderMenu } from '../menu/ConversationHeaderMenu';
|
||||
import { Flex } from '../basic/Flex';
|
||||
import { ExpirationTimerOptions } from '../../util/expiringMessages';
|
||||
import {
|
||||
useSelectedConversationKey,
|
||||
useSelectedIsActive,
|
||||
useSelectedIsBlocked,
|
||||
useSelectedIsGroup,
|
||||
useSelectedIsKickedFromGroup,
|
||||
useSelectedisNoteToSelf,
|
||||
useSelectedIsPrivate,
|
||||
useSelectedIsPublic,
|
||||
useSelectedMembers,
|
||||
useSelectedNotificationSetting,
|
||||
useSelectedSubscriberCount,
|
||||
} from '../../state/selectors/selectedConversation';
|
||||
|
||||
export interface TimerOption {
|
||||
name: string;
|
||||
|
@ -58,8 +62,8 @@ export interface TimerOption {
|
|||
|
||||
const SelectionOverlay = () => {
|
||||
const selectedMessageIds = useSelector(getSelectedMessageIds);
|
||||
const selectedConversationKey = useSelector(getSelectedConversationKey);
|
||||
const isPublic = useSelector(getSelectedConversationIsPublic);
|
||||
const selectedConversationKey = useSelectedConversationKey();
|
||||
const isPublic = useSelectedIsPublic();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { i18n } = window;
|
||||
|
@ -200,11 +204,11 @@ const BackButton = (props: { onGoBack: () => void; showBackButton: boolean }) =>
|
|||
};
|
||||
|
||||
const CallButton = () => {
|
||||
const isPrivate = useSelector(getIsSelectedPrivate);
|
||||
const isBlocked = useSelector(getIsSelectedBlocked);
|
||||
const activeAt = useSelector(getIsSelectedActive);
|
||||
const isMe = useSelector(getIsSelectedNoteToSelf);
|
||||
const selectedConvoKey = useSelector(getSelectedConversationKey);
|
||||
const isPrivate = useSelectedIsPrivate();
|
||||
const isBlocked = useSelectedIsBlocked();
|
||||
const activeAt = useSelectedIsActive();
|
||||
const isMe = useSelectedisNoteToSelf();
|
||||
const selectedConvoKey = useSelectedConversationKey();
|
||||
|
||||
const hasIncomingCall = useSelector(getHasIncomingCall);
|
||||
const hasOngoingCall = useSelector(getHasOngoingCall);
|
||||
|
@ -266,18 +270,22 @@ export const ConversationHeaderSubtitle = (props: { text?: string | null }): JSX
|
|||
const ConversationHeaderTitle = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const headerTitleProps = useSelector(getConversationHeaderTitleProps);
|
||||
const notificationSetting = useSelector(getCurrentNotificationSettingText);
|
||||
const notificationSetting = useSelectedNotificationSetting();
|
||||
const isRightPanelOn = useSelector(isRightPanelShowing);
|
||||
const convoName = useConversationUsername(headerTitleProps?.conversationKey);
|
||||
const subscriberCount = useSelector(getCurrentSubscriberCount);
|
||||
const subscriberCount = useSelectedSubscriberCount();
|
||||
const selectedConvoKey = useSelectedConversationKey();
|
||||
const convoName = useConversationUsername(selectedConvoKey);
|
||||
|
||||
if (!headerTitleProps) {
|
||||
const isPublic = useSelectedIsPublic();
|
||||
const isKickedFromGroup = useSelectedIsKickedFromGroup();
|
||||
const isMe = useSelectedisNoteToSelf();
|
||||
const isGroup = useSelectedIsGroup();
|
||||
const members = useSelectedMembers();
|
||||
|
||||
if (!selectedConvoKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { isGroup, isPublic, members, isMe, isKickedFromGroup } = headerTitleProps;
|
||||
|
||||
const { i18n } = window;
|
||||
|
||||
if (isMe) {
|
||||
|
@ -331,15 +339,15 @@ const ConversationHeaderTitle = () => {
|
|||
export const ConversationHeaderWithDetails = () => {
|
||||
const isSelectionMode = useSelector(isMessageSelectionMode);
|
||||
const isMessageDetailOpened = useSelector(isMessageDetailView);
|
||||
const selectedConvoKey = useSelector(getSelectedConversationKey);
|
||||
const selectedConvoKey = useSelectedConversationKey();
|
||||
const dispatch = useDispatch();
|
||||
const isKickedFromGroup = useIsKickedFromGroup(selectedConvoKey);
|
||||
const expireTimerSetting = useExpireTimer(selectedConvoKey);
|
||||
|
||||
if (!selectedConvoKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isKickedFromGroup = useIsKickedFromGroup(selectedConvoKey);
|
||||
const expireTimerSetting = useExpireTimer(selectedConvoKey);
|
||||
const expirationSettingName = expireTimerSetting
|
||||
? ExpirationTimerOptions.getName(expireTimerSetting || 0)
|
||||
: undefined;
|
||||
|
|
|
@ -7,10 +7,8 @@ import {
|
|||
declineConversationWithConfirm,
|
||||
} from '../../interactions/conversationInteractions';
|
||||
import { getConversationController } from '../../session/conversations';
|
||||
import {
|
||||
getSelectedConversation,
|
||||
hasSelectedConversationIncomingMessages,
|
||||
} from '../../state/selectors/conversations';
|
||||
import { hasSelectedConversationIncomingMessages } from '../../state/selectors/conversations';
|
||||
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
|
||||
import { SessionButton, SessionButtonColor } from '../basic/SessionButton';
|
||||
|
||||
const handleDeclineConversationRequest = (convoId: string) => {
|
||||
|
@ -44,12 +42,12 @@ const ConversationBannerRow = styled.div`
|
|||
`;
|
||||
|
||||
export const ConversationMessageRequestButtons = () => {
|
||||
const selectedConversation = useSelector(getSelectedConversation);
|
||||
const selectedConvoId = useSelectedConversationKey();
|
||||
|
||||
const hasIncomingMessages = useSelector(hasSelectedConversationIncomingMessages);
|
||||
const isIncomingMessageRequest = useIsRequest(selectedConversation?.id);
|
||||
const isIncomingMessageRequest = useIsRequest(selectedConvoId);
|
||||
|
||||
if (!selectedConversation || !hasIncomingMessages) {
|
||||
if (!selectedConvoId || !hasIncomingMessages) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -62,7 +60,7 @@ export const ConversationMessageRequestButtons = () => {
|
|||
<ConversationBannerRow>
|
||||
<SessionButton
|
||||
onClick={async () => {
|
||||
await handleAcceptConversationRequest(selectedConversation.id);
|
||||
await handleAcceptConversationRequest(selectedConvoId);
|
||||
}}
|
||||
text={window.i18n('accept')}
|
||||
dataTestId="accept-message-request"
|
||||
|
@ -71,7 +69,7 @@ export const ConversationMessageRequestButtons = () => {
|
|||
buttonColor={SessionButtonColor.Danger}
|
||||
text={window.i18n('decline')}
|
||||
onClick={() => {
|
||||
handleDeclineConversationRequest(selectedConversation.id);
|
||||
handleDeclineConversationRequest(selectedConvoId);
|
||||
}}
|
||||
dataTestId="decline-message-request"
|
||||
/>
|
||||
|
|
|
@ -2,10 +2,8 @@ import React from 'react';
|
|||
import { useSelector } from 'react-redux';
|
||||
import styled from 'styled-components';
|
||||
import { useIsRequest } from '../../hooks/useParamSelector';
|
||||
import {
|
||||
getSelectedConversation,
|
||||
hasSelectedConversationIncomingMessages,
|
||||
} from '../../state/selectors/conversations';
|
||||
import { hasSelectedConversationIncomingMessages } from '../../state/selectors/conversations';
|
||||
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
|
||||
|
||||
const ConversationRequestTextBottom = styled.div`
|
||||
display: flex;
|
||||
|
@ -22,8 +20,8 @@ const ConversationRequestTextInner = styled.div`
|
|||
`;
|
||||
|
||||
export const ConversationRequestinfo = () => {
|
||||
const selectedConversation = useSelector(getSelectedConversation);
|
||||
const isIncomingMessageRequest = useIsRequest(selectedConversation?.id);
|
||||
const selectedConversation = useSelectedConversationKey();
|
||||
const isIncomingMessageRequest = useIsRequest(selectedConversation);
|
||||
|
||||
const showMsgRequestUI = selectedConversation && isIncomingMessageRequest;
|
||||
const hasIncomingMessages = useSelector(hasSelectedConversationIncomingMessages);
|
||||
|
|
|
@ -15,19 +15,19 @@ import {
|
|||
import {
|
||||
getOldBottomMessageId,
|
||||
getOldTopMessageId,
|
||||
getSelectedConversationKey,
|
||||
getSortedMessagesTypesOfSelectedConversation,
|
||||
} from '../../state/selectors/conversations';
|
||||
import { GroupUpdateMessage } from './message/message-item/GroupUpdateMessage';
|
||||
import { MessageRequestResponse } from './message/message-item/MessageRequestResponse';
|
||||
import { MessageDateBreak } from './message/message-item/DateBreak';
|
||||
import { GroupInvitation } from './message/message-item/GroupInvitation';
|
||||
import { GroupUpdateMessage } from './message/message-item/GroupUpdateMessage';
|
||||
import { Message } from './message/message-item/Message';
|
||||
import { MessageRequestResponse } from './message/message-item/MessageRequestResponse';
|
||||
import { CallNotification } from './message/message-item/notification-bubble/CallNotification';
|
||||
|
||||
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
|
||||
import { DataExtractionNotification } from './message/message-item/DataExtractionNotification';
|
||||
import { SessionLastSeenIndicator } from './SessionLastSeenIndicator';
|
||||
import { TimerNotification } from './TimerNotification';
|
||||
import { DataExtractionNotification } from './message/message-item/DataExtractionNotification';
|
||||
|
||||
function isNotTextboxEvent(e: KeyboardEvent) {
|
||||
return (e?.target as any)?.type === undefined;
|
||||
|
@ -46,7 +46,7 @@ export const SessionMessagesList = (props: {
|
|||
onEndPressed: () => void;
|
||||
}) => {
|
||||
const messagesProps = useSelector(getSortedMessagesTypesOfSelectedConversation);
|
||||
const convoKey = useSelector(getSelectedConversationKey);
|
||||
const convoKey = useSelectedConversationKey();
|
||||
|
||||
const [didScroll, setDidScroll] = useState(false);
|
||||
const oldTopMessageId = useSelector(getOldTopMessageId);
|
||||
|
|
|
@ -17,12 +17,14 @@ import {
|
|||
import { StateType } from '../../state/reducer';
|
||||
import {
|
||||
getQuotedMessageToAnimate,
|
||||
getSelectedConversation,
|
||||
getSelectedConversationKey,
|
||||
getSortedMessagesOfSelectedConversation,
|
||||
} from '../../state/selectors/conversations';
|
||||
import { TypingBubble } from './TypingBubble';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
getSelectedConversation,
|
||||
getSelectedConversationKey,
|
||||
} from '../../state/selectors/selectedConversation';
|
||||
|
||||
export type SessionMessageListProps = {
|
||||
messageContainerRef: React.RefObject<HTMLDivElement>;
|
||||
|
|
|
@ -17,11 +17,7 @@ import {
|
|||
} from '../../interactions/conversationInteractions';
|
||||
import { Constants } from '../../session';
|
||||
import { closeRightPanel } from '../../state/ducks/conversations';
|
||||
import {
|
||||
getCurrentSubscriberCount,
|
||||
getSelectedConversation,
|
||||
isRightPanelShowing,
|
||||
} from '../../state/selectors/conversations';
|
||||
import { isRightPanelShowing } from '../../state/selectors/conversations';
|
||||
import { getTimerOptions } from '../../state/selectors/timerOptions';
|
||||
import { AttachmentTypeWithPath } from '../../types/Attachment';
|
||||
import { Avatar, AvatarSize } from '../avatar/Avatar';
|
||||
|
@ -32,6 +28,18 @@ import { MediaItemType } from '../lightbox/LightboxGallery';
|
|||
import { MediaGallery } from './media-gallery/MediaGallery';
|
||||
import { getAbsoluteAttachmentPath } from '../../types/MessageAttachment';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
useSelectedConversationKey,
|
||||
useSelectedDisplayNameInProfile,
|
||||
useSelectedIsActive,
|
||||
useSelectedIsBlocked,
|
||||
useSelectedIsGroup,
|
||||
useSelectedIsKickedFromGroup,
|
||||
useSelectedIsLeft,
|
||||
useSelectedIsPublic,
|
||||
useSelectedSubscriberCount,
|
||||
useSelectedWeAreAdmin,
|
||||
} from '../../state/selectors/selectedConversation';
|
||||
|
||||
async function getMediaGalleryProps(
|
||||
conversationId: string
|
||||
|
@ -107,13 +115,16 @@ async function getMediaGalleryProps(
|
|||
}
|
||||
|
||||
const HeaderItem = () => {
|
||||
const selectedConversation = useSelector(getSelectedConversation);
|
||||
const selectedConvoKey = useSelectedConversationKey();
|
||||
const dispatch = useDispatch();
|
||||
const isBlocked = useSelectedIsBlocked();
|
||||
const isKickedFromGroup = useSelectedIsKickedFromGroup();
|
||||
const left = useSelectedIsLeft();
|
||||
const isGroup = useSelectedIsGroup();
|
||||
|
||||
if (!selectedConversation) {
|
||||
if (!selectedConvoKey) {
|
||||
return null;
|
||||
}
|
||||
const { id, isGroup, isKickedFromGroup, isBlocked, left } = selectedConversation;
|
||||
|
||||
const showInviteContacts = isGroup && !isKickedFromGroup && !isBlocked && !left;
|
||||
|
||||
|
@ -129,14 +140,14 @@ const HeaderItem = () => {
|
|||
style={{ position: 'absolute' }}
|
||||
dataTestId="back-button-conversation-options"
|
||||
/>
|
||||
<Avatar size={AvatarSize.XL} pubkey={id} />
|
||||
<Avatar size={AvatarSize.XL} pubkey={selectedConvoKey} />
|
||||
{showInviteContacts && (
|
||||
<SessionIconButton
|
||||
iconType="addUser"
|
||||
iconSize="medium"
|
||||
onClick={() => {
|
||||
if (selectedConversation) {
|
||||
showInviteContactByConvoId(selectedConversation.id);
|
||||
if (selectedConvoKey) {
|
||||
showInviteContactByConvoId(selectedConvoKey);
|
||||
}
|
||||
}}
|
||||
dataTestId="add-user-button"
|
||||
|
@ -191,15 +202,24 @@ export const SessionRightPanelWithDetails = () => {
|
|||
const [documents, setDocuments] = useState<Array<MediaItemType>>([]);
|
||||
const [media, setMedia] = useState<Array<MediaItemType>>([]);
|
||||
|
||||
const selectedConversation = useSelector(getSelectedConversation);
|
||||
const selectedConvoKey = useSelectedConversationKey();
|
||||
const isShowing = useSelector(isRightPanelShowing);
|
||||
const subscriberCount = useSelector(getCurrentSubscriberCount);
|
||||
const subscriberCount = useSelectedSubscriberCount();
|
||||
|
||||
const isActive = useSelectedIsActive();
|
||||
const displayNameInProfile = useSelectedDisplayNameInProfile();
|
||||
const isBlocked = useSelectedIsBlocked();
|
||||
const isKickedFromGroup = useSelectedIsKickedFromGroup();
|
||||
const left = useSelectedIsLeft();
|
||||
const isGroup = useSelectedIsGroup();
|
||||
const isPublic = useSelectedIsPublic();
|
||||
const weAreAdmin = useSelectedWeAreAdmin();
|
||||
|
||||
useEffect(() => {
|
||||
let isRunning = true;
|
||||
|
||||
if (isShowing && selectedConversation) {
|
||||
void getMediaGalleryProps(selectedConversation.id).then(results => {
|
||||
if (isShowing && selectedConvoKey) {
|
||||
void getMediaGalleryProps(selectedConvoKey).then(results => {
|
||||
if (isRunning) {
|
||||
if (!_.isEqual(documents, results.documents)) {
|
||||
setDocuments(results.documents);
|
||||
|
@ -216,11 +236,11 @@ export const SessionRightPanelWithDetails = () => {
|
|||
isRunning = false;
|
||||
return;
|
||||
};
|
||||
}, [isShowing, selectedConversation?.id]);
|
||||
}, [isShowing, selectedConvoKey]);
|
||||
|
||||
useInterval(async () => {
|
||||
if (isShowing && selectedConversation) {
|
||||
const results = await getMediaGalleryProps(selectedConversation.id);
|
||||
if (isShowing && selectedConvoKey) {
|
||||
const results = await getMediaGalleryProps(selectedConvoKey);
|
||||
if (results.documents.length !== documents.length || results.media.length !== media.length) {
|
||||
setDocuments(results.documents);
|
||||
setMedia(results.media);
|
||||
|
@ -228,23 +248,12 @@ export const SessionRightPanelWithDetails = () => {
|
|||
}
|
||||
}, 10000);
|
||||
|
||||
if (!selectedConversation) {
|
||||
if (!selectedConvoKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
id,
|
||||
displayNameInProfile,
|
||||
isKickedFromGroup,
|
||||
left,
|
||||
isPublic,
|
||||
weAreAdmin,
|
||||
isBlocked,
|
||||
isGroup,
|
||||
activeAt,
|
||||
} = selectedConversation;
|
||||
const showMemberCount = !!(subscriberCount && subscriberCount > 0);
|
||||
const commonNoShow = isKickedFromGroup || left || isBlocked || !activeAt;
|
||||
const commonNoShow = isKickedFromGroup || left || isBlocked || !isActive;
|
||||
const hasDisappearingMessages = !isPublic && !commonNoShow;
|
||||
const leaveGroupString = isPublic
|
||||
? window.i18n('leaveGroup')
|
||||
|
@ -260,7 +269,7 @@ export const SessionRightPanelWithDetails = () => {
|
|||
return {
|
||||
content: option.name,
|
||||
onClick: () => {
|
||||
void setDisappearingMessagesByConvoId(id, option.value);
|
||||
void setDisappearingMessagesByConvoId(selectedConvoKey, option.value);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
@ -272,10 +281,10 @@ export const SessionRightPanelWithDetails = () => {
|
|||
|
||||
const deleteConvoAction = isPublic
|
||||
? () => {
|
||||
deleteAllMessagesByConvoIdWithConfirmation(id);
|
||||
deleteAllMessagesByConvoIdWithConfirmation(selectedConvoKey); // TODO this does not delete the public group and showLeaveGroupByConvoId is not only working for closed groups
|
||||
}
|
||||
: () => {
|
||||
showLeaveGroupByConvoId(id);
|
||||
showLeaveGroupByConvoId(selectedConvoKey);
|
||||
};
|
||||
return (
|
||||
<div className="group-settings">
|
||||
|
@ -295,7 +304,7 @@ export const SessionRightPanelWithDetails = () => {
|
|||
className="group-settings-item"
|
||||
role="button"
|
||||
onClick={async () => {
|
||||
await showUpdateGroupNameByConvoId(id);
|
||||
await showUpdateGroupNameByConvoId(selectedConvoKey);
|
||||
}}
|
||||
>
|
||||
{isPublic ? window.i18n('editGroup') : window.i18n('editGroupName')}
|
||||
|
@ -307,7 +316,7 @@ export const SessionRightPanelWithDetails = () => {
|
|||
className="group-settings-item"
|
||||
role="button"
|
||||
onClick={() => {
|
||||
showAddModeratorsByConvoId(id);
|
||||
showAddModeratorsByConvoId(selectedConvoKey);
|
||||
}}
|
||||
>
|
||||
{window.i18n('addModerators')}
|
||||
|
@ -316,7 +325,7 @@ export const SessionRightPanelWithDetails = () => {
|
|||
className="group-settings-item"
|
||||
role="button"
|
||||
onClick={() => {
|
||||
showRemoveModeratorsByConvoId(id);
|
||||
showRemoveModeratorsByConvoId(selectedConvoKey);
|
||||
}}
|
||||
>
|
||||
{window.i18n('removeModerators')}
|
||||
|
@ -329,7 +338,7 @@ export const SessionRightPanelWithDetails = () => {
|
|||
className="group-settings-item"
|
||||
role="button"
|
||||
onClick={async () => {
|
||||
await showUpdateGroupMembersByConvoId(id);
|
||||
await showUpdateGroupMembersByConvoId(selectedConvoKey);
|
||||
}}
|
||||
>
|
||||
{window.i18n('groupMembers')}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import React from 'react';
|
||||
|
||||
import { isImageTypeSupported, isVideoTypeSupported } from '../../util/GoogleChrome';
|
||||
import { Image } from './Image';
|
||||
import { StagedGenericAttachment } from './StagedGenericAttachment';
|
||||
import { StagedPlaceholderAttachment } from './StagedPlaceholderAttachment';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import {
|
||||
removeAllStagedAttachmentsInConversation,
|
||||
removeStagedAttachmentInConversation,
|
||||
} from '../../state/ducks/stagedAttachments';
|
||||
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
|
||||
import {
|
||||
areAllAttachmentsVisual,
|
||||
AttachmentType,
|
||||
getUrl,
|
||||
isVideoAttachment,
|
||||
} from '../../types/Attachment';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import {
|
||||
removeAllStagedAttachmentsInConversation,
|
||||
removeStagedAttachmentInConversation,
|
||||
} from '../../state/ducks/stagedAttachments';
|
||||
import { getSelectedConversationKey } from '../../state/selectors/conversations';
|
||||
import { isImageTypeSupported, isVideoTypeSupported } from '../../util/GoogleChrome';
|
||||
import { Image } from './Image';
|
||||
import { StagedGenericAttachment } from './StagedGenericAttachment';
|
||||
import { StagedPlaceholderAttachment } from './StagedPlaceholderAttachment';
|
||||
|
||||
type Props = {
|
||||
attachments: Array<AttachmentType>;
|
||||
|
@ -30,7 +30,7 @@ export const StagedAttachmentList = (props: Props) => {
|
|||
const { attachments, onAddAttachment, onClickAttachment } = props;
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const conversationKey = useSelector(getSelectedConversationKey);
|
||||
const conversationKey = useSelectedConversationKey();
|
||||
|
||||
const onRemoveAllStaged = () => {
|
||||
if (!conversationKey) {
|
||||
|
|
|
@ -31,13 +31,7 @@ import { ToastUtils } from '../../../session/utils';
|
|||
import { ReduxConversationType } from '../../../state/ducks/conversations';
|
||||
import { removeAllStagedAttachmentsInConversation } from '../../../state/ducks/stagedAttachments';
|
||||
import { StateType } from '../../../state/reducer';
|
||||
import {
|
||||
getIsTypingEnabled,
|
||||
getMentionsInput,
|
||||
getQuotedMessage,
|
||||
getSelectedConversation,
|
||||
getSelectedConversationKey,
|
||||
} from '../../../state/selectors/conversations';
|
||||
import { getMentionsInput, getQuotedMessage } from '../../../state/selectors/conversations';
|
||||
import { AttachmentUtil } from '../../../util';
|
||||
import { Flex } from '../../basic/Flex';
|
||||
import { CaptionEditor } from '../../CaptionEditor';
|
||||
|
@ -57,6 +51,11 @@ import { renderEmojiQuickResultRow, searchEmojiForQuery } from './EmojiQuickResu
|
|||
import { LinkPreviews } from '../../../util/linkPreviews';
|
||||
import styled from 'styled-components';
|
||||
import { FixedBaseEmoji } from '../../../types/Reaction';
|
||||
import {
|
||||
getSelectedCanWrite,
|
||||
getSelectedConversation,
|
||||
getSelectedConversationKey,
|
||||
} from '../../../state/selectors/selectedConversation';
|
||||
|
||||
export interface ReplyingToMessageProps {
|
||||
convoId: string;
|
||||
|
@ -1084,7 +1083,7 @@ const mapStateToProps = (state: StateType) => {
|
|||
quotedMessageProps: getQuotedMessage(state),
|
||||
selectedConversation: getSelectedConversation(state),
|
||||
selectedConversationKey: getSelectedConversationKey(state),
|
||||
typingEnabled: getIsTypingEnabled(state),
|
||||
typingEnabled: getSelectedCanWrite(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import moment from 'moment';
|
||||
// tslint:disable-next-line:match-default-export-name
|
||||
import formatFileSize from 'filesize';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { getSelectedConversationKey } from '../../../state/selectors/conversations';
|
||||
import { saveAttachmentToDisk } from '../../../util/attachmentsUtil';
|
||||
import { MediaItemType } from '../../lightbox/LightboxGallery';
|
||||
import { useSelectedConversationKey } from '../../../state/selectors/selectedConversation';
|
||||
|
||||
type Props = {
|
||||
// Required
|
||||
|
@ -24,7 +23,11 @@ export const DocumentListItem = (props: Props) => {
|
|||
const { shouldShowSeparator, fileName, fileSize, timestamp } = props;
|
||||
|
||||
const defaultShowSeparator = shouldShowSeparator === undefined ? true : shouldShowSeparator;
|
||||
const selectedConversationKey = useSelector(getSelectedConversationKey) as string;
|
||||
const selectedConversationKey = useSelectedConversationKey();
|
||||
|
||||
if (!selectedConversationKey) {
|
||||
throw new Error('DocumentListItem: selectedConversationKey was not set');
|
||||
}
|
||||
|
||||
const saveAttachmentCallback = useCallback(() => {
|
||||
void saveAttachmentToDisk({
|
||||
|
|
|
@ -3,11 +3,11 @@ import { useSelector } from 'react-redux';
|
|||
import styled from 'styled-components';
|
||||
import { MessageRenderingProps } from '../../../../models/messageType';
|
||||
import { PubKey } from '../../../../session/types';
|
||||
import { getMessageAuthorProps } from '../../../../state/selectors/conversations';
|
||||
import {
|
||||
getMessageAuthorProps,
|
||||
getSelectedConversationIsGroup,
|
||||
isPublicGroupConversation,
|
||||
} from '../../../../state/selectors/conversations';
|
||||
useSelectedIsGroup,
|
||||
useSelectedIsPublic,
|
||||
} from '../../../../state/selectors/selectedConversation';
|
||||
import { Flex } from '../../../basic/Flex';
|
||||
import { ContactName } from '../../ContactName';
|
||||
|
||||
|
@ -27,8 +27,9 @@ const StyledAuthorContainer = styled(Flex)`
|
|||
export const MessageAuthorText = (props: Props) => {
|
||||
const selected = useSelector(state => getMessageAuthorProps(state as any, props.messageId));
|
||||
|
||||
const isPublic = useSelector(isPublicGroupConversation);
|
||||
const isGroup = useSelector(getSelectedConversationIsGroup);
|
||||
const isPublic = useSelectedIsPublic();
|
||||
const isGroup = useSelectedIsGroup();
|
||||
|
||||
if (!selected) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -8,12 +8,12 @@ import { getSodiumRenderer } from '../../../../session/crypto';
|
|||
import { PubKey } from '../../../../session/types';
|
||||
import { openConversationWithMessages } from '../../../../state/ducks/conversations';
|
||||
import { updateUserDetailsModal } from '../../../../state/ducks/modalDialog';
|
||||
import { getMessageAvatarProps } from '../../../../state/selectors/conversations';
|
||||
import {
|
||||
getIsTypingEnabled,
|
||||
getMessageAvatarProps,
|
||||
getSelectedConversationIsGroup,
|
||||
getSelectedConversationKey,
|
||||
} from '../../../../state/selectors/conversations';
|
||||
getSelectedCanWrite,
|
||||
useSelectedConversationKey,
|
||||
useSelectedIsGroup,
|
||||
} from '../../../../state/selectors/selectedConversation';
|
||||
import { Avatar, AvatarSize, CrownIcon } from '../../../avatar/Avatar';
|
||||
// tslint:disable: use-simple-attributes
|
||||
|
||||
|
@ -37,10 +37,10 @@ export const MessageAvatar = (props: Props) => {
|
|||
|
||||
const dispatch = useDispatch();
|
||||
const avatarProps = useSelector(state => getMessageAvatarProps(state as any, messageId));
|
||||
const selectedConvoKey = useSelector(getSelectedConversationKey);
|
||||
const isSelectedGroup = useSelector(getSelectedConversationIsGroup);
|
||||
const selectedConvoKey = useSelectedConversationKey();
|
||||
const isSelectedGroup = useSelectedIsGroup();
|
||||
|
||||
const isTypingEnabled = useSelector(getIsTypingEnabled);
|
||||
const isTypingEnabled = useSelector(getSelectedCanWrite);
|
||||
|
||||
if (!avatarProps) {
|
||||
return null;
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import { isEmpty, isEqual } from 'lodash';
|
||||
import React, { ReactElement, useEffect, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { MessageRenderingProps } from '../../../../models/messageType';
|
||||
import { isEmpty, isEqual } from 'lodash';
|
||||
import { SortedReactionList } from '../../../../types/Reaction';
|
||||
import { StyledPopupContainer } from '../reactions/ReactionPopup';
|
||||
import { Flex } from '../../../basic/Flex';
|
||||
import { nativeEmojiData } from '../../../../util/emoji';
|
||||
import { Reaction, ReactionProps } from '../reactions/Reaction';
|
||||
import { SessionIcon } from '../../../icon';
|
||||
import { useMessageReactsPropsById } from '../../../../hooks/useParamSelector';
|
||||
import { getSelectedConversationIsGroup } from '../../../../state/selectors/conversations';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { MessageRenderingProps } from '../../../../models/messageType';
|
||||
import { useSelectedIsGroup } from '../../../../state/selectors/selectedConversation';
|
||||
import { SortedReactionList } from '../../../../types/Reaction';
|
||||
import { nativeEmojiData } from '../../../../util/emoji';
|
||||
import { Flex } from '../../../basic/Flex';
|
||||
import { SessionIcon } from '../../../icon';
|
||||
import { Reaction, ReactionProps } from '../reactions/Reaction';
|
||||
import { StyledPopupContainer } from '../reactions/ReactionPopup';
|
||||
|
||||
export const popupXDefault = -81;
|
||||
export const popupYDefault = -90;
|
||||
|
@ -164,7 +163,7 @@ export const MessageReactions = (props: Props): ReactElement => {
|
|||
|
||||
const msgProps = useMessageReactsPropsById(messageId);
|
||||
|
||||
const inGroup = useSelector(getSelectedConversationIsGroup);
|
||||
const inGroup = useSelectedIsGroup();
|
||||
|
||||
useEffect(() => {
|
||||
if (msgProps?.sortedReacts && !isEqual(reactions, msgProps?.sortedReacts)) {
|
||||
|
|
|
@ -1,22 +1,19 @@
|
|||
import React, { useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import * as MIME from '../../../../../ts/types/MIME';
|
||||
import * as GoogleChrome from '../../../../../ts/util/GoogleChrome';
|
||||
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { noop } from 'lodash';
|
||||
import { useDisableDrag } from '../../../../hooks/useDisableDrag';
|
||||
import { useEncryptedFileFetch } from '../../../../hooks/useEncryptedFileFetch';
|
||||
import { PubKey } from '../../../../session/types';
|
||||
import {
|
||||
getSelectedConversationKey,
|
||||
isPublicGroupConversation,
|
||||
} from '../../../../state/selectors/conversations';
|
||||
useSelectedIsPrivate,
|
||||
useSelectedIsPublic,
|
||||
} from '../../../../state/selectors/selectedConversation';
|
||||
import { ContactName } from '../../ContactName';
|
||||
import { MessageBody } from './MessageBody';
|
||||
import { useIsPrivate } from '../../../../hooks/useParamSelector';
|
||||
|
||||
export type QuotePropsWithoutListener = {
|
||||
attachment?: QuotedAttachmentType;
|
||||
|
@ -229,8 +226,7 @@ export const QuoteText = (
|
|||
) => {
|
||||
const { text, attachment, isIncoming } = props;
|
||||
|
||||
const convoId = useSelector(getSelectedConversationKey);
|
||||
const isGroup = !useIsPrivate(convoId);
|
||||
const isGroup = !useSelectedIsPrivate();
|
||||
|
||||
if (text) {
|
||||
return (
|
||||
|
@ -345,7 +341,7 @@ export const Quote = (props: QuotePropsWithListener) => {
|
|||
setImageBroken(true);
|
||||
};
|
||||
|
||||
const isPublic = useSelector(isPublicGroupConversation);
|
||||
const isPublic = useSelectedIsPublic();
|
||||
|
||||
if (!validateQuote(props)) {
|
||||
return null;
|
||||
|
|
|
@ -17,11 +17,11 @@ import {
|
|||
getMostRecentMessageId,
|
||||
getOldestMessageId,
|
||||
getQuotedMessageToAnimate,
|
||||
getSelectedConversationKey,
|
||||
getShowScrollButton,
|
||||
getYoungestMessageId,
|
||||
} from '../../../../state/selectors/conversations';
|
||||
import { getIsAppFocused } from '../../../../state/selectors/section';
|
||||
import { useSelectedConversationKey } from '../../../../state/selectors/selectedConversation';
|
||||
import { ScrollToLoadedMessageContext } from '../../SessionMessagesListContainer';
|
||||
|
||||
type ReadableMessageProps = {
|
||||
|
@ -63,7 +63,7 @@ export const ReadableMessage = (props: ReadableMessageProps) => {
|
|||
const isAppFocused = useSelector(getIsAppFocused);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const selectedConversationKey = useSelector(getSelectedConversationKey);
|
||||
const selectedConversationKey = useSelectedConversationKey();
|
||||
const loadedMessagesLength = useSelector(getLoadedMessagesLength);
|
||||
const mostRecentMessageId = useSelector(getMostRecentMessageId);
|
||||
const oldestMessageId = useSelector(getOldestMessageId);
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { PubKey } from '../../../../../session/types';
|
||||
|
||||
import {
|
||||
CallNotificationType,
|
||||
PropsForCallNotification,
|
||||
} from '../../../../../state/ducks/conversations';
|
||||
import { getSelectedConversation } from '../../../../../state/selectors/conversations';
|
||||
import {
|
||||
useSelectedConversationKey,
|
||||
useSelectedDisplayNameInProfile,
|
||||
useSelectedNickname,
|
||||
} from '../../../../../state/selectors/selectedConversation';
|
||||
import { LocalizerKeys } from '../../../../../types/LocalizerKeys';
|
||||
import { SessionIconType } from '../../../../icon';
|
||||
import { ReadableMessage } from '../ReadableMessage';
|
||||
|
@ -37,13 +40,13 @@ const style: StyleType = {
|
|||
|
||||
export const CallNotification = (props: PropsForCallNotification) => {
|
||||
const { messageId, receivedAt, isUnread, notificationType } = props;
|
||||
const selectedConvoId = useSelectedConversationKey();
|
||||
|
||||
const selectedConvoProps = useSelector(getSelectedConversation);
|
||||
const displayNameInProfile = useSelectedDisplayNameInProfile();
|
||||
const nickname = useSelectedNickname();
|
||||
|
||||
const displayName =
|
||||
selectedConvoProps?.nickname ||
|
||||
selectedConvoProps?.displayNameInProfile ||
|
||||
(selectedConvoProps?.id && PubKey.shorten(selectedConvoProps?.id));
|
||||
nickname || displayNameInProfile || (selectedConvoId && PubKey.shorten(selectedConvoId));
|
||||
|
||||
const styleItem = style[notificationType];
|
||||
const notificationText = window.i18n(styleItem.notificationTextKey, [displayName || 'Unknown']);
|
||||
|
|
|
@ -76,7 +76,7 @@ export const Reaction = (props: ReactionProps): ReactElement => {
|
|||
const reactionRef = useRef<HTMLDivElement>(null);
|
||||
const { docX, elW } = useMouse(reactionRef);
|
||||
|
||||
const gutterWidth = 380;
|
||||
const gutterWidth = 380; // TODO make this a variable which can be shared in CSS and JS
|
||||
const tooltipMidPoint = POPUP_WIDTH / 2; // px
|
||||
const [tooltipPosition, setTooltipPosition] = useState<TipPosition>('center');
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { isEmpty, isEqual } from 'lodash';
|
||||
import React, { ReactElement, useEffect, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import styled from 'styled-components';
|
||||
import { Data } from '../../data/data';
|
||||
import { useMessageReactsPropsById, useWeAreModerator } from '../../hooks/useParamSelector';
|
||||
|
@ -11,7 +11,7 @@ import {
|
|||
updateReactListModal,
|
||||
updateUserDetailsModal,
|
||||
} from '../../state/ducks/modalDialog';
|
||||
import { getSelectedConversationIsPublic } from '../../state/selectors/conversations';
|
||||
import { useSelectedIsPublic } from '../../state/selectors/selectedConversation';
|
||||
import { SortedReactionList } from '../../types/Reaction';
|
||||
import { nativeEmojiData } from '../../util/emoji';
|
||||
import { Reactions } from '../../util/reactions';
|
||||
|
@ -228,7 +228,7 @@ export const ReactListModal = (props: Props): ReactElement => {
|
|||
const [senders, setSenders] = useState<Array<string>>([]);
|
||||
|
||||
const msgProps = useMessageReactsPropsById(messageId);
|
||||
const isPublic = useSelector(getSelectedConversationIsPublic);
|
||||
const isPublic = useSelectedIsPublic();
|
||||
const weAreModerator = useWeAreModerator(msgProps?.convoId);
|
||||
const me = UserUtils.getOurPubKeyStrFromCache();
|
||||
|
||||
|
|
|
@ -5,25 +5,24 @@ import { contextMenu } from 'react-contexify';
|
|||
import { Avatar, AvatarSize } from '../../avatar/Avatar';
|
||||
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import {
|
||||
openConversationWithMessages,
|
||||
ReduxConversationType,
|
||||
} from '../../../state/ducks/conversations';
|
||||
import { updateUserDetailsModal } from '../../../state/ducks/modalDialog';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { useSelector } from 'react-redux';
|
||||
import _, { isNil } from 'lodash';
|
||||
import {
|
||||
useAvatarPath,
|
||||
useConversationUsername,
|
||||
useHasUnread,
|
||||
useIsBlocked,
|
||||
useIsPrivate,
|
||||
useIsSelectedConversation,
|
||||
useMentionedUs,
|
||||
} from '../../../hooks/useParamSelector';
|
||||
import { isSearching } from '../../../state/selectors/search';
|
||||
import { useSelectedConversationKey } from '../../../state/selectors/selectedConversation';
|
||||
import { MemoConversationListItemContextMenu } from '../../menu/ConversationListItemContextMenu';
|
||||
import { ConversationListItemHeaderItem } from './HeaderItem';
|
||||
import { MessageItem } from './MessageItem';
|
||||
|
@ -85,7 +84,9 @@ const ConversationListItem = (props: Props) => {
|
|||
let hasUnreadMentionedUs = useMentionedUs(conversationId);
|
||||
let isBlocked = useIsBlocked(conversationId);
|
||||
const isSearch = useSelector(isSearching);
|
||||
const isSelectedConvo = useIsSelectedConversation(conversationId);
|
||||
const selectedConvo = useSelectedConversationKey();
|
||||
|
||||
const isSelectedConvo = conversationId === selectedConvo && !isNil(selectedConvo);
|
||||
|
||||
if (isSearch) {
|
||||
// force isBlocked and hasUnreadMentionedUs to be false, we just want to display the row without any special style when showing search results
|
||||
|
|
|
@ -3,10 +3,7 @@ import React from 'react';
|
|||
|
||||
import { SpacerLG } from '../../basic/Text';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import {
|
||||
getConversationRequests,
|
||||
getSelectedConversation,
|
||||
} from '../../../state/selectors/conversations';
|
||||
import { getConversationRequests } from '../../../state/selectors/conversations';
|
||||
import { MemoConversationListItemWithDetails } from '../conversation-list-item/ConversationListItem';
|
||||
import styled from 'styled-components';
|
||||
import { SessionButton, SessionButtonColor } from '../../basic/SessionButton';
|
||||
|
@ -20,6 +17,7 @@ import {
|
|||
resetConversationExternal,
|
||||
} from '../../../state/ducks/conversations';
|
||||
import { updateConfirmModal } from '../../../state/ducks/modalDialog';
|
||||
import { useSelectedConversationKey } from '../../../state/selectors/selectedConversation';
|
||||
|
||||
const MessageRequestListPlaceholder = styled.div`
|
||||
color: var(--conversation-tab-text-color);
|
||||
|
@ -55,7 +53,7 @@ export const OverlayMessageRequest = () => {
|
|||
}
|
||||
const convoRequestCount = useSelector(getConversationRequests).length;
|
||||
const messageRequests = useSelector(getConversationRequests);
|
||||
const selectedConversation = useSelector(getSelectedConversation);
|
||||
const selectedConvoId = useSelectedConversationKey();
|
||||
|
||||
const buttonText = window.i18n('clearAll');
|
||||
|
||||
|
@ -94,7 +92,7 @@ export const OverlayMessageRequest = () => {
|
|||
await convoModel.setIsApproved(false);
|
||||
|
||||
// if we're looking at the convo to decline, close the convo
|
||||
if (selectedConversation?.id === id) {
|
||||
if (selectedConvoId === id) {
|
||||
dispatch(resetConversationExternal());
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -6,12 +6,12 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||
import { Lightbox } from './Lightbox';
|
||||
|
||||
// tslint:disable-next-line: no-submodule-imports
|
||||
import { useDispatch } from 'react-redux';
|
||||
import useKey from 'react-use/lib/useKey';
|
||||
import { AttachmentTypeWithPath } from '../../types/Attachment';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { showLightBox } from '../../state/ducks/conversations';
|
||||
import { getSelectedConversationKey } from '../../state/selectors/conversations';
|
||||
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
|
||||
import { MIME } from '../../types';
|
||||
import { AttachmentTypeWithPath } from '../../types/Attachment';
|
||||
import { saveAttachmentToDisk } from '../../util/attachmentsUtil';
|
||||
|
||||
export interface MediaItemType {
|
||||
|
@ -33,7 +33,11 @@ type Props = {
|
|||
export const LightboxGallery = (props: Props) => {
|
||||
const { media } = props;
|
||||
const [currentIndex, setCurrentIndex] = useState(-1);
|
||||
const selectedConversation = useSelector(getSelectedConversationKey) as string;
|
||||
const selectedConversation = useSelectedConversationKey();
|
||||
|
||||
if (!selectedConversation) {
|
||||
throw new Error('LightboxGallery: selectedConversation is undefined');
|
||||
}
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
|
|
@ -24,9 +24,8 @@ import {
|
|||
} from './Menu';
|
||||
import _ from 'lodash';
|
||||
import { ContextConversationId } from '../leftpane/conversation-list-item/ConversationListItem';
|
||||
import { getSelectedConversationKey } from '../../state/selectors/conversations';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { SessionContextMenuContainer } from '../SessionContextMenuContainer';
|
||||
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
|
||||
|
||||
export type PropsConversationHeaderMenu = {
|
||||
triggerId: string;
|
||||
|
@ -35,7 +34,7 @@ export type PropsConversationHeaderMenu = {
|
|||
export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => {
|
||||
const { triggerId } = props;
|
||||
|
||||
const selectedConversation = useSelector(getSelectedConversationKey);
|
||||
const selectedConversation = useSelectedConversationKey();
|
||||
|
||||
if (!selectedConversation) {
|
||||
throw new Error('selectedConversation must be set for a header to be visible!');
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
import { isEmpty, isNil, pick } from 'lodash';
|
||||
import { isEmpty, pick } from 'lodash';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { ConversationModel } from '../models/conversation';
|
||||
import { PubKey } from '../session/types';
|
||||
import { UserUtils } from '../session/utils';
|
||||
import { StateType } from '../state/reducer';
|
||||
import {
|
||||
getMessageReactsProps,
|
||||
getSelectedConversationKey,
|
||||
} from '../state/selectors/conversations';
|
||||
import { getMessageReactsProps } from '../state/selectors/conversations';
|
||||
|
||||
export function useAvatarPath(convoId: string | undefined) {
|
||||
const convoProps = useConversationPropsById(convoId);
|
||||
|
@ -220,8 +217,3 @@ export function useMentionedUs(conversationId?: string): boolean {
|
|||
export function useIsTyping(conversationId?: string): boolean {
|
||||
return useConversationPropsById(conversationId)?.isTyping || false;
|
||||
}
|
||||
|
||||
export function useIsSelectedConversation(conversation?: string): boolean {
|
||||
const selectedConvo = useSelector(getSelectedConversationKey);
|
||||
return !isNil(selectedConvo) && !isNil(conversation) && selectedConvo === conversation;
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ import {
|
|||
InputItem,
|
||||
removeVideoEventsListener,
|
||||
} from '../session/utils/calling/CallManager';
|
||||
import { getSelectedConversationKey } from '../state/selectors/conversations';
|
||||
import { getCallIsInFullScreen, getHasOngoingCallWithPubkey } from '../state/selectors/call';
|
||||
import { useSelectedConversationKey } from '../state/selectors/selectedConversation';
|
||||
|
||||
export function useVideoCallEventsListener(uniqueId: string, onSame: boolean) {
|
||||
const selectedConversationKey = useSelector(getSelectedConversationKey);
|
||||
const selectedConversationKey = useSelectedConversationKey();
|
||||
const ongoingCallPubkey = useSelector(getHasOngoingCallWithPubkey);
|
||||
const isFullScreen = useSelector(getCallIsInFullScreen);
|
||||
|
||||
|
|
|
@ -190,8 +190,9 @@ export function showLeaveGroupByConvoId(conversationId: string) {
|
|||
|
||||
const title = window.i18n('leaveGroup');
|
||||
const message = window.i18n('leaveGroupConfirmation');
|
||||
const ourPK = UserUtils.getOurPubKeyStrFromCache();
|
||||
const isAdmin = (conversation.get('groupAdmins') || []).includes(ourPK);
|
||||
const isAdmin = (conversation.get('groupAdmins') || []).includes(
|
||||
UserUtils.getOurPubKeyStrFromCache()
|
||||
);
|
||||
const isClosedGroup = conversation.isClosedGroup() || false;
|
||||
|
||||
// if this is not a closed group, or we are not admin, we can just show a confirmation dialog
|
||||
|
|
|
@ -1296,8 +1296,8 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
|
|||
return window.i18n('titleIsNow', [groupUpdate.name]);
|
||||
}
|
||||
if (groupUpdate.joined && groupUpdate.joined.length) {
|
||||
const names = groupUpdate.joined.map((pubKey: string) =>
|
||||
getConversationController().getContactProfileNameOrShortenedPubKey(pubKey)
|
||||
const names = groupUpdate.joined.map(
|
||||
getConversationController().getContactProfileNameOrShortenedPubKey
|
||||
);
|
||||
|
||||
if (names.length > 1) {
|
||||
|
|
|
@ -143,43 +143,43 @@ async function handleContactsUpdate(result: IncomingConfResult): Promise<Incomin
|
|||
continue;
|
||||
}
|
||||
|
||||
const existingConvo = await getConversationController().getOrCreateAndWait(
|
||||
const contactConvo = await getConversationController().getOrCreateAndWait(
|
||||
wrapperConvo.id,
|
||||
ConversationTypeEnum.PRIVATE
|
||||
);
|
||||
if (wrapperConvo.id && existingConvo) {
|
||||
if (wrapperConvo.id && contactConvo) {
|
||||
let changes = false;
|
||||
|
||||
// the display name set is handled in `updateProfileOfContact`
|
||||
if (wrapperConvo.nickname !== existingConvo.getNickname()) {
|
||||
await existingConvo.setNickname(wrapperConvo.nickname || null, false);
|
||||
if (wrapperConvo.nickname !== contactConvo.getNickname()) {
|
||||
await contactConvo.setNickname(wrapperConvo.nickname || null, false);
|
||||
changes = true;
|
||||
}
|
||||
|
||||
if (!wrapperConvo.hidden && !existingConvo.isHidden()) {
|
||||
existingConvo.set({ hidden: false });
|
||||
if (!wrapperConvo.hidden && !contactConvo.isHidden()) {
|
||||
contactConvo.set({ hidden: false });
|
||||
changes = true;
|
||||
}
|
||||
|
||||
if (Boolean(wrapperConvo.approved) !== Boolean(existingConvo.isApproved())) {
|
||||
await existingConvo.setIsApproved(Boolean(wrapperConvo.approved), false);
|
||||
if (Boolean(wrapperConvo.approved) !== Boolean(contactConvo.isApproved())) {
|
||||
await contactConvo.setIsApproved(Boolean(wrapperConvo.approved), false);
|
||||
changes = true;
|
||||
}
|
||||
|
||||
if (Boolean(wrapperConvo.approvedMe) !== Boolean(existingConvo.didApproveMe())) {
|
||||
await existingConvo.setDidApproveMe(Boolean(wrapperConvo.approvedMe), false);
|
||||
if (Boolean(wrapperConvo.approvedMe) !== Boolean(contactConvo.didApproveMe())) {
|
||||
await contactConvo.setDidApproveMe(Boolean(wrapperConvo.approvedMe), false);
|
||||
changes = true;
|
||||
}
|
||||
|
||||
if (Boolean(wrapperConvo.approvedMe) !== Boolean(existingConvo.didApproveMe())) {
|
||||
await existingConvo.setDidApproveMe(Boolean(wrapperConvo.approvedMe), false);
|
||||
if (Boolean(wrapperConvo.approvedMe) !== Boolean(contactConvo.didApproveMe())) {
|
||||
await contactConvo.setDidApproveMe(Boolean(wrapperConvo.approvedMe), false);
|
||||
changes = true;
|
||||
}
|
||||
|
||||
//TODO priority means more than just isPinned but has an order logic in it too
|
||||
const shouldBePinned = wrapperConvo.priority > 0;
|
||||
if (shouldBePinned !== Boolean(existingConvo.isPinned())) {
|
||||
await existingConvo.setIsPinned(shouldBePinned, false);
|
||||
if (shouldBePinned !== Boolean(contactConvo.isPinned())) {
|
||||
await contactConvo.setIsPinned(shouldBePinned, false);
|
||||
changes = true;
|
||||
}
|
||||
|
||||
|
@ -188,12 +188,12 @@ async function handleContactsUpdate(result: IncomingConfResult): Promise<Incomin
|
|||
|
||||
// make sure to write the changes to the database now as the `AvatarDownloadJob` below might take some time before getting run
|
||||
if (changes) {
|
||||
await existingConvo.commit();
|
||||
await contactConvo.commit();
|
||||
}
|
||||
|
||||
// we still need to handle the `name` (synchronous) and the `profilePicture` (asynchronous)
|
||||
await ProfileManager.updateProfileOfContact(
|
||||
existingConvo.id,
|
||||
contactConvo.id,
|
||||
wrapperConvo.name,
|
||||
wrapperConvo.profilePicture?.url || null,
|
||||
wrapperConvo.profilePicture?.key || null
|
||||
|
@ -273,20 +273,20 @@ async function handleCommunitiesUpdate() {
|
|||
fromWrapper.roomCasePreserved
|
||||
);
|
||||
|
||||
const existingConvo = getConversationController().get(convoId);
|
||||
if (fromWrapper && existingConvo) {
|
||||
const communityConvo = getConversationController().get(convoId);
|
||||
if (fromWrapper && communityConvo) {
|
||||
let changes = false;
|
||||
|
||||
//TODO priority means more than just isPinned but has an order logic in it too
|
||||
const shouldBePinned = fromWrapper.priority > 0;
|
||||
if (shouldBePinned !== Boolean(existingConvo.isPinned())) {
|
||||
await existingConvo.setIsPinned(shouldBePinned, false);
|
||||
if (shouldBePinned !== Boolean(communityConvo.isPinned())) {
|
||||
await communityConvo.setIsPinned(shouldBePinned, false);
|
||||
changes = true;
|
||||
}
|
||||
|
||||
// make sure to write the changes to the database now as the `AvatarDownloadJob` below might take some time before getting run
|
||||
if (changes) {
|
||||
await existingConvo.commit();
|
||||
await communityConvo.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,8 +340,8 @@ async function handleLegacyGroupUpdate(latestEnvelopeTimestamp: number) {
|
|||
for (let index = 0; index < allLegacyGroupsInWrapper.length; index++) {
|
||||
const fromWrapper = allLegacyGroupsInWrapper[index];
|
||||
|
||||
const convo = getConversationController().get(fromWrapper.pubkeyHex);
|
||||
if (!convo) {
|
||||
const legacyGroupConvo = getConversationController().get(fromWrapper.pubkeyHex);
|
||||
if (!legacyGroupConvo) {
|
||||
// this should not happen as we made sure to create them before
|
||||
window.log.warn(
|
||||
'could not find legacy group which should already be there:',
|
||||
|
@ -360,8 +360,9 @@ async function handleLegacyGroupUpdate(latestEnvelopeTimestamp: number) {
|
|||
members,
|
||||
admins,
|
||||
activeAt:
|
||||
!!convo.get('active_at') && convo.get('active_at') < latestEnvelopeTimestamp
|
||||
? convo.get('active_at')
|
||||
!!legacyGroupConvo.get('active_at') &&
|
||||
legacyGroupConvo.get('active_at') < latestEnvelopeTimestamp
|
||||
? legacyGroupConvo.get('active_at')
|
||||
: latestEnvelopeTimestamp,
|
||||
weWereJustAdded: false, // TODO to remove
|
||||
};
|
||||
|
@ -369,16 +370,16 @@ async function handleLegacyGroupUpdate(latestEnvelopeTimestamp: number) {
|
|||
await ClosedGroup.updateOrCreateClosedGroup(groupDetails);
|
||||
|
||||
let changes = false;
|
||||
if (convo.isPinned() !== fromWrapper.priority > 0) {
|
||||
await convo.setIsPinned(fromWrapper.priority > 0, false);
|
||||
if (legacyGroupConvo.isPinned() !== fromWrapper.priority > 0) {
|
||||
await legacyGroupConvo.setIsPinned(fromWrapper.priority > 0, false);
|
||||
changes = true;
|
||||
}
|
||||
if (!!convo.isHidden() !== !!fromWrapper.hidden) {
|
||||
convo.set({ hidden: !!fromWrapper.hidden });
|
||||
if (!!legacyGroupConvo.isHidden() !== !!fromWrapper.hidden) {
|
||||
legacyGroupConvo.set({ hidden: !!fromWrapper.hidden });
|
||||
changes = true;
|
||||
}
|
||||
if (convo.get('expireTimer') !== fromWrapper.disappearingTimerSeconds) {
|
||||
await convo.updateExpireTimer(
|
||||
if (legacyGroupConvo.get('expireTimer') !== fromWrapper.disappearingTimerSeconds) {
|
||||
await legacyGroupConvo.updateExpireTimer(
|
||||
fromWrapper.disappearingTimerSeconds,
|
||||
undefined,
|
||||
latestEnvelopeTimestamp,
|
||||
|
@ -390,45 +391,23 @@ async function handleLegacyGroupUpdate(latestEnvelopeTimestamp: number) {
|
|||
}
|
||||
|
||||
if (changes) {
|
||||
await convo.commit();
|
||||
await legacyGroupConvo.commit();
|
||||
}
|
||||
|
||||
// save the encryption keypair if needed
|
||||
if (!isEmpty(fromWrapper.encPubkey) && !isEmpty(fromWrapper.encSeckey)) {
|
||||
const inWrapperKeypair: HexKeyPair = {
|
||||
publicHex: toHex(fromWrapper.encPubkey),
|
||||
privateHex: toHex(fromWrapper.encSeckey),
|
||||
};
|
||||
try {
|
||||
const inWrapperKeypair: HexKeyPair = {
|
||||
publicHex: toHex(fromWrapper.encPubkey),
|
||||
privateHex: toHex(fromWrapper.encSeckey),
|
||||
};
|
||||
|
||||
await addKeyPairToCacheAndDBIfNeeded(fromWrapper.pubkeyHex, inWrapperKeypair);
|
||||
await addKeyPairToCacheAndDBIfNeeded(fromWrapper.pubkeyHex, inWrapperKeypair);
|
||||
} catch (e) {
|
||||
window.log.warn('failed to save keypair for legacugroup', fromWrapper.pubkeyHex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // if the convos already exists, make sure to update the fields if needed
|
||||
// for (let index = 0; index < allCommunitiesInWrapper.length; index++) {
|
||||
// const fromWrapper = allCommunitiesInWrapper[index];
|
||||
// const convoId = OpenGroupUtils.getOpenGroupV2ConversationId(
|
||||
// fromWrapper.baseUrl,
|
||||
// fromWrapper.roomCasePreserved
|
||||
// );
|
||||
|
||||
// const existingConvo = getConversationController().get(convoId);
|
||||
// if (fromWrapper && existingConvo) {
|
||||
// let changes = false;
|
||||
|
||||
// //TODO priority means more than just isPinned but has an order logic in it too
|
||||
// const shouldBePinned = fromWrapper.priority > 0;
|
||||
// if (shouldBePinned !== Boolean(existingConvo.isPinned())) {
|
||||
// await existingConvo.setIsPinned(shouldBePinned, false);
|
||||
// changes = true;
|
||||
// }
|
||||
|
||||
// // make sure to write the changes to the database now as the `AvatarDownloadJob` below might take some time before getting run
|
||||
// if (changes) {
|
||||
// await existingConvo.commit();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
async function handleUserGroupsUpdate(result: IncomingConfResult): Promise<IncomingConfResult> {
|
||||
|
|
|
@ -87,22 +87,19 @@ export class ConversationController {
|
|||
throw new Error('getConversationController().get() needs complete initial fetch');
|
||||
}
|
||||
|
||||
let conversation = this.conversations.get(id);
|
||||
if (conversation) {
|
||||
return conversation;
|
||||
if (this.conversations.get(id)) {
|
||||
return this.conversations.get(id) as ConversationModel;
|
||||
}
|
||||
|
||||
conversation = this.conversations.add({
|
||||
const conversation = this.conversations.add({
|
||||
id,
|
||||
type,
|
||||
});
|
||||
|
||||
const create = async () => {
|
||||
try {
|
||||
const saveDetails = await Data.saveConversation(conversation.attributes);
|
||||
if (saveDetails) {
|
||||
await conversation.refreshInMemoryDetails(saveDetails);
|
||||
}
|
||||
// this saves to DB and to the required wrapper
|
||||
await conversation.commit();
|
||||
} catch (error) {
|
||||
window?.log?.error(
|
||||
'Conversation save failed! ',
|
||||
|
@ -114,25 +111,22 @@ export class ConversationController {
|
|||
throw error;
|
||||
}
|
||||
|
||||
return conversation;
|
||||
};
|
||||
window?.inboxStore?.dispatch(
|
||||
conversationActions.conversationAdded({
|
||||
id: conversation.id,
|
||||
data: conversation.getConversationModelProps(),
|
||||
})
|
||||
);
|
||||
|
||||
conversation.initialPromise = create();
|
||||
conversation.initialPromise.then(() => {
|
||||
if (window?.inboxStore) {
|
||||
window.inboxStore?.dispatch(
|
||||
conversationActions.conversationAdded({
|
||||
id: conversation.id,
|
||||
data: conversation.getConversationModelProps(),
|
||||
})
|
||||
);
|
||||
}
|
||||
if (!conversation.isPublic() && conversation.isActive()) {
|
||||
// NOTE: we request snodes updating the cache, but ignore the result
|
||||
|
||||
void getSwarmFor(id);
|
||||
}
|
||||
});
|
||||
return conversation;
|
||||
};
|
||||
|
||||
conversation.initialPromise = create();
|
||||
|
||||
return conversation;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@ import { createSelector } from '@reduxjs/toolkit';
|
|||
import { CallStateType, CallStatusEnum } from '../ducks/call';
|
||||
import { ConversationsStateType, ReduxConversationType } from '../ducks/conversations';
|
||||
import { StateType } from '../reducer';
|
||||
import { getConversations, getSelectedConversationKey } from './conversations';
|
||||
import { getConversations } from './conversations';
|
||||
import { getSelectedConversationKey } from './selectedConversation';
|
||||
|
||||
const getCallState = (state: StateType): CallStateType => state.call;
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { createSelector } from '@reduxjs/toolkit';
|
||||
|
||||
import { StateType } from '../reducer';
|
||||
import {
|
||||
ConversationLookupType,
|
||||
ConversationsStateType,
|
||||
|
@ -11,12 +10,8 @@ import {
|
|||
ReduxConversationType,
|
||||
SortedMessageModelProps,
|
||||
} from '../ducks/conversations';
|
||||
import { StateType } from '../reducer';
|
||||
|
||||
import { getIntl } from './user';
|
||||
import { BlockedNumberController } from '../../util';
|
||||
import { ConversationModel } from '../../models/conversation';
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
import { ConversationHeaderTitleProps } from '../../components/conversation/ConversationHeader';
|
||||
import { ReplyingToMessageProps } from '../../components/conversation/composition/CompositionBox';
|
||||
import { MessageAttachmentSelectorProps } from '../../components/conversation/message/message-content/MessageAttachment';
|
||||
import { MessageAuthorSelectorProps } from '../../components/conversation/message/message-content/MessageAuthorText';
|
||||
|
@ -30,14 +25,19 @@ import { MessageStatusSelectorProps } from '../../components/conversation/messag
|
|||
import { MessageTextSelectorProps } from '../../components/conversation/message/message-content/MessageText';
|
||||
import { GenericReadableMessageSelectorProps } from '../../components/conversation/message/message-item/GenericReadableMessage';
|
||||
import { LightBoxOptions } from '../../components/conversation/SessionConversation';
|
||||
import { ConversationModel } from '../../models/conversation';
|
||||
import { ConversationTypeEnum, isOpenOrClosedGroup } from '../../models/conversationAttributes';
|
||||
import { getConversationController } from '../../session/conversations';
|
||||
import { UserUtils } from '../../session/utils';
|
||||
import { LocalizerType } from '../../types/Util';
|
||||
import { BlockedNumberController } from '../../util';
|
||||
import { Storage } from '../../util/storage';
|
||||
import { ConversationTypeEnum, isOpenOrClosedGroup } from '../../models/conversationAttributes';
|
||||
import { getIntl } from './user';
|
||||
|
||||
import { MessageReactsSelectorProps } from '../../components/conversation/message/message-content/MessageReactions';
|
||||
import { filter, isEmpty, pick, sortBy } from 'lodash';
|
||||
import { getCanWrite, getModeratorsOutsideRedux, getSubscriberCount } from './sogsRoomInfo';
|
||||
import { MessageReactsSelectorProps } from '../../components/conversation/message/message-content/MessageReactions';
|
||||
import { getModeratorsOutsideRedux } from './sogsRoomInfo';
|
||||
import { getSelectedConversation, getSelectedConversationKey } from './selectedConversation';
|
||||
|
||||
export const getConversations = (state: StateType): ConversationsStateType => state.conversations;
|
||||
|
||||
|
@ -52,80 +52,6 @@ export const getConversationsCount = createSelector(getConversationLookup, (stat
|
|||
return Object.values(state).length;
|
||||
});
|
||||
|
||||
export const getSelectedConversationKey = createSelector(
|
||||
getConversations,
|
||||
(state: ConversationsStateType): string | undefined => {
|
||||
return state.selectedConversation;
|
||||
}
|
||||
);
|
||||
|
||||
export const getSelectedConversation = createSelector(
|
||||
getConversations,
|
||||
(state: ConversationsStateType): ReduxConversationType | undefined => {
|
||||
return state.selectedConversation
|
||||
? state.conversationLookup[state.selectedConversation]
|
||||
: undefined;
|
||||
}
|
||||
);
|
||||
|
||||
export const getSelectedConversationIsPublic = createSelector(
|
||||
getSelectedConversation,
|
||||
(state: ReduxConversationType | undefined): boolean => {
|
||||
return state?.isPublic || false;
|
||||
}
|
||||
);
|
||||
|
||||
export function getIsTypingEnabled(state: StateType) {
|
||||
const selectedConvoPubkey = getSelectedConversationKey(state);
|
||||
if (!selectedConvoPubkey) {
|
||||
return false;
|
||||
}
|
||||
const selectedConvo = state.conversations.conversationLookup[selectedConvoPubkey];
|
||||
if (!selectedConvo) {
|
||||
return false;
|
||||
}
|
||||
const canWrite = getCanWrite(state, selectedConvoPubkey);
|
||||
const { isBlocked, isKickedFromGroup, left, isPublic } = selectedConvo;
|
||||
|
||||
return !(isBlocked || isKickedFromGroup || left || (isPublic && !canWrite));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current conversation selected is a group conversation.
|
||||
* Returns false if the current conversation selected is not a group conversation, or none are selected
|
||||
*/
|
||||
export const getSelectedConversationIsGroup = createSelector(
|
||||
getSelectedConversation,
|
||||
(state: ReduxConversationType | undefined): boolean => {
|
||||
const type = state?.type;
|
||||
return type ? isOpenOrClosedGroup(type) : false;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns true if the current conversation selected is a closed group and false otherwise.
|
||||
*/
|
||||
export const isClosedGroupConversation = createSelector(
|
||||
getSelectedConversation,
|
||||
(state: ReduxConversationType | undefined): boolean => {
|
||||
return (
|
||||
(state?.type === ConversationTypeEnum.GROUP && !state.isPublic) ||
|
||||
state?.type === ConversationTypeEnum.GROUPV3 ||
|
||||
false
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns true if the current conversation selected is a public group and false otherwise.
|
||||
*/
|
||||
export const isPublicGroupConversation = createSelector(
|
||||
getSelectedConversation,
|
||||
(state: ReduxConversationType | undefined): boolean => {
|
||||
return (state?.type === ConversationTypeEnum.GROUP && state.isPublic) || false;
|
||||
}
|
||||
);
|
||||
|
||||
export const getOurPrimaryConversation = createSelector(
|
||||
getConversations,
|
||||
(state: ConversationsStateType): ReduxConversationType =>
|
||||
|
@ -547,85 +473,6 @@ export const getGlobalUnreadMessageCount = createSelector(getLeftPaneLists, (sta
|
|||
return state.globalUnreadCount;
|
||||
});
|
||||
|
||||
export const getConversationHeaderTitleProps = (
|
||||
state: StateType
|
||||
): ConversationHeaderTitleProps | undefined => {
|
||||
const convo = getSelectedConversation(state);
|
||||
if (!convo) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
isKickedFromGroup: !!convo.isKickedFromGroup,
|
||||
conversationKey: convo.id,
|
||||
isMe: !!convo.isMe,
|
||||
members: convo.members || [],
|
||||
isPublic: !!convo.isPublic,
|
||||
isGroup: isOpenOrClosedGroup(convo.type),
|
||||
currentNotificationSetting: convo.currentNotificationSetting,
|
||||
};
|
||||
};
|
||||
|
||||
export const getCurrentSubscriberCount = (state: StateType): number | undefined => {
|
||||
const convo = getSelectedConversation(state);
|
||||
if (!convo) {
|
||||
return undefined;
|
||||
}
|
||||
return getSubscriberCount(state, convo.id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the formatted text for notification setting.
|
||||
*/
|
||||
export const getCurrentNotificationSettingText = createSelector(getSelectedConversation, (state):
|
||||
| string
|
||||
| undefined => {
|
||||
if (!state) {
|
||||
return undefined;
|
||||
}
|
||||
switch (state.currentNotificationSetting) {
|
||||
case 'all':
|
||||
return window.i18n('notificationForConvo_all');
|
||||
case 'mentions_only':
|
||||
return window.i18n('notificationForConvo_mentions_only');
|
||||
case 'disabled':
|
||||
return window.i18n('notificationForConvo_disabled');
|
||||
default:
|
||||
return window.i18n('notificationForConvo_all');
|
||||
}
|
||||
});
|
||||
|
||||
export const getIsSelectedPrivate = createSelector(
|
||||
getSelectedConversation,
|
||||
(selectedProps): boolean => {
|
||||
return selectedProps?.isPrivate || false;
|
||||
}
|
||||
);
|
||||
|
||||
export const getIsSelectedBlocked = createSelector(
|
||||
getSelectedConversation,
|
||||
(selectedProps): boolean => {
|
||||
return selectedProps?.isBlocked || false;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns true if the currently selected conversation is active (has an active_at field > 0)
|
||||
*/
|
||||
export const getIsSelectedActive = createSelector(
|
||||
getSelectedConversation,
|
||||
(selectedProps): boolean => {
|
||||
return Boolean(selectedProps?.activeAt);
|
||||
}
|
||||
);
|
||||
|
||||
export const getIsSelectedNoteToSelf = createSelector(
|
||||
getSelectedConversation,
|
||||
(selectedProps): boolean => {
|
||||
return selectedProps?.isMe || false;
|
||||
}
|
||||
);
|
||||
|
||||
export const isMessageDetailView = createSelector(
|
||||
getConversations,
|
||||
(state: ConversationsStateType): boolean => state.messageDetailProps !== undefined
|
||||
|
|
|
@ -4,8 +4,9 @@ import { createSelector } from '@reduxjs/toolkit';
|
|||
import { StateType } from '../reducer';
|
||||
|
||||
import { SearchStateType } from '../ducks/search';
|
||||
import { getConversationLookup, getSelectedConversationKey } from './conversations';
|
||||
import { getConversationLookup } from './conversations';
|
||||
import { ConversationLookupType } from '../ducks/conversations';
|
||||
import { getSelectedConversationKey } from './selectedConversation';
|
||||
|
||||
export const getSearch = (state: StateType): SearchStateType => state.search;
|
||||
|
||||
|
|
185
ts/state/selectors/selectedConversation.ts
Normal file
185
ts/state/selectors/selectedConversation.ts
Normal file
|
@ -0,0 +1,185 @@
|
|||
import { useSelector } from 'react-redux';
|
||||
import { ConversationTypeEnum, isOpenOrClosedGroup } from '../../models/conversationAttributes';
|
||||
import { ReduxConversationType } from '../ducks/conversations';
|
||||
import { StateType } from '../reducer';
|
||||
import { getCanWrite, getSubscriberCount } from './sogsRoomInfo';
|
||||
|
||||
/**
|
||||
* Returns the formatted text for notification setting.
|
||||
*/
|
||||
const getCurrentNotificationSettingText = (state: StateType): string | undefined => {
|
||||
if (!state) {
|
||||
return undefined;
|
||||
}
|
||||
const currentNotificationSetting = getSelectedConversation(state)?.currentNotificationSetting;
|
||||
switch (currentNotificationSetting) {
|
||||
case 'all':
|
||||
return window.i18n('notificationForConvo_all');
|
||||
case 'mentions_only':
|
||||
return window.i18n('notificationForConvo_mentions_only');
|
||||
case 'disabled':
|
||||
return window.i18n('notificationForConvo_disabled');
|
||||
default:
|
||||
return window.i18n('notificationForConvo_all');
|
||||
}
|
||||
};
|
||||
|
||||
const getIsSelectedPrivate = (state: StateType): boolean => {
|
||||
return Boolean(getSelectedConversation(state)?.isPrivate) || false;
|
||||
};
|
||||
|
||||
const getIsSelectedBlocked = (state: StateType): boolean => {
|
||||
return Boolean(getSelectedConversation(state)?.isBlocked) || false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the currently selected conversation is active (has an active_at field > 0)
|
||||
*/
|
||||
const getIsSelectedActive = (state: StateType): boolean => {
|
||||
return Boolean(getSelectedConversation(state)?.activeAt) || false;
|
||||
};
|
||||
|
||||
const getIsSelectedNoteToSelf = (state: StateType): boolean => {
|
||||
return getSelectedConversation(state)?.isMe || false;
|
||||
};
|
||||
|
||||
export const getSelectedConversationKey = (state: StateType): string | undefined => {
|
||||
return state.conversations.selectedConversation;
|
||||
};
|
||||
|
||||
export const getSelectedConversation = (state: StateType): ReduxConversationType | undefined => {
|
||||
const selected = getSelectedConversationKey(state);
|
||||
return selected ? state.conversations.conversationLookup[selected] : undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the current conversation selected is a public group and false otherwise.
|
||||
*/
|
||||
export const getSelectedConversationIsPublic = (state: StateType): boolean => {
|
||||
return Boolean(getSelectedConversation(state)?.isPublic) || false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the current conversation selected can be typed into
|
||||
*/
|
||||
export function getSelectedCanWrite(state: StateType) {
|
||||
const selectedConvoPubkey = getSelectedConversationKey(state);
|
||||
if (!selectedConvoPubkey) {
|
||||
return false;
|
||||
}
|
||||
const selectedConvo = getSelectedConversation(state);
|
||||
if (!selectedConvo) {
|
||||
return false;
|
||||
}
|
||||
const canWrite = getCanWrite(state, selectedConvoPubkey);
|
||||
const { isBlocked, isKickedFromGroup, left, isPublic } = selectedConvo;
|
||||
|
||||
return !(isBlocked || isKickedFromGroup || left || (isPublic && !canWrite));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current conversation selected is a group conversation.
|
||||
* Returns false if the current conversation selected is not a group conversation, or none are selected
|
||||
*/
|
||||
const getSelectedConversationIsGroup = (state: StateType): boolean => {
|
||||
const selected = getSelectedConversation(state);
|
||||
if (!selected || !selected.type) {
|
||||
return false;
|
||||
}
|
||||
return selected.type ? isOpenOrClosedGroup(selected.type) : false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the current conversation selected is a closed group and false otherwise.
|
||||
*/
|
||||
export const isClosedGroupConversation = (state: StateType): boolean => {
|
||||
const selected = getSelectedConversation(state);
|
||||
if (!selected) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
(selected.type === ConversationTypeEnum.GROUP && !selected.isPublic) ||
|
||||
selected.type === ConversationTypeEnum.GROUPV3 ||
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
const getGroupMembers = (state: StateType): Array<string> => {
|
||||
const selected = getSelectedConversation(state);
|
||||
if (!selected) {
|
||||
return [];
|
||||
}
|
||||
return selected.members || [];
|
||||
};
|
||||
|
||||
const getSelectedSubscriberCount = (state: StateType): number | undefined => {
|
||||
const convo = getSelectedConversation(state);
|
||||
if (!convo) {
|
||||
return undefined;
|
||||
}
|
||||
return getSubscriberCount(state, convo.id);
|
||||
};
|
||||
|
||||
// ============== SELECTORS RELEVANT TO SELECTED/OPENED CONVERSATION ==============
|
||||
|
||||
export function useSelectedConversationKey() {
|
||||
return useSelector(getSelectedConversationKey);
|
||||
}
|
||||
|
||||
export function useSelectedIsGroup() {
|
||||
return useSelector(getSelectedConversationIsGroup);
|
||||
}
|
||||
|
||||
export function useSelectedIsPublic() {
|
||||
return useSelector(getSelectedConversationIsPublic);
|
||||
}
|
||||
|
||||
export function useSelectedIsPrivate() {
|
||||
return useSelector(getIsSelectedPrivate);
|
||||
}
|
||||
|
||||
export function useSelectedIsBlocked() {
|
||||
return useSelector(getIsSelectedBlocked);
|
||||
}
|
||||
|
||||
export function useSelectedIsActive() {
|
||||
return useSelector(getIsSelectedActive);
|
||||
}
|
||||
|
||||
export function useSelectedisNoteToSelf() {
|
||||
return useSelector(getIsSelectedNoteToSelf);
|
||||
}
|
||||
|
||||
export function useSelectedMembers() {
|
||||
return useSelector(getGroupMembers);
|
||||
}
|
||||
|
||||
export function useSelectedSubscriberCount() {
|
||||
return useSelector(getSelectedSubscriberCount);
|
||||
}
|
||||
|
||||
export function useSelectedNotificationSetting() {
|
||||
return useSelector(getCurrentNotificationSettingText);
|
||||
}
|
||||
|
||||
export function useSelectedIsKickedFromGroup() {
|
||||
return useSelector(
|
||||
(state: StateType) => Boolean(getSelectedConversation(state)?.isKickedFromGroup) || false
|
||||
);
|
||||
}
|
||||
|
||||
export function useSelectedIsLeft() {
|
||||
return useSelector((state: StateType) => Boolean(getSelectedConversation(state)?.left) || false);
|
||||
}
|
||||
|
||||
export function useSelectedNickname() {
|
||||
return useSelector((state: StateType) => getSelectedConversation(state)?.nickname);
|
||||
}
|
||||
|
||||
export function useSelectedDisplayNameInProfile() {
|
||||
return useSelector((state: StateType) => getSelectedConversation(state)?.displayNameInProfile);
|
||||
}
|
||||
|
||||
export function useSelectedWeAreAdmin() {
|
||||
return useSelector((state: StateType) => getSelectedConversation(state)?.weAreAdmin || false);
|
||||
}
|
|
@ -2,7 +2,7 @@ import { createSelector } from '@reduxjs/toolkit';
|
|||
import { StagedAttachmentType } from '../../components/conversation/composition/CompositionBox';
|
||||
import { StagedAttachmentsStateType } from '../ducks/stagedAttachments';
|
||||
import { StateType } from '../reducer';
|
||||
import { getSelectedConversationKey } from './conversations';
|
||||
import { getSelectedConversationKey } from './selectedConversation';
|
||||
|
||||
export const getStagedAttachmentsState = (state: StateType): StagedAttachmentsStateType =>
|
||||
state.stagedAttachments;
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { SessionConversation } from '../../components/conversation/SessionConversation';
|
||||
import { mapDispatchToProps } from '../actions';
|
||||
import { StateType } from '../reducer';
|
||||
import { getTheme } from '../selectors/theme';
|
||||
import { getHasOngoingCallWithFocusedConvo } from '../selectors/call';
|
||||
import {
|
||||
getIsSelectedConvoInitialLoadingInProgress,
|
||||
getLightBoxOptions,
|
||||
getSelectedConversation,
|
||||
getSelectedConversationKey,
|
||||
getSelectedMessageIds,
|
||||
getSortedMessagesOfSelectedConversation,
|
||||
isMessageDetailView,
|
||||
isRightPanelShowing,
|
||||
} from '../selectors/conversations';
|
||||
import { getOurNumber } from '../selectors/user';
|
||||
import {
|
||||
getSelectedConversation,
|
||||
getSelectedConversationKey,
|
||||
} from '../selectors/selectedConversation';
|
||||
import { getStagedAttachmentsForCurrentConversation } from '../selectors/stagedAttachments';
|
||||
import { getHasOngoingCallWithFocusedConvo } from '../selectors/call';
|
||||
import { SessionConversation } from '../../components/conversation/SessionConversation';
|
||||
import { getTheme } from '../selectors/theme';
|
||||
import { getOurNumber } from '../selectors/user';
|
||||
|
||||
const mapStateToProps = (state: StateType) => {
|
||||
return {
|
||||
|
|
Loading…
Reference in a new issue