Merge branch 'feature/ses-145/leave-conversation-update' into userconfig_disappearingmessage
commit
24887dd05b
@ -0,0 +1,82 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { useIsPrivate, useIsPublic } from '../../../../hooks/useParamSelector';
|
||||||
|
import {
|
||||||
|
ConversationInteractionStatus,
|
||||||
|
ConversationInteractionType,
|
||||||
|
} from '../../../../interactions/conversationInteractions';
|
||||||
|
import { PropsForInteractionNotification } from '../../../../state/ducks/conversations';
|
||||||
|
import { assertUnreachable } from '../../../../types/sqlSharedTypes';
|
||||||
|
import { Flex } from '../../../basic/Flex';
|
||||||
|
import { ReadableMessage } from './ReadableMessage';
|
||||||
|
|
||||||
|
const StyledFailText = styled.div`
|
||||||
|
color: var(--danger-color);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const InteractionNotification = (props: PropsForInteractionNotification) => {
|
||||||
|
const { notificationType, convoId, messageId, receivedAt, isUnread } = props;
|
||||||
|
|
||||||
|
const { interactionStatus, interactionType } = notificationType;
|
||||||
|
|
||||||
|
const isGroup = !useIsPrivate(convoId);
|
||||||
|
const isCommunity = useIsPublic(convoId);
|
||||||
|
|
||||||
|
// NOTE at this time we don't show visible control messages in communities, that might change in future...
|
||||||
|
if (isCommunity) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interactionStatus !== ConversationInteractionStatus.Error) {
|
||||||
|
// NOTE For now we only show interaction errors in the message history
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let text = '';
|
||||||
|
|
||||||
|
switch (interactionType) {
|
||||||
|
case ConversationInteractionType.Hide:
|
||||||
|
text = window.i18n('hideConversationFailedPleaseTryAgain');
|
||||||
|
break;
|
||||||
|
case ConversationInteractionType.Leave:
|
||||||
|
text = isCommunity
|
||||||
|
? window.i18n('leaveCommunityFailedPleaseTryAgain')
|
||||||
|
: isGroup
|
||||||
|
? window.i18n('leaveGroupFailedPleaseTryAgain')
|
||||||
|
: window.i18n('deleteConversationFailedPleaseTryAgain');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assertUnreachable(
|
||||||
|
interactionType,
|
||||||
|
`InteractionErrorMessage: Missing case error "${interactionType}"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEmpty(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ReadableMessage
|
||||||
|
messageId={messageId}
|
||||||
|
receivedAt={receivedAt}
|
||||||
|
isUnread={isUnread}
|
||||||
|
key={`readable-message-${messageId}`}
|
||||||
|
dataTestId="interaction-notification"
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
id={`convo-interaction-${convoId}`}
|
||||||
|
container={true}
|
||||||
|
flexDirection="row"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
margin={'var(--margins-md) var(--margins-sm)'}
|
||||||
|
data-testid="control-message"
|
||||||
|
>
|
||||||
|
<StyledFailText>{text}</StyledFailText>
|
||||||
|
</Flex>
|
||||||
|
</ReadableMessage>
|
||||||
|
);
|
||||||
|
};
|
@ -1,61 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { useDispatch } from 'react-redux';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import { getConversationController } from '../../session/conversations';
|
|
||||||
import { adminLeaveClosedGroup } from '../../state/ducks/modalDialog';
|
|
||||||
import { SessionWrapperModal } from '../SessionWrapperModal';
|
|
||||||
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
|
|
||||||
import { SpacerLG } from '../basic/Text';
|
|
||||||
import { SessionSpinner } from '../basic/SessionSpinner';
|
|
||||||
|
|
||||||
const StyledWarning = styled.p`
|
|
||||||
max-width: 500px;
|
|
||||||
line-height: 1.3333;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const AdminLeaveClosedGroupDialog = (props: { conversationId: string }) => {
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const convo = getConversationController().get(props.conversationId);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const titleText = `${window.i18n('leaveGroup')} ${convo?.getRealSessionUsername() || ''}`;
|
|
||||||
|
|
||||||
const closeDialog = () => {
|
|
||||||
dispatch(adminLeaveClosedGroup(null));
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClickOK = async () => {
|
|
||||||
if (loading) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setLoading(true);
|
|
||||||
// we know want to delete a closed group right after we've left it, so we can call the deleteContact which takes care of it all
|
|
||||||
await getConversationController().deleteClosedGroup(props.conversationId, {
|
|
||||||
fromSyncMessage: false,
|
|
||||||
sendLeaveMessage: true,
|
|
||||||
});
|
|
||||||
setLoading(false);
|
|
||||||
closeDialog();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SessionWrapperModal title={titleText} onClose={closeDialog}>
|
|
||||||
<SpacerLG />
|
|
||||||
<StyledWarning>{window.i18n('leaveGroupConfirmationAdmin')}</StyledWarning>
|
|
||||||
<SessionSpinner loading={loading} />
|
|
||||||
|
|
||||||
<div className="session-modal__button-group">
|
|
||||||
<SessionButton
|
|
||||||
text={window.i18n('leaveAndRemoveForEveryone')}
|
|
||||||
buttonColor={SessionButtonColor.Danger}
|
|
||||||
buttonType={SessionButtonType.Simple}
|
|
||||||
onClick={onClickOK}
|
|
||||||
/>
|
|
||||||
<SessionButton
|
|
||||||
text={window.i18n('cancel')}
|
|
||||||
buttonType={SessionButtonType.Simple}
|
|
||||||
onClick={closeDialog}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</SessionWrapperModal>
|
|
||||||
);
|
|
||||||
};
|
|
@ -0,0 +1,105 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
|
||||||
|
import { useIsPrivate, useIsPublic } from '../../../hooks/useParamSelector';
|
||||||
|
import { MessageBody } from '../../conversation/message/message-content/MessageBody';
|
||||||
|
import { assertUnreachable } from '../../../types/sqlSharedTypes';
|
||||||
|
import {
|
||||||
|
ConversationInteractionStatus,
|
||||||
|
ConversationInteractionType,
|
||||||
|
} from '../../../interactions/conversationInteractions';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { getConversationController } from '../../../session/conversations';
|
||||||
|
import { LastMessageType } from '../../../state/ducks/conversations';
|
||||||
|
|
||||||
|
const StyledInteractionItemText = styled.div<{ isError: boolean }>`
|
||||||
|
${props => props.isError && 'color: var(--danger-color) !important;'}
|
||||||
|
`;
|
||||||
|
|
||||||
|
type InteractionItemProps = {
|
||||||
|
conversationId: string;
|
||||||
|
lastMessage: LastMessageType | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InteractionItem = (props: InteractionItemProps) => {
|
||||||
|
const { conversationId, lastMessage } = props;
|
||||||
|
const isGroup = !useIsPrivate(conversationId);
|
||||||
|
const isCommunity = useIsPublic(conversationId);
|
||||||
|
|
||||||
|
if (!lastMessage) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { interactionType, interactionStatus } = lastMessage;
|
||||||
|
|
||||||
|
if (!interactionType || !interactionStatus) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [storedLastMessageText, setStoredLastMessageText] = useState(lastMessage?.text);
|
||||||
|
const [storedLastMessageInteractionStatus, setStoredLastMessageInteractionStatus] = useState(
|
||||||
|
lastMessage?.interactionStatus
|
||||||
|
);
|
||||||
|
|
||||||
|
// NOTE we want to reset the interaction state when the last message changes
|
||||||
|
useEffect(() => {
|
||||||
|
if (conversationId) {
|
||||||
|
const convo = getConversationController().get(conversationId);
|
||||||
|
|
||||||
|
if (storedLastMessageInteractionStatus !== convo.get('lastMessageInteractionStatus')) {
|
||||||
|
setStoredLastMessageInteractionStatus(convo.get('lastMessageInteractionStatus'));
|
||||||
|
setStoredLastMessageText(convo.get('lastMessage'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [conversationId]);
|
||||||
|
|
||||||
|
let text = storedLastMessageText || '';
|
||||||
|
let errorText = '';
|
||||||
|
|
||||||
|
switch (interactionType) {
|
||||||
|
case ConversationInteractionType.Hide:
|
||||||
|
errorText = window.i18n('hideConversationFailed');
|
||||||
|
text =
|
||||||
|
interactionStatus === ConversationInteractionStatus.Error
|
||||||
|
? errorText
|
||||||
|
: interactionStatus === ConversationInteractionStatus.Start ||
|
||||||
|
interactionStatus === ConversationInteractionStatus.Loading
|
||||||
|
? window.i18n('hiding')
|
||||||
|
: text;
|
||||||
|
break;
|
||||||
|
case ConversationInteractionType.Leave:
|
||||||
|
errorText = isCommunity
|
||||||
|
? window.i18n('leaveCommunityFailed')
|
||||||
|
: isGroup
|
||||||
|
? window.i18n('leaveGroupFailed')
|
||||||
|
: window.i18n('deleteConversationFailed');
|
||||||
|
text =
|
||||||
|
interactionStatus === ConversationInteractionStatus.Error
|
||||||
|
? errorText
|
||||||
|
: interactionStatus === ConversationInteractionStatus.Start ||
|
||||||
|
interactionStatus === ConversationInteractionStatus.Loading
|
||||||
|
? window.i18n('leaving')
|
||||||
|
: text;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assertUnreachable(
|
||||||
|
interactionType,
|
||||||
|
`InteractionItem: Missing case error "${interactionType}"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEmpty(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="module-conversation-list-item__message">
|
||||||
|
<StyledInteractionItemText
|
||||||
|
className="module-conversation-list-item__message__text"
|
||||||
|
isError={Boolean(interactionStatus === ConversationInteractionStatus.Error)}
|
||||||
|
>
|
||||||
|
<MessageBody text={text} disableJumbomoji={true} disableLinks={true} isGroup={isGroup} />
|
||||||
|
</StyledInteractionItemText>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue