Skip to content

Commit

Permalink
feat: Improvements for Delivered state and add tests (#17611)
Browse files Browse the repository at this point in the history
* runfix: Missing OutlineCheck Icon (#17609)

* feat: add dataUieValue for delivered state

* fix cr changes and add tests
  • Loading branch information
przemvs committed Jun 19, 2024
1 parent 74d04e5 commit 29dde79
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ import {QualifiedId} from '@wireapp/api-client/lib/user';
import cx from 'classnames';
import ko from 'knockout';

import {OutlineCheck} from '@wireapp/react-ui-kit';

import {DeliveredMessage} from 'Components/MessagesList/Message/DeliveredMessage';
import {ReadIndicator} from 'Components/MessagesList/Message/ReadIndicator';
import {Conversation} from 'src/script/entity/Conversation';
import {CompositeMessage} from 'src/script/entity/message/CompositeMessage';
Expand All @@ -33,8 +32,6 @@ import {useRelativeTimestamp} from 'src/script/hooks/useRelativeTimestamp';
import {StatusType} from 'src/script/message/StatusType';
import {useKoSubscribableChildren} from 'Util/ComponentUtil';
import {getMessageAriaLabel} from 'Util/conversationMessages';
import {t} from 'Util/LocalizerUtil';
import {checkIsMessageDelivered} from 'Util/util';

import {ContentAsset} from './asset';
import {deliveredMessageIndicator, messageBodyWrapper} from './ContentMessage.styles';
Expand Down Expand Up @@ -167,8 +164,6 @@ export const ContentMessageComponent = ({
}
};

const showDeliveredMessageIcon = checkIsMessageDelivered(isLastDeliveredMessage, readReceipts);

// Closing another ActionMenu on outside click
useClickOutside(messageRef, hideActionMenuVisibility);

Expand Down Expand Up @@ -269,11 +264,7 @@ export const ContentMessageComponent = ({
</div>

<div css={deliveredMessageIndicator}>
{showDeliveredMessageIcon && (
<div data-uie-name="status-message-read-receipt-delivered" title={t('conversationMessageDelivered')}>
<OutlineCheck />
</div>
)}
<DeliveredMessage isLastDeliveredMessage={isLastDeliveredMessage} readReceipts={readReceipts} />
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const messageBodyActions: CSSObject = {
minHeight: '32px',
minWidth: '40px',
position: 'absolute',
right: '16px',
right: '-40px',
top: '-34px',
userSelect: 'none',
'@media (max-width: @screen-md-min)': {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

import {render} from '@testing-library/react';

import {DeliveredMessage} from './DeliveredMessage';

import {withTheme} from '../../../../auth/util/test/TestUtil';
import {ReadReceipt} from '../../../../storage';

describe('DeliveredMessage', () => {
it('should render null if isLastDeliveredMessage is false', () => {
const {queryByTestId} = render(withTheme(<DeliveredMessage isLastDeliveredMessage={false} />));
expect(queryByTestId('status-message-read-receipt-delivered')).toBeNull();
});

it('should render null if readReceipts is not empty', () => {
const readReceipts = [{time: '123', userId: 'userId-1'}] as ReadReceipt[];
const {queryByTestId} = render(
withTheme(<DeliveredMessage isLastDeliveredMessage={true} readReceipts={readReceipts} />),
);
expect(queryByTestId('status-message-read-receipt-delivered')).toBeNull();
});

it('should render the delivered message icon if isLastDeliveredMessage is true and readReceipts is empty', () => {
const {queryByTestId} = render(withTheme(<DeliveredMessage isLastDeliveredMessage={true} readReceipts={[]} />));
expect(queryByTestId('status-message-read-receipt-delivered')).not.toBeNull();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

import {OutlineCheck} from '@wireapp/react-ui-kit';

import {t} from 'Util/LocalizerUtil';
import {formatTimeShort} from 'Util/TimeUtil';

import {ReadReceipt} from '../../../../storage';

interface DeliveredMessageProps {
isLastDeliveredMessage?: boolean;
readReceipts?: ReadReceipt[];
}

export const DeliveredMessage = ({isLastDeliveredMessage = false, readReceipts = []}: DeliveredMessageProps) => {
const readReceiptText = readReceipts.length ? formatTimeShort(readReceipts[0].time) : '';
const showDeliveredMessageIcon = isLastDeliveredMessage && readReceiptText === '';

if (!showDeliveredMessageIcon) {
return null;
}

return (
<div
data-uie-name="status-message-read-receipt-delivered"
title={t('conversationMessageDelivered')}
className="delivered-message-icon"
>
<OutlineCheck />
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

export * from './DeliveredMessage';
19 changes: 4 additions & 15 deletions src/script/components/MessagesList/Message/PingMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,8 @@

import cx from 'classnames';

import {OutlineCheck} from '@wireapp/react-ui-kit';

import {DeliveredMessage} from 'Components/MessagesList/Message/DeliveredMessage';
import {useKoSubscribableChildren} from 'Util/ComponentUtil';
import {t} from 'Util/LocalizerUtil';
import {checkIsMessageDelivered} from 'Util/util';

import {ReadReceiptStatus} from './ReadReceiptStatus';

Expand All @@ -46,17 +43,14 @@ const PingMessage = ({message, is1to1Conversation, isLastDeliveredMessage}: Ping
'readReceipts',
]);

const showDeliveredMessageIcon = checkIsMessageDelivered(isLastDeliveredMessage, readReceipts);

return (
<div className="message-header" data-uie-name="element-message-ping">
<div className="message-header-icon">
<div className={`icon-ping ${get_icon_classes}`} />
</div>
<div
className={cx('message-header-label', {
className={cx('message-header-label message-header-ping', {
'ephemeral-message-obfuscated': isObfuscated,
'message-header-ping-delivered': showDeliveredMessageIcon,
})}
title={ephemeral_caption}
data-uie-name="element-message-ping-text"
Expand All @@ -66,13 +60,8 @@ const PingMessage = ({message, is1to1Conversation, isLastDeliveredMessage}: Ping
<span className="ellipsis">{caption}</span>
</p>

{showDeliveredMessageIcon ? (
<div className="message-ping-delivered-icon" title={t('conversationMessageDelivered')}>
<OutlineCheck />
</div>
) : (
<ReadReceiptStatus message={message} is1to1Conversation={is1to1Conversation} />
)}
<DeliveredMessage isLastDeliveredMessage={isLastDeliveredMessage} readReceipts={readReceipts} />
<ReadReceiptStatus message={message} is1to1Conversation={is1to1Conversation} />
</div>
</div>
);
Expand Down
44 changes: 22 additions & 22 deletions src/script/components/MessagesList/Message/ReadReceiptStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,29 +46,29 @@ export const ReadReceiptStatus = ({message, is1to1Conversation, onClickDetails}:

const showEyeIndicator = !!readReceiptText;

if (!showEyeIndicator) {
return null;
}

return (
<>
{showEyeIndicator && (
<button
className={cx(
'message-status-read',
is1to1Conversation && 'message-status-read__one-on-one',
!!onClickDetails && 'message-status-read__clickable',
)}
data-uie-name="status-message-read-receipts"
aria-label={t('accessibility.messageDetailsReadReceipts', readReceiptText)}
{...(!is1to1Conversation && {
onClick: () => {
onClickDetails?.(message);
},
})}
>
<Icon.Read />
<span className="message-status-read__count" data-uie-name="status-message-read-receipt-count">
{readReceiptText}
</span>
</button>
<button
className={cx(
'message-status-read',
is1to1Conversation && 'message-status-read__one-on-one',
!!onClickDetails && 'message-status-read__clickable',
)}
</>
data-uie-name="status-message-read-receipts"
aria-label={t('accessibility.messageDetailsReadReceipts', readReceiptText)}
{...(!is1to1Conversation && {
onClick: () => {
onClickDetails?.(message);
},
})}
>
<Icon.Read />
<span className="message-status-read__count" data-uie-name="status-message-read-receipt-count">
{readReceiptText}
</span>
</button>
);
};
8 changes: 0 additions & 8 deletions src/script/util/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,11 @@ import {StatusCodes as HTTP_STATUS} from 'http-status-codes';

import {Runtime} from '@wireapp/commons';

import {formatTimeShort} from 'Util/TimeUtil';

import {isTabKey} from './KeyboardUtil';

import {Config} from '../Config';
import type {Conversation} from '../entity/Conversation';
import {AuthError} from '../error/AuthError';
import {ReadReceipt} from '../storage';

export const checkIndexedDb = (): Promise<void> => {
if (!Runtime.isSupportingIndexedDb()) {
Expand Down Expand Up @@ -319,8 +316,3 @@ export const removeAnimationsClass = (element: HTMLElement | null) => {
});
}
};

export const checkIsMessageDelivered = (isLastDeliveredMessage: boolean, readReceipts?: ReadReceipt[]) => {
const readReceiptText = readReceipts?.length ? formatTimeShort(readReceipts[0].time) : '';
return isLastDeliveredMessage && readReceiptText === '';
};
5 changes: 3 additions & 2 deletions src/style/content/conversation/message-list.less
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@
}
}

.message-ping-delivered-icon {
.message-ping-delivered-icon,
.message-header-ping .delivered-message-icon {
display: flex;
width: var(--delivered-state-width);
align-items: center;
Expand All @@ -191,7 +192,7 @@
font-weight: @font-weight-regular;
white-space: normal;

&.message-header-ping-delivered {
&:has(.delivered-message-icon) {
width: 100%;
justify-content: space-between;
}
Expand Down

0 comments on commit 29dde79

Please sign in to comment.