Adds an edit message entry point in message details screen

This commit is contained in:
Josh Perez 2023-06-15 11:34:20 -07:00 committed by GitHub
parent 008cb99ab9
commit 94cd764107
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 168 additions and 122 deletions

View file

@ -5150,6 +5150,10 @@
"messageformat": "Disappears in", "messageformat": "Disappears in",
"description": "In the message details screen, shown as a label of how long it will be before the message disappears" "description": "In the message details screen, shown as a label of how long it will be before the message disappears"
}, },
"icu:MessageDetail__view-edits": {
"messageformat": "View edit history",
"description": "Link to view a message's edit history"
},
"icu:ProfileEditor--about": { "icu:ProfileEditor--about": {
"messageformat": "About", "messageformat": "About",
"description": "Default text for about field" "description": "Default text for about field"

View file

@ -424,6 +424,7 @@
} }
&__attachment img { &__attachment img {
border-radius: 4px;
height: 18px; height: 18px;
position: absolute; position: absolute;
inset-inline-end: 8px; inset-inline-end: 8px;

View file

@ -253,6 +253,12 @@
} }
} }
&--edit {
&::after {
@include details-icon('../images/icons/v3/edit/edit.svg');
}
}
&--down { &--down {
border-radius: 18px; border-radius: 18px;
@include light-theme { @include light-theme {

View file

@ -3,7 +3,16 @@
.EditHistoryMessagesModal { .EditHistoryMessagesModal {
&__divider { &__divider {
border-style: solid;
margin-block: 24px; margin-block: 24px;
@include light-theme {
border-color: $color-gray-15;
}
@include dark-theme {
border-color: $color-gray-75;
}
} }
&__title { &__title {

View file

@ -39,18 +39,6 @@
} }
} }
.module-message-detail__contact-container {
border-top: 1px solid $color-gray-15;
margin-top: 36px;
@include light-theme {
border-top-color: $color-gray-15;
}
@include dark-theme {
border-top-color: $color-gray-75;
}
}
.module-message-detail__contact-group__header { .module-message-detail__contact-group__header {
@include font-body-1-bold; @include font-body-1-bold;
align-items: center; align-items: center;

View file

@ -27,6 +27,12 @@ import { formatDateTimeLong } from '../../util/timestamp';
import { DurationInSeconds } from '../../util/durations'; import { DurationInSeconds } from '../../util/durations';
import { format as formatRelativeTime } from '../../util/expirationTimer'; import { format as formatRelativeTime } from '../../util/expirationTimer';
import { missingCaseError } from '../../util/missingCaseError'; import { missingCaseError } from '../../util/missingCaseError';
import { PanelRow } from './conversation-details/PanelRow';
import { PanelSection } from './conversation-details/PanelSection';
import {
ConversationDetailsIcon,
IconType,
} from './conversation-details/ConversationDetailsIcon';
export type Contact = Pick< export type Contact = Pick<
ConversationType, ConversationType,
@ -88,6 +94,7 @@ export type PropsReduxActions = Pick<
| 'saveAttachment' | 'saveAttachment'
| 'showContactModal' | 'showContactModal'
| 'showConversation' | 'showConversation'
| 'showEditHistoryModal'
| 'showExpiredIncomingTapToViewToast' | 'showExpiredIncomingTapToViewToast'
| 'showExpiredOutgoingTapToViewToast' | 'showExpiredOutgoingTapToViewToast'
| 'showLightbox' | 'showLightbox'
@ -131,6 +138,7 @@ export function MessageDetail({
saveAttachment, saveAttachment,
showContactModal, showContactModal,
showConversation, showConversation,
showEditHistoryModal,
showExpiredIncomingTapToViewToast, showExpiredIncomingTapToViewToast,
showExpiredOutgoingTapToViewToast, showExpiredOutgoingTapToViewToast,
showLightbox, showLightbox,
@ -321,123 +329,150 @@ export function MessageDetail({
return ( return (
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
<div className="module-message-detail" tabIndex={0} ref={focusRef}> <div className="module-message-detail" tabIndex={0} ref={focusRef}>
<div <PanelSection>
className="module-message-detail__message-container" <div
ref={messageContainerRef} className="module-message-detail__message-container"
> ref={messageContainerRef}
<Message >
{...message} <Message
renderingContext="conversation/MessageDetail" {...message}
checkForAccount={checkForAccount} renderingContext="conversation/MessageDetail"
clearTargetedMessage={clearTargetedMessage} checkForAccount={checkForAccount}
contactNameColor={contactNameColor} clearTargetedMessage={clearTargetedMessage}
containerElementRef={messageContainerRef} contactNameColor={contactNameColor}
containerWidthBreakpoint={WidthBreakpoint.Wide} containerElementRef={messageContainerRef}
renderMenu={undefined} containerWidthBreakpoint={WidthBreakpoint.Wide}
disableScroll renderMenu={undefined}
displayLimit={Number.MAX_SAFE_INTEGER} disableScroll
showLightboxForViewOnceMedia={showLightboxForViewOnceMedia} displayLimit={Number.MAX_SAFE_INTEGER}
doubleCheckMissingQuoteReference={doubleCheckMissingQuoteReference} showLightboxForViewOnceMedia={showLightboxForViewOnceMedia}
getPreferredBadge={getPreferredBadge} doubleCheckMissingQuoteReference={doubleCheckMissingQuoteReference}
i18n={i18n} getPreferredBadge={getPreferredBadge}
interactionMode={interactionMode} i18n={i18n}
kickOffAttachmentDownload={kickOffAttachmentDownload} interactionMode={interactionMode}
markAttachmentAsCorrupted={markAttachmentAsCorrupted} kickOffAttachmentDownload={kickOffAttachmentDownload}
messageExpanded={messageExpanded} markAttachmentAsCorrupted={markAttachmentAsCorrupted}
openGiftBadge={openGiftBadge} messageExpanded={messageExpanded}
platform={platform} openGiftBadge={openGiftBadge}
pushPanelForConversation={pushPanelForConversation} platform={platform}
retryMessageSend={retryMessageSend} pushPanelForConversation={pushPanelForConversation}
renderAudioAttachment={renderAudioAttachment} retryMessageSend={retryMessageSend}
saveAttachment={saveAttachment} renderAudioAttachment={renderAudioAttachment}
shouldCollapseAbove={false} saveAttachment={saveAttachment}
shouldCollapseBelow={false} shouldCollapseAbove={false}
shouldHideMetadata={false} shouldCollapseBelow={false}
showConversation={showConversation} shouldHideMetadata={false}
showSpoiler={showSpoiler} showConversation={showConversation}
scrollToQuotedMessage={() => { showSpoiler={showSpoiler}
log.warn('MessageDetail: scrollToQuotedMessage called!'); scrollToQuotedMessage={() => {
}} log.warn('MessageDetail: scrollToQuotedMessage called!');
showContactModal={showContactModal} }}
showExpiredIncomingTapToViewToast={showExpiredIncomingTapToViewToast} showContactModal={showContactModal}
showExpiredOutgoingTapToViewToast={showExpiredOutgoingTapToViewToast} showExpiredIncomingTapToViewToast={
showLightbox={showLightbox} showExpiredIncomingTapToViewToast
startConversation={startConversation} }
theme={theme} showExpiredOutgoingTapToViewToast={
viewStory={viewStory} showExpiredOutgoingTapToViewToast
onToggleSelect={noop} }
onReplyToMessage={noop} showLightbox={showLightbox}
/> startConversation={startConversation}
</div> theme={theme}
<table className="module-message-detail__info"> viewStory={viewStory}
<tbody> onToggleSelect={noop}
{(errors || []).map(error => ( onReplyToMessage={noop}
<tr key={_keyForError(error)}> />
</div>
<table className="module-message-detail__info">
<tbody>
{(errors || []).map(error => (
<tr key={_keyForError(error)}>
<td className="module-message-detail__label">
{i18n('icu:error')}
</td>
<td>
{' '}
<span className="error-message">{error.message}</span>{' '}
</td>
</tr>
))}
<tr>
<td className="module-message-detail__label"> <td className="module-message-detail__label">
{i18n('icu:error')} {i18n('icu:sent')}
</td> </td>
<td> <td>
{' '} <ContextMenu
<span className="error-message">{error.message}</span>{' '} i18n={i18n}
menuOptions={[
{
icon: 'StoryDetailsModal__copy-icon',
label: i18n('icu:StoryDetailsModal__copy-timestamp'),
onClick: () => {
void window.navigator.clipboard.writeText(
String(sentAt)
);
},
},
]}
>
<>
<Time timestamp={sentAt}>
{formatDateTimeLong(i18n, sentAt)}
</Time>{' '}
<span className="module-message-detail__unix-timestamp">
({sentAt})
</span>
</>
</ContextMenu>
</td> </td>
</tr> </tr>
))} {receivedAt && message.direction === 'incoming' ? (
<tr> <tr>
<td className="module-message-detail__label">{i18n('icu:sent')}</td> <td className="module-message-detail__label">
<td> {i18n('icu:received')}
<ContextMenu </td>
i18n={i18n} <td>
menuOptions={[ <Time timestamp={receivedAt}>
{ {formatDateTimeLong(i18n, receivedAt)}
icon: 'StoryDetailsModal__copy-icon',
label: i18n('icu:StoryDetailsModal__copy-timestamp'),
onClick: () => {
void window.navigator.clipboard.writeText(String(sentAt));
},
},
]}
>
<>
<Time timestamp={sentAt}>
{formatDateTimeLong(i18n, sentAt)}
</Time>{' '} </Time>{' '}
<span className="module-message-detail__unix-timestamp"> <span className="module-message-detail__unix-timestamp">
({sentAt}) ({receivedAt})
</span> </span>
</> </td>
</ContextMenu> </tr>
</td> ) : null}
</tr> {timeRemaining && timeRemaining > 0 && (
{receivedAt && message.direction === 'incoming' ? ( <tr>
<tr> <td className="module-message-detail__label">
<td className="module-message-detail__label"> {i18n('icu:MessageDetail--disappears-in')}
{i18n('icu:received')} </td>
</td> <td>
<td> {formatRelativeTime(i18n, timeRemaining, {
<Time timestamp={receivedAt}> largest: 2,
{formatDateTimeLong(i18n, receivedAt)} })}
</Time>{' '} </td>
<span className="module-message-detail__unix-timestamp"> </tr>
({receivedAt}) )}
</span> </tbody>
</td> </table>
</tr> </PanelSection>
) : null} {message.isEditedMessage && (
{timeRemaining && timeRemaining > 0 && ( <PanelSection>
<tr> <PanelRow
<td className="module-message-detail__label"> icon={
{i18n('icu:MessageDetail--disappears-in')} <ConversationDetailsIcon
</td> ariaLabel={i18n('icu:MessageDetail__view-edits')}
<td> icon={IconType.edit}
{formatRelativeTime(i18n, timeRemaining, { />
largest: 2, }
})} label={i18n('icu:MessageDetail__view-edits')}
</td> onClick={() => {
</tr> showEditHistoryModal?.(message.id);
)} }}
</tbody> />
</table> </PanelSection>
{renderContacts()} )}
<PanelSection>{renderContacts()}</PanelSection>
</div> </div>
); );
} }

View file

@ -9,6 +9,7 @@ import { bemGenerator } from './util';
export enum IconType { export enum IconType {
'block' = 'block', 'block' = 'block',
'edit' = 'edit',
'unblock' = 'unblock', 'unblock' = 'unblock',
'color' = 'color', 'color' = 'color',
'down' = 'down', 'down' = 'down',

View file

@ -54,7 +54,8 @@ export function SmartMessageDetail(): JSX.Element | null {
showSpoiler, showSpoiler,
startConversation, startConversation,
} = useConversationsActions(); } = useConversationsActions();
const { showContactModal, toggleSafetyNumberModal } = useGlobalModalActions(); const { showContactModal, showEditHistoryModal, toggleSafetyNumberModal } =
useGlobalModalActions();
const { showLightbox, showLightboxForViewOnceMedia } = useLightboxActions(); const { showLightbox, showLightboxForViewOnceMedia } = useLightboxActions();
const { viewStory } = useStoriesActions(); const { viewStory } = useStoriesActions();
@ -100,6 +101,7 @@ export function SmartMessageDetail(): JSX.Element | null {
sentAt={message.timestamp} sentAt={message.timestamp}
showContactModal={showContactModal} showContactModal={showContactModal}
showConversation={showConversation} showConversation={showConversation}
showEditHistoryModal={showEditHistoryModal}
showExpiredIncomingTapToViewToast={showExpiredIncomingTapToViewToast} showExpiredIncomingTapToViewToast={showExpiredIncomingTapToViewToast}
showExpiredOutgoingTapToViewToast={showExpiredOutgoingTapToViewToast} showExpiredOutgoingTapToViewToast={showExpiredOutgoingTapToViewToast}
showLightbox={showLightbox} showLightbox={showLightbox}