feat: added notice banner component
show notice when conversation is in legacy mode, extracted some UI components from the ConversationHeader, updated featureReleaseTimestamppull/2660/head
parent
93005d32d8
commit
4dbbada728
@ -0,0 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { Flex } from './basic/Flex';
|
||||||
|
|
||||||
|
const StyledNoticeBanner = styled(Flex)`
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: var(--background-primary-color);
|
||||||
|
min-height: 30px;
|
||||||
|
font-size: var(--font-size-lg);
|
||||||
|
padding: 0 var(--margins-sm);
|
||||||
|
text-align: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type NoticeBannerProps = {
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NoticeBanner = (props: NoticeBannerProps) => {
|
||||||
|
const { text } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledNoticeBanner
|
||||||
|
container={true}
|
||||||
|
flexDirection={'row'}
|
||||||
|
justifyContent={'center'}
|
||||||
|
alignItems={'center'}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</StyledNoticeBanner>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,283 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { Avatar, AvatarSize } from '../avatar/Avatar';
|
|
||||||
|
|
||||||
import { contextMenu } from 'react-contexify';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import { ConversationNotificationSettingType } from '../../models/conversationAttributes';
|
|
||||||
import {
|
|
||||||
getIsSelectedActive,
|
|
||||||
getIsSelectedBlocked,
|
|
||||||
getIsSelectedNoteToSelf,
|
|
||||||
getIsSelectedPrivate,
|
|
||||||
getSelectedConversationIsPublic,
|
|
||||||
getSelectedConversationKey,
|
|
||||||
getSelectedMessageIds,
|
|
||||||
isMessageDetailView,
|
|
||||||
isMessageSelectionMode,
|
|
||||||
} from '../../state/selectors/conversations';
|
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
|
||||||
|
|
||||||
import {
|
|
||||||
deleteMessagesById,
|
|
||||||
deleteMessagesByIdForEveryone,
|
|
||||||
} from '../../interactions/conversations/unsendingInteractions';
|
|
||||||
import {
|
|
||||||
closeMessageDetailsView,
|
|
||||||
openRightPanel,
|
|
||||||
resetSelectedMessageIds,
|
|
||||||
} from '../../state/ducks/conversations';
|
|
||||||
import { callRecipient } from '../../interactions/conversationInteractions';
|
|
||||||
import { getHasIncomingCall, getHasOngoingCall } from '../../state/selectors/call';
|
|
||||||
import { useIsRequest } from '../../hooks/useParamSelector';
|
|
||||||
import {
|
|
||||||
SessionButton,
|
|
||||||
SessionButtonColor,
|
|
||||||
SessionButtonShape,
|
|
||||||
SessionButtonType,
|
|
||||||
} from '../basic/SessionButton';
|
|
||||||
import { SessionIconButton } from '../icon';
|
|
||||||
import { ConversationHeaderMenu } from '../menu/ConversationHeaderMenu';
|
|
||||||
import { Flex } from '../basic/Flex';
|
|
||||||
import { ConversationHeaderTitle } from './ConversationHeaderTitle';
|
|
||||||
|
|
||||||
export interface TimerOption {
|
|
||||||
name: string;
|
|
||||||
value: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ConversationHeaderProps = {
|
|
||||||
conversationKey: string;
|
|
||||||
name?: string;
|
|
||||||
|
|
||||||
profileName?: string;
|
|
||||||
avatarPath: string | null;
|
|
||||||
|
|
||||||
isMe: boolean;
|
|
||||||
isGroup: boolean;
|
|
||||||
isPrivate: boolean;
|
|
||||||
isPublic: boolean;
|
|
||||||
weAreAdmin: boolean;
|
|
||||||
|
|
||||||
// We might not always have the full list of members,
|
|
||||||
// e.g. for open groups where we could have thousands
|
|
||||||
// of members. We'll keep this for now (for closed chats)
|
|
||||||
members: Array<any>;
|
|
||||||
|
|
||||||
// not equal members.length (see above)
|
|
||||||
subscriberCount?: number;
|
|
||||||
|
|
||||||
expirationSettingName?: string;
|
|
||||||
currentNotificationSetting: ConversationNotificationSettingType;
|
|
||||||
hasNickname: boolean;
|
|
||||||
|
|
||||||
isBlocked: boolean;
|
|
||||||
|
|
||||||
isKickedFromGroup: boolean;
|
|
||||||
left: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const SelectionOverlay = () => {
|
|
||||||
const selectedMessageIds = useSelector(getSelectedMessageIds);
|
|
||||||
const selectedConversationKey = useSelector(getSelectedConversationKey);
|
|
||||||
const isPublic = useSelector(getSelectedConversationIsPublic);
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
|
|
||||||
const { i18n } = window;
|
|
||||||
|
|
||||||
function onCloseOverlay() {
|
|
||||||
dispatch(resetSelectedMessageIds());
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDeleteSelectedMessages() {
|
|
||||||
if (selectedConversationKey) {
|
|
||||||
void deleteMessagesById(selectedMessageIds, selectedConversationKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function onDeleteSelectedMessagesForEveryone() {
|
|
||||||
if (selectedConversationKey) {
|
|
||||||
void deleteMessagesByIdForEveryone(selectedMessageIds, selectedConversationKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const isOnlyServerDeletable = isPublic;
|
|
||||||
const deleteMessageButtonText = i18n('delete');
|
|
||||||
const deleteForEveryoneMessageButtonText = i18n('deleteForEveryone');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="message-selection-overlay">
|
|
||||||
<div className="close-button">
|
|
||||||
<SessionIconButton iconType="exit" iconSize="medium" onClick={onCloseOverlay} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="button-group">
|
|
||||||
{!isOnlyServerDeletable && (
|
|
||||||
<SessionButton
|
|
||||||
buttonColor={SessionButtonColor.Danger}
|
|
||||||
buttonShape={SessionButtonShape.Square}
|
|
||||||
buttonType={SessionButtonType.Solid}
|
|
||||||
text={deleteMessageButtonText}
|
|
||||||
onClick={onDeleteSelectedMessages}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<SessionButton
|
|
||||||
buttonColor={SessionButtonColor.Danger}
|
|
||||||
buttonShape={SessionButtonShape.Square}
|
|
||||||
buttonType={SessionButtonType.Solid}
|
|
||||||
text={deleteForEveryoneMessageButtonText}
|
|
||||||
onClick={onDeleteSelectedMessagesForEveryone}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TripleDotContainer = styled.div`
|
|
||||||
user-select: none;
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const TripleDotsMenu = (props: { triggerId: string; showBackButton: boolean }) => {
|
|
||||||
const { showBackButton } = props;
|
|
||||||
if (showBackButton) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<TripleDotContainer
|
|
||||||
role="button"
|
|
||||||
onClick={(e: any) => {
|
|
||||||
contextMenu.show({
|
|
||||||
id: props.triggerId,
|
|
||||||
event: e,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
data-testid="three-dots-conversation-options"
|
|
||||||
>
|
|
||||||
<SessionIconButton iconType="ellipses" iconSize="medium" />
|
|
||||||
</TripleDotContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const AvatarHeader = (props: {
|
|
||||||
pubkey: string;
|
|
||||||
showBackButton: boolean;
|
|
||||||
onAvatarClick?: (pubkey: string) => void;
|
|
||||||
}) => {
|
|
||||||
const { pubkey, onAvatarClick, showBackButton } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span className="module-conversation-header__avatar">
|
|
||||||
<Avatar
|
|
||||||
size={AvatarSize.S}
|
|
||||||
onAvatarClick={() => {
|
|
||||||
// do not allow right panel to appear if another button is shown on the SessionConversation
|
|
||||||
if (onAvatarClick && !showBackButton) {
|
|
||||||
onAvatarClick(pubkey);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
pubkey={pubkey}
|
|
||||||
dataTestId="conversation-options-avatar"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const BackButton = (props: { onGoBack: () => void; showBackButton: boolean }) => {
|
|
||||||
const { onGoBack, showBackButton } = props;
|
|
||||||
if (!showBackButton) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SessionIconButton
|
|
||||||
iconType="chevron"
|
|
||||||
iconSize="large"
|
|
||||||
iconRotation={90}
|
|
||||||
onClick={onGoBack}
|
|
||||||
dataTestId="back-button-message-details"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const CallButton = () => {
|
|
||||||
const isPrivate = useSelector(getIsSelectedPrivate);
|
|
||||||
const isBlocked = useSelector(getIsSelectedBlocked);
|
|
||||||
const activeAt = useSelector(getIsSelectedActive);
|
|
||||||
const isMe = useSelector(getIsSelectedNoteToSelf);
|
|
||||||
const selectedConvoKey = useSelector(getSelectedConversationKey);
|
|
||||||
|
|
||||||
const hasIncomingCall = useSelector(getHasIncomingCall);
|
|
||||||
const hasOngoingCall = useSelector(getHasOngoingCall);
|
|
||||||
const canCall = !(hasIncomingCall || hasOngoingCall);
|
|
||||||
|
|
||||||
const isRequest = useIsRequest(selectedConvoKey);
|
|
||||||
|
|
||||||
if (!isPrivate || isMe || !selectedConvoKey || isBlocked || !activeAt || isRequest) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SessionIconButton
|
|
||||||
iconType="phone"
|
|
||||||
iconSize="large"
|
|
||||||
iconPadding="2px"
|
|
||||||
// negative margin to keep conversation header title centered
|
|
||||||
margin="0 10px 0 -32px"
|
|
||||||
onClick={() => {
|
|
||||||
void callRecipient(selectedConvoKey, canCall);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ConversationHeaderWithDetails = () => {
|
|
||||||
const isSelectionMode = useSelector(isMessageSelectionMode);
|
|
||||||
const isMessageDetailOpened = useSelector(isMessageDetailView);
|
|
||||||
const selectedConvoKey = useSelector(getSelectedConversationKey);
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
|
|
||||||
if (!selectedConvoKey) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const triggerId = 'conversation-header';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="module-conversation-header">
|
|
||||||
<div className="conversation-header--items-wrapper">
|
|
||||||
<BackButton
|
|
||||||
onGoBack={() => {
|
|
||||||
dispatch(closeMessageDetailsView());
|
|
||||||
}}
|
|
||||||
showBackButton={isMessageDetailOpened}
|
|
||||||
/>
|
|
||||||
<TripleDotsMenu triggerId={triggerId} showBackButton={isMessageDetailOpened} />
|
|
||||||
<ConversationHeaderTitle />
|
|
||||||
|
|
||||||
{!isSelectionMode && (
|
|
||||||
<Flex
|
|
||||||
container={true}
|
|
||||||
flexDirection="row"
|
|
||||||
alignItems="center"
|
|
||||||
flexGrow={0}
|
|
||||||
flexShrink={0}
|
|
||||||
>
|
|
||||||
<CallButton />
|
|
||||||
<AvatarHeader
|
|
||||||
onAvatarClick={() => {
|
|
||||||
dispatch(openRightPanel());
|
|
||||||
}}
|
|
||||||
pubkey={selectedConvoKey}
|
|
||||||
showBackButton={isMessageDetailOpened}
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<ConversationHeaderMenu triggerId={triggerId} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{isSelectionMode && <SelectionOverlay />}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { ConversationNotificationSettingType } from '../../../models/conversationAttributes';
|
||||||
|
import {
|
||||||
|
getSelectedConversationKey,
|
||||||
|
isMessageDetailView,
|
||||||
|
isMessageSelectionMode,
|
||||||
|
} from '../../../state/selectors/conversations';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
import { closeMessageDetailsView, openRightPanel } from '../../../state/ducks/conversations';
|
||||||
|
|
||||||
|
import { ConversationHeaderMenu } from '../../menu/ConversationHeaderMenu';
|
||||||
|
import { Flex } from '../../basic/Flex';
|
||||||
|
import { ConversationHeaderTitle } from './ConversationHeaderTitle';
|
||||||
|
import { AvatarHeader, BackButton, CallButton, TripleDotsMenu } from './ConversationHeaderItems';
|
||||||
|
import { SelectionOverlay } from './ConversationHeaderSelectionOverlay';
|
||||||
|
|
||||||
|
export interface TimerOption {
|
||||||
|
name: string;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ConversationHeaderProps = {
|
||||||
|
conversationKey: string;
|
||||||
|
name?: string;
|
||||||
|
|
||||||
|
profileName?: string;
|
||||||
|
avatarPath: string | null;
|
||||||
|
|
||||||
|
isMe: boolean;
|
||||||
|
isGroup: boolean;
|
||||||
|
isPrivate: boolean;
|
||||||
|
isPublic: boolean;
|
||||||
|
weAreAdmin: boolean;
|
||||||
|
|
||||||
|
// We might not always have the full list of members,
|
||||||
|
// e.g. for open groups where we could have thousands
|
||||||
|
// of members. We'll keep this for now (for closed chats)
|
||||||
|
members: Array<any>;
|
||||||
|
|
||||||
|
// not equal members.length (see above)
|
||||||
|
subscriberCount?: number;
|
||||||
|
|
||||||
|
expirationSettingName?: string;
|
||||||
|
currentNotificationSetting: ConversationNotificationSettingType;
|
||||||
|
hasNickname: boolean;
|
||||||
|
|
||||||
|
isBlocked: boolean;
|
||||||
|
|
||||||
|
isKickedFromGroup: boolean;
|
||||||
|
left: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ConversationHeaderWithDetails = () => {
|
||||||
|
const isSelectionMode = useSelector(isMessageSelectionMode);
|
||||||
|
const isMessageDetailOpened = useSelector(isMessageDetailView);
|
||||||
|
const selectedConvoKey = useSelector(getSelectedConversationKey);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
if (!selectedConvoKey) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const triggerId = 'conversation-header';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="module-conversation-header">
|
||||||
|
<div className="conversation-header--items-wrapper">
|
||||||
|
<BackButton
|
||||||
|
onGoBack={() => {
|
||||||
|
dispatch(closeMessageDetailsView());
|
||||||
|
}}
|
||||||
|
showBackButton={isMessageDetailOpened}
|
||||||
|
/>
|
||||||
|
<TripleDotsMenu triggerId={triggerId} showBackButton={isMessageDetailOpened} />
|
||||||
|
<ConversationHeaderTitle />
|
||||||
|
|
||||||
|
{!isSelectionMode && (
|
||||||
|
<Flex
|
||||||
|
container={true}
|
||||||
|
flexDirection="row"
|
||||||
|
alignItems="center"
|
||||||
|
flexGrow={0}
|
||||||
|
flexShrink={0}
|
||||||
|
>
|
||||||
|
<CallButton />
|
||||||
|
<AvatarHeader
|
||||||
|
onAvatarClick={() => {
|
||||||
|
dispatch(openRightPanel());
|
||||||
|
}}
|
||||||
|
pubkey={selectedConvoKey}
|
||||||
|
showBackButton={isMessageDetailOpened}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<ConversationHeaderMenu triggerId={triggerId} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{isSelectionMode && <SelectionOverlay />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { contextMenu } from 'react-contexify';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { useIsRequest } from '../../../hooks/useParamSelector';
|
||||||
|
import { callRecipient } from '../../../interactions/conversationInteractions';
|
||||||
|
import { getHasIncomingCall, getHasOngoingCall } from '../../../state/selectors/call';
|
||||||
|
import {
|
||||||
|
getIsSelectedActive,
|
||||||
|
getIsSelectedBlocked,
|
||||||
|
getIsSelectedNoteToSelf,
|
||||||
|
getIsSelectedPrivate,
|
||||||
|
getSelectedConversationKey,
|
||||||
|
} from '../../../state/selectors/conversations';
|
||||||
|
import { Avatar, AvatarSize } from '../../avatar/Avatar';
|
||||||
|
import { SessionIconButton } from '../../icon';
|
||||||
|
|
||||||
|
const TripleDotContainer = styled.div`
|
||||||
|
user-select: none;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TripleDotsMenu = (props: { triggerId: string; showBackButton: boolean }) => {
|
||||||
|
const { showBackButton } = props;
|
||||||
|
if (showBackButton) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TripleDotContainer
|
||||||
|
role="button"
|
||||||
|
onClick={(e: any) => {
|
||||||
|
contextMenu.show({
|
||||||
|
id: props.triggerId,
|
||||||
|
event: e,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
data-testid="three-dots-conversation-options"
|
||||||
|
>
|
||||||
|
<SessionIconButton iconType="ellipses" iconSize="medium" />
|
||||||
|
</TripleDotContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AvatarHeader = (props: {
|
||||||
|
pubkey: string;
|
||||||
|
showBackButton: boolean;
|
||||||
|
onAvatarClick?: (pubkey: string) => void;
|
||||||
|
}) => {
|
||||||
|
const { pubkey, onAvatarClick, showBackButton } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className="module-conversation-header__avatar">
|
||||||
|
<Avatar
|
||||||
|
size={AvatarSize.S}
|
||||||
|
onAvatarClick={() => {
|
||||||
|
// do not allow right panel to appear if another button is shown on the SessionConversation
|
||||||
|
if (onAvatarClick && !showBackButton) {
|
||||||
|
onAvatarClick(pubkey);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
pubkey={pubkey}
|
||||||
|
dataTestId="conversation-options-avatar"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BackButton = (props: { onGoBack: () => void; showBackButton: boolean }) => {
|
||||||
|
const { onGoBack, showBackButton } = props;
|
||||||
|
if (!showBackButton) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SessionIconButton
|
||||||
|
iconType="chevron"
|
||||||
|
iconSize="large"
|
||||||
|
iconRotation={90}
|
||||||
|
onClick={onGoBack}
|
||||||
|
dataTestId="back-button-message-details"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CallButton = () => {
|
||||||
|
const isPrivate = useSelector(getIsSelectedPrivate);
|
||||||
|
const isBlocked = useSelector(getIsSelectedBlocked);
|
||||||
|
const activeAt = useSelector(getIsSelectedActive);
|
||||||
|
const isMe = useSelector(getIsSelectedNoteToSelf);
|
||||||
|
const selectedConvoKey = useSelector(getSelectedConversationKey);
|
||||||
|
|
||||||
|
const hasIncomingCall = useSelector(getHasIncomingCall);
|
||||||
|
const hasOngoingCall = useSelector(getHasOngoingCall);
|
||||||
|
const canCall = !(hasIncomingCall || hasOngoingCall);
|
||||||
|
|
||||||
|
const isRequest = useIsRequest(selectedConvoKey);
|
||||||
|
|
||||||
|
if (!isPrivate || isMe || !selectedConvoKey || isBlocked || !activeAt || isRequest) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SessionIconButton
|
||||||
|
iconType="phone"
|
||||||
|
iconSize="large"
|
||||||
|
iconPadding="2px"
|
||||||
|
// negative margin to keep conversation header title centered
|
||||||
|
margin="0 10px 0 -32px"
|
||||||
|
onClick={() => {
|
||||||
|
void callRecipient(selectedConvoKey, canCall);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import {
|
||||||
|
deleteMessagesById,
|
||||||
|
deleteMessagesByIdForEveryone,
|
||||||
|
} from '../../../interactions/conversations/unsendingInteractions';
|
||||||
|
import { resetSelectedMessageIds } from '../../../state/ducks/conversations';
|
||||||
|
import {
|
||||||
|
getSelectedConversationIsPublic,
|
||||||
|
getSelectedConversationKey,
|
||||||
|
getSelectedMessageIds,
|
||||||
|
} from '../../../state/selectors/conversations';
|
||||||
|
import {
|
||||||
|
SessionButton,
|
||||||
|
SessionButtonColor,
|
||||||
|
SessionButtonShape,
|
||||||
|
SessionButtonType,
|
||||||
|
} from '../../basic/SessionButton';
|
||||||
|
import { SessionIconButton } from '../../icon';
|
||||||
|
|
||||||
|
export const SelectionOverlay = () => {
|
||||||
|
const selectedMessageIds = useSelector(getSelectedMessageIds);
|
||||||
|
const selectedConversationKey = useSelector(getSelectedConversationKey);
|
||||||
|
const isPublic = useSelector(getSelectedConversationIsPublic);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const { i18n } = window;
|
||||||
|
|
||||||
|
function onCloseOverlay() {
|
||||||
|
dispatch(resetSelectedMessageIds());
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDeleteSelectedMessages() {
|
||||||
|
if (selectedConversationKey) {
|
||||||
|
void deleteMessagesById(selectedMessageIds, selectedConversationKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function onDeleteSelectedMessagesForEveryone() {
|
||||||
|
if (selectedConversationKey) {
|
||||||
|
void deleteMessagesByIdForEveryone(selectedMessageIds, selectedConversationKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isOnlyServerDeletable = isPublic;
|
||||||
|
const deleteMessageButtonText = i18n('delete');
|
||||||
|
const deleteForEveryoneMessageButtonText = i18n('deleteForEveryone');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="message-selection-overlay">
|
||||||
|
<div className="close-button">
|
||||||
|
<SessionIconButton iconType="exit" iconSize="medium" onClick={onCloseOverlay} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="button-group">
|
||||||
|
{!isOnlyServerDeletable && (
|
||||||
|
<SessionButton
|
||||||
|
buttonColor={SessionButtonColor.Danger}
|
||||||
|
buttonShape={SessionButtonShape.Square}
|
||||||
|
buttonType={SessionButtonType.Solid}
|
||||||
|
text={deleteMessageButtonText}
|
||||||
|
onClick={onDeleteSelectedMessages}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<SessionButton
|
||||||
|
buttonColor={SessionButtonColor.Danger}
|
||||||
|
buttonShape={SessionButtonShape.Square}
|
||||||
|
buttonType={SessionButtonType.Solid}
|
||||||
|
text={deleteForEveryoneMessageButtonText}
|
||||||
|
onClick={onDeleteSelectedMessagesForEveryone}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,21 +1,21 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import styled, { CSSProperties } from 'styled-components';
|
import styled, { CSSProperties } from 'styled-components';
|
||||||
import { useConversationUsername } from '../../hooks/useParamSelector';
|
import { useConversationUsername } from '../../../hooks/useParamSelector';
|
||||||
import { ConversationNotificationSettingType } from '../../models/conversationAttributes';
|
import { ConversationNotificationSettingType } from '../../../models/conversationAttributes';
|
||||||
import { closeRightPanel, openRightPanel } from '../../state/ducks/conversations';
|
import { closeRightPanel, openRightPanel } from '../../../state/ducks/conversations';
|
||||||
import { setRightOverlayMode } from '../../state/ducks/section';
|
import { setRightOverlayMode } from '../../../state/ducks/section';
|
||||||
import {
|
import {
|
||||||
getConversationHeaderTitleProps,
|
getConversationHeaderTitleProps,
|
||||||
getCurrentNotificationSettingText,
|
getCurrentNotificationSettingText,
|
||||||
isRightPanelShowing,
|
isRightPanelShowing,
|
||||||
} from '../../state/selectors/conversations';
|
} from '../../../state/selectors/conversations';
|
||||||
import {
|
import {
|
||||||
DisappearingMessageConversationType,
|
DisappearingMessageConversationType,
|
||||||
ExpirationTimerOptions,
|
ExpirationTimerOptions,
|
||||||
} from '../../util/expiringMessages';
|
} from '../../../util/expiringMessages';
|
||||||
import { Flex } from '../basic/Flex';
|
import { Flex } from '../../basic/Flex';
|
||||||
import { SessionIconButton } from '../icon';
|
import { SessionIconButton } from '../../icon';
|
||||||
|
|
||||||
export const StyledSubtitleContainer = styled.div`
|
export const StyledSubtitleContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
Loading…
Reference in New Issue