mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-04-23 01:48:13 +01:00
Init payments message types
This commit is contained in:
@@ -83,6 +83,10 @@ import { DAY, HOUR, MINUTE, SECOND } from '../../util/durations';
|
||||
import { BadgeImageTheme } from '../../badges/BadgeImageTheme';
|
||||
import { getBadgeImageFileLocalPath } from '../../badges/getBadgeImageFileLocalPath';
|
||||
import { handleOutsideClick } from '../../util/handleOutsideClick';
|
||||
import { PaymentEventKind } from '../../types/Payment';
|
||||
import type { AnyPaymentEvent } from '../../types/Payment';
|
||||
import { Emojify } from './Emojify';
|
||||
import { getPaymentEventDescription } from '../../messages/helpers';
|
||||
|
||||
const GUESS_METADATA_WIDTH_TIMESTAMP_SIZE = 10;
|
||||
const GUESS_METADATA_WIDTH_EXPIRE_TIMER_SIZE = 18;
|
||||
@@ -216,11 +220,14 @@ export type PropsData = {
|
||||
conversationType: ConversationTypeType;
|
||||
attachments?: Array<AttachmentType>;
|
||||
giftBadge?: GiftBadgeType;
|
||||
payment?: AnyPaymentEvent;
|
||||
quote?: {
|
||||
conversationColor: ConversationColorType;
|
||||
conversationTitle: string;
|
||||
customColor?: CustomColorType;
|
||||
text: string;
|
||||
rawAttachment?: QuotedAttachmentType;
|
||||
payment?: AnyPaymentEvent;
|
||||
isFromMe: boolean;
|
||||
sentAt: number;
|
||||
authorId: string;
|
||||
@@ -1405,9 +1412,52 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
throw missingCaseError(giftBadge.state);
|
||||
}
|
||||
|
||||
public renderPayment(): JSX.Element | null {
|
||||
const {
|
||||
payment,
|
||||
direction,
|
||||
author,
|
||||
conversationTitle,
|
||||
conversationColor,
|
||||
i18n,
|
||||
} = this.props;
|
||||
if (payment == null || payment.kind !== PaymentEventKind.Notification) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`module-payment-notification__container ${
|
||||
direction === 'outgoing'
|
||||
? `module-payment-notification--outgoing module-payment-notification--outgoing-${conversationColor}`
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
<p className="module-payment-notification__label">
|
||||
{getPaymentEventDescription(
|
||||
payment,
|
||||
author.title,
|
||||
conversationTitle,
|
||||
author.isMe,
|
||||
i18n
|
||||
)}
|
||||
</p>
|
||||
<p className="module-payment-notification__check_device_box">
|
||||
{i18n('icu:payment-event-notification-check-primary-device')}
|
||||
</p>
|
||||
{payment.note != null && (
|
||||
<p className="module-payment-notification__note">
|
||||
<Emojify text={payment.note} />
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public renderQuote(): JSX.Element | null {
|
||||
const {
|
||||
conversationColor,
|
||||
conversationTitle,
|
||||
customColor,
|
||||
direction,
|
||||
disableScroll,
|
||||
@@ -1441,10 +1491,12 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
onClick={clickHandler}
|
||||
text={quote.text}
|
||||
rawAttachment={quote.rawAttachment}
|
||||
payment={quote.payment}
|
||||
isIncoming={isIncoming}
|
||||
authorTitle={quote.authorTitle}
|
||||
bodyRanges={quote.bodyRanges}
|
||||
conversationColor={conversationColor}
|
||||
conversationTitle={conversationTitle}
|
||||
customColor={customColor}
|
||||
isViewOnce={isViewOnce}
|
||||
isGiftBadge={isGiftBadge}
|
||||
@@ -1459,6 +1511,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
|
||||
public renderStoryReplyContext(): JSX.Element | null {
|
||||
const {
|
||||
conversationTitle,
|
||||
conversationColor,
|
||||
customColor,
|
||||
direction,
|
||||
@@ -1483,6 +1536,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
<Quote
|
||||
authorTitle={storyReplyContext.authorTitle}
|
||||
conversationColor={conversationColor}
|
||||
conversationTitle={conversationTitle}
|
||||
customColor={customColor}
|
||||
i18n={i18n}
|
||||
isFromMe={storyReplyContext.isFromMe}
|
||||
@@ -2169,6 +2223,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
{this.renderStoryReplyContext()}
|
||||
{this.renderAttachment()}
|
||||
{this.renderPreview()}
|
||||
{this.renderPayment()}
|
||||
{this.renderEmbeddedContact()}
|
||||
{this.renderText()}
|
||||
{this.renderMetadata()}
|
||||
|
||||
32
ts/components/conversation/PaymentEventNotification.tsx
Normal file
32
ts/components/conversation/PaymentEventNotification.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2020-2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import type { LocalizerType } from '../../types/Util';
|
||||
import type { ConversationType } from '../../state/ducks/conversations';
|
||||
import { SystemMessage } from './SystemMessage';
|
||||
import { Emojify } from './Emojify';
|
||||
import type { AnyPaymentEvent } from '../../types/Payment';
|
||||
import { getPaymentEventDescription } from '../../messages/helpers';
|
||||
|
||||
export type PropsType = {
|
||||
event: AnyPaymentEvent;
|
||||
sender: ConversationType;
|
||||
conversation: ConversationType;
|
||||
i18n: LocalizerType;
|
||||
};
|
||||
|
||||
export function PaymentEventNotification(props: PropsType): JSX.Element {
|
||||
const { event, sender, conversation, i18n } = props;
|
||||
const message = getPaymentEventDescription(
|
||||
event,
|
||||
sender.title,
|
||||
conversation.title,
|
||||
sender.isMe,
|
||||
i18n
|
||||
);
|
||||
return (
|
||||
<SystemMessage icon="payment-event" contents={<Emojify text={message} />} />
|
||||
);
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import enMessages from '../../../_locales/en/messages.json';
|
||||
import { getDefaultConversation } from '../../test-both/helpers/getDefaultConversation';
|
||||
import { WidthBreakpoint } from '../_util';
|
||||
import { ThemeType } from '../../types/Util';
|
||||
import { PaymentEventKind } from '../../types/Payment';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
@@ -166,6 +167,7 @@ const renderInMessage = ({
|
||||
authorId: 'an-author',
|
||||
authorTitle,
|
||||
conversationColor,
|
||||
conversationTitle: getDefaultConversation().title,
|
||||
isFromMe,
|
||||
rawAttachment,
|
||||
isViewOnce,
|
||||
@@ -567,3 +569,12 @@ IsStoryReplyEmoji.args = {
|
||||
IsStoryReplyEmoji.story = {
|
||||
name: 'isStoryReply emoji',
|
||||
};
|
||||
|
||||
export const Payment = Template.bind({});
|
||||
Payment.args = {
|
||||
text: '',
|
||||
payment: {
|
||||
kind: PaymentEventKind.Notification,
|
||||
note: null,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -22,10 +22,14 @@ import { TextAttachment } from '../TextAttachment';
|
||||
import { getTextWithMentions } from '../../util/getTextWithMentions';
|
||||
import { getClassNamesFor } from '../../util/getClassNamesFor';
|
||||
import { getCustomColorStyle } from '../../util/getCustomColorStyle';
|
||||
import type { AnyPaymentEvent } from '../../types/Payment';
|
||||
import { PaymentEventKind } from '../../types/Payment';
|
||||
import { getPaymentEventNotificationText } from '../../messages/helpers';
|
||||
|
||||
export type Props = {
|
||||
authorTitle: string;
|
||||
conversationColor: ConversationColorType;
|
||||
conversationTitle: string;
|
||||
customColor?: CustomColorType;
|
||||
bodyRanges?: HydratedBodyRangesType;
|
||||
i18n: LocalizerType;
|
||||
@@ -38,6 +42,7 @@ export type Props = {
|
||||
onClose?: () => void;
|
||||
text: string;
|
||||
rawAttachment?: QuotedAttachmentType;
|
||||
payment?: AnyPaymentEvent;
|
||||
isGiftBadge: boolean;
|
||||
isViewOnce: boolean;
|
||||
reactionEmoji?: string;
|
||||
@@ -74,6 +79,10 @@ function validateQuote(quote: Props): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (quote.payment?.kind === PaymentEventKind.Notification) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -274,6 +283,28 @@ export class Quote extends React.Component<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
public renderPayment(): JSX.Element | null {
|
||||
const { payment, authorTitle, conversationTitle, isFromMe, i18n } =
|
||||
this.props;
|
||||
|
||||
if (payment == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Emojify text="💳" />
|
||||
{getPaymentEventNotificationText(
|
||||
payment,
|
||||
authorTitle,
|
||||
conversationTitle,
|
||||
isFromMe,
|
||||
i18n
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
public renderIconContainer(): JSX.Element | null {
|
||||
const { isGiftBadge, isViewOnce, i18n, rawAttachment } = this.props;
|
||||
const { imageBroken } = this.state;
|
||||
@@ -550,6 +581,7 @@ export class Quote extends React.Component<Props, State> {
|
||||
<div className={this.getClassName('__primary')}>
|
||||
{this.renderAuthor()}
|
||||
{this.renderGenericFile()}
|
||||
{this.renderPayment()}
|
||||
{this.renderText()}
|
||||
</div>
|
||||
{reactionEmoji && (
|
||||
|
||||
@@ -26,6 +26,8 @@ import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||
import type { WidthBreakpoint } from '../_util';
|
||||
import { ThemeType } from '../../types/Util';
|
||||
import { TextDirection } from './Message';
|
||||
import { PaymentEventKind } from '../../types/Payment';
|
||||
import type { PropsData as TimelineMessageProps } from './TimelineMessage';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
@@ -36,61 +38,53 @@ export default {
|
||||
// eslint-disable-next-line
|
||||
const noop = () => {};
|
||||
|
||||
const items: Record<string, TimelineItemType> = {
|
||||
'id-1': {
|
||||
type: 'message',
|
||||
data: {
|
||||
author: getDefaultConversation({
|
||||
phoneNumber: '(202) 555-2001',
|
||||
}),
|
||||
canDeleteForEveryone: false,
|
||||
canDownload: true,
|
||||
canReact: true,
|
||||
canReply: true,
|
||||
canRetry: true,
|
||||
canRetryDeleteForEveryone: true,
|
||||
conversationColor: 'forest',
|
||||
conversationId: 'conversation-id',
|
||||
conversationTitle: 'Conversation Title',
|
||||
conversationType: 'group',
|
||||
direction: 'incoming',
|
||||
id: 'id-1',
|
||||
isBlocked: false,
|
||||
isMessageRequestAccepted: true,
|
||||
previews: [],
|
||||
readStatus: ReadStatus.Read,
|
||||
text: '🔥',
|
||||
textDirection: TextDirection.Default,
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
'id-2': {
|
||||
function mockMessageTimelineItem(
|
||||
id: string,
|
||||
data: Partial<TimelineMessageProps>
|
||||
): TimelineItemType {
|
||||
return {
|
||||
type: 'message',
|
||||
data: {
|
||||
id,
|
||||
author: getDefaultConversation({}),
|
||||
canDeleteForEveryone: false,
|
||||
canDownload: true,
|
||||
canReact: true,
|
||||
canReply: true,
|
||||
canRetry: true,
|
||||
canRetryDeleteForEveryone: true,
|
||||
conversationColor: 'forest',
|
||||
conversationId: 'conversation-id',
|
||||
conversationTitle: 'Conversation Title',
|
||||
conversationType: 'group',
|
||||
conversationColor: 'crimson',
|
||||
direction: 'incoming',
|
||||
id: 'id-2',
|
||||
status: 'sent',
|
||||
text: 'Hello there from the new world!',
|
||||
isBlocked: false,
|
||||
isMessageRequestAccepted: true,
|
||||
previews: [],
|
||||
readStatus: ReadStatus.Read,
|
||||
text: 'Hello there from the new world! http://somewhere.com',
|
||||
canRetryDeleteForEveryone: true,
|
||||
textDirection: TextDirection.Default,
|
||||
timestamp: Date.now(),
|
||||
...data,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const items: Record<string, TimelineItemType> = {
|
||||
'id-1': mockMessageTimelineItem('id-1', {
|
||||
author: getDefaultConversation({
|
||||
phoneNumber: '(202) 555-2001',
|
||||
}),
|
||||
conversationColor: 'forest',
|
||||
text: '🔥',
|
||||
}),
|
||||
'id-2': mockMessageTimelineItem('id-2', {
|
||||
conversationColor: 'forest',
|
||||
direction: 'incoming',
|
||||
text: 'Hello there from the new world! http://somewhere.com',
|
||||
}),
|
||||
'id-2.5': {
|
||||
type: 'unsupportedMessage',
|
||||
data: {
|
||||
@@ -105,32 +99,7 @@ const items: Record<string, TimelineItemType> = {
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
'id-3': {
|
||||
type: 'message',
|
||||
data: {
|
||||
author: getDefaultConversation({}),
|
||||
canDeleteForEveryone: false,
|
||||
canDownload: true,
|
||||
canReact: true,
|
||||
canReply: true,
|
||||
canRetry: true,
|
||||
canRetryDeleteForEveryone: true,
|
||||
conversationColor: 'crimson',
|
||||
conversationId: 'conversation-id',
|
||||
conversationTitle: 'Conversation Title',
|
||||
conversationType: 'group',
|
||||
direction: 'incoming',
|
||||
id: 'id-3',
|
||||
isBlocked: false,
|
||||
isMessageRequestAccepted: true,
|
||||
previews: [],
|
||||
readStatus: ReadStatus.Read,
|
||||
text: 'Hello there from the new world!',
|
||||
textDirection: TextDirection.Default,
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
'id-3': mockMessageTimelineItem('id-3', {}),
|
||||
'id-4': {
|
||||
type: 'timerNotification',
|
||||
data: {
|
||||
@@ -206,141 +175,85 @@ const items: Record<string, TimelineItemType> = {
|
||||
data: null,
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
'id-10': {
|
||||
type: 'message',
|
||||
'id-10': mockMessageTimelineItem('id-10', {
|
||||
conversationColor: 'plum',
|
||||
direction: 'outgoing',
|
||||
text: '🔥',
|
||||
}),
|
||||
'id-11': mockMessageTimelineItem('id-11', {
|
||||
direction: 'outgoing',
|
||||
status: 'read',
|
||||
text: 'Hello there from the new world! http://somewhere.com',
|
||||
}),
|
||||
'id-12': mockMessageTimelineItem('id-12', {
|
||||
direction: 'outgoing',
|
||||
text: 'Hello there from the new world! 🔥',
|
||||
}),
|
||||
'id-13': mockMessageTimelineItem('id-13', {
|
||||
direction: 'outgoing',
|
||||
text: 'Hello there from the new world! And this is multiple lines of text. Lines and lines and lines.',
|
||||
}),
|
||||
'id-14': mockMessageTimelineItem('id-14', {
|
||||
direction: 'outgoing',
|
||||
status: 'read',
|
||||
text: 'Hello there from the new world! And this is multiple lines of text. Lines and lines and lines.',
|
||||
}),
|
||||
'id-15': {
|
||||
type: 'paymentEvent',
|
||||
data: {
|
||||
author: getDefaultConversation({}),
|
||||
canDeleteForEveryone: false,
|
||||
canDownload: true,
|
||||
canReact: true,
|
||||
canReply: true,
|
||||
canRetry: true,
|
||||
canRetryDeleteForEveryone: true,
|
||||
conversationColor: 'plum',
|
||||
conversationId: 'conversation-id',
|
||||
conversationTitle: 'Conversation Title',
|
||||
conversationType: 'group',
|
||||
direction: 'outgoing',
|
||||
id: 'id-6',
|
||||
isBlocked: false,
|
||||
isMessageRequestAccepted: true,
|
||||
previews: [],
|
||||
readStatus: ReadStatus.Read,
|
||||
status: 'sent',
|
||||
text: '🔥',
|
||||
textDirection: TextDirection.Default,
|
||||
timestamp: Date.now(),
|
||||
event: {
|
||||
kind: PaymentEventKind.ActivationRequest,
|
||||
},
|
||||
sender: getDefaultConversation(),
|
||||
conversation: getDefaultConversation(),
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
'id-11': {
|
||||
type: 'message',
|
||||
'id-16': {
|
||||
type: 'paymentEvent',
|
||||
data: {
|
||||
author: getDefaultConversation({}),
|
||||
canDeleteForEveryone: false,
|
||||
canDownload: true,
|
||||
canReact: true,
|
||||
canReply: true,
|
||||
canRetry: true,
|
||||
canRetryDeleteForEveryone: true,
|
||||
conversationColor: 'crimson',
|
||||
conversationId: 'conversation-id',
|
||||
conversationTitle: 'Conversation Title',
|
||||
conversationType: 'group',
|
||||
direction: 'outgoing',
|
||||
id: 'id-7',
|
||||
isBlocked: false,
|
||||
isMessageRequestAccepted: true,
|
||||
previews: [],
|
||||
readStatus: ReadStatus.Read,
|
||||
status: 'read',
|
||||
text: 'Hello there from the new world! http://somewhere.com',
|
||||
textDirection: TextDirection.Default,
|
||||
timestamp: Date.now(),
|
||||
event: {
|
||||
kind: PaymentEventKind.Activation,
|
||||
},
|
||||
sender: getDefaultConversation(),
|
||||
conversation: getDefaultConversation(),
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
'id-12': {
|
||||
type: 'message',
|
||||
'id-17': {
|
||||
type: 'paymentEvent',
|
||||
data: {
|
||||
author: getDefaultConversation({}),
|
||||
canDeleteForEveryone: false,
|
||||
canDownload: true,
|
||||
canReact: true,
|
||||
canReply: true,
|
||||
canRetry: true,
|
||||
canRetryDeleteForEveryone: true,
|
||||
conversationColor: 'crimson',
|
||||
conversationId: 'conversation-id',
|
||||
conversationTitle: 'Conversation Title',
|
||||
conversationType: 'group',
|
||||
direction: 'outgoing',
|
||||
id: 'id-8',
|
||||
isBlocked: false,
|
||||
isMessageRequestAccepted: true,
|
||||
previews: [],
|
||||
readStatus: ReadStatus.Read,
|
||||
status: 'sent',
|
||||
text: 'Hello there from the new world! 🔥',
|
||||
textDirection: TextDirection.Default,
|
||||
timestamp: Date.now(),
|
||||
event: {
|
||||
kind: PaymentEventKind.ActivationRequest,
|
||||
},
|
||||
sender: getDefaultConversation({
|
||||
isMe: true,
|
||||
}),
|
||||
conversation: getDefaultConversation(),
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
'id-13': {
|
||||
type: 'message',
|
||||
'id-18': {
|
||||
type: 'paymentEvent',
|
||||
data: {
|
||||
author: getDefaultConversation({}),
|
||||
canDeleteForEveryone: false,
|
||||
canDownload: true,
|
||||
canReact: true,
|
||||
canReply: true,
|
||||
canRetry: true,
|
||||
canRetryDeleteForEveryone: true,
|
||||
conversationColor: 'crimson',
|
||||
conversationId: 'conversation-id',
|
||||
conversationTitle: 'Conversation Title',
|
||||
conversationType: 'group',
|
||||
direction: 'outgoing',
|
||||
id: 'id-9',
|
||||
isBlocked: false,
|
||||
isMessageRequestAccepted: true,
|
||||
previews: [],
|
||||
readStatus: ReadStatus.Read,
|
||||
status: 'sent',
|
||||
text: 'Hello there from the new world! And this is multiple lines of text. Lines and lines and lines.',
|
||||
textDirection: TextDirection.Default,
|
||||
timestamp: Date.now(),
|
||||
event: {
|
||||
kind: PaymentEventKind.Activation,
|
||||
},
|
||||
sender: getDefaultConversation({
|
||||
isMe: true,
|
||||
}),
|
||||
conversation: getDefaultConversation(),
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
'id-14': {
|
||||
type: 'message',
|
||||
data: {
|
||||
author: getDefaultConversation({}),
|
||||
canDeleteForEveryone: false,
|
||||
canDownload: true,
|
||||
canReact: true,
|
||||
canReply: true,
|
||||
canRetry: true,
|
||||
canRetryDeleteForEveryone: true,
|
||||
conversationColor: 'crimson',
|
||||
conversationId: 'conversation-id',
|
||||
conversationTitle: 'Conversation Title',
|
||||
conversationType: 'group',
|
||||
direction: 'outgoing',
|
||||
id: 'id-10',
|
||||
isBlocked: false,
|
||||
isMessageRequestAccepted: true,
|
||||
previews: [],
|
||||
readStatus: ReadStatus.Read,
|
||||
status: 'read',
|
||||
text: 'Hello there from the new world! And this is multiple lines of text. Lines and lines and lines.',
|
||||
textDirection: TextDirection.Default,
|
||||
timestamp: Date.now(),
|
||||
'id-19': mockMessageTimelineItem('id-19', {
|
||||
direction: 'outgoing',
|
||||
status: 'read',
|
||||
payment: {
|
||||
kind: PaymentEventKind.Notification,
|
||||
note: 'Thanks',
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
const actions = () => ({
|
||||
|
||||
@@ -17,6 +17,7 @@ import { AvatarColors } from '../../types/Colors';
|
||||
import { getDefaultConversation } from '../../test-both/helpers/getDefaultConversation';
|
||||
import { WidthBreakpoint } from '../_util';
|
||||
import { ThemeType } from '../../types/Util';
|
||||
import { PaymentEventKind } from '../../types/Payment';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
@@ -437,6 +438,50 @@ export function Notification(): JSX.Element {
|
||||
changedContact: getDefaultConversation(),
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'paymentEvent',
|
||||
data: {
|
||||
event: {
|
||||
kind: PaymentEventKind.ActivationRequest,
|
||||
},
|
||||
sender: getDefaultConversation(),
|
||||
conversation: getDefaultConversation(),
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'paymentEvent',
|
||||
data: {
|
||||
event: {
|
||||
kind: PaymentEventKind.Activation,
|
||||
},
|
||||
sender: getDefaultConversation(),
|
||||
conversation: getDefaultConversation(),
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'paymentEvent',
|
||||
data: {
|
||||
event: {
|
||||
kind: PaymentEventKind.ActivationRequest,
|
||||
},
|
||||
sender: getDefaultConversation({
|
||||
isMe: true,
|
||||
}),
|
||||
conversation: getDefaultConversation(),
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'paymentEvent',
|
||||
data: {
|
||||
event: {
|
||||
kind: PaymentEventKind.Activation,
|
||||
},
|
||||
sender: getDefaultConversation({
|
||||
isMe: true,
|
||||
}),
|
||||
conversation: getDefaultConversation(),
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'resetSessionNotification',
|
||||
data: null,
|
||||
|
||||
@@ -53,6 +53,8 @@ import type { SmartContactRendererType } from '../../groupChange';
|
||||
import { ResetSessionNotification } from './ResetSessionNotification';
|
||||
import type { PropsType as ProfileChangeNotificationPropsType } from './ProfileChangeNotification';
|
||||
import { ProfileChangeNotification } from './ProfileChangeNotification';
|
||||
import type { PropsType as PaymentEventNotificationPropsType } from './PaymentEventNotification';
|
||||
import { PaymentEventNotification } from './PaymentEventNotification';
|
||||
import type { FullJSXType } from '../Intl';
|
||||
import { TimelineMessage } from './TimelineMessage';
|
||||
|
||||
@@ -116,6 +118,10 @@ type ProfileChangeNotificationType = {
|
||||
type: 'profileChange';
|
||||
data: ProfileChangeNotificationPropsType;
|
||||
};
|
||||
type PaymentEventType = {
|
||||
type: 'paymentEvent';
|
||||
data: Omit<PaymentEventNotificationPropsType, 'i18n'>;
|
||||
};
|
||||
|
||||
export type TimelineItemType = (
|
||||
| CallHistoryType
|
||||
@@ -133,6 +139,7 @@ export type TimelineItemType = (
|
||||
| ChangeNumberNotificationType
|
||||
| UnsupportedMessageType
|
||||
| VerificationNotificationType
|
||||
| PaymentEventType
|
||||
) & { timestamp: number };
|
||||
|
||||
type PropsLocalType = {
|
||||
@@ -302,6 +309,14 @@ export class TimelineItem extends React.PureComponent<PropsType> {
|
||||
i18n={i18n}
|
||||
/>
|
||||
);
|
||||
} else if (item.type === 'paymentEvent') {
|
||||
notification = (
|
||||
<PaymentEventNotification
|
||||
{...this.props}
|
||||
{...item.data}
|
||||
i18n={i18n}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
// Weird, yes, but the idea is to get a compile error when we aren't comprehensive
|
||||
// with our if/else checks above, but also log out the type we don't understand
|
||||
|
||||
@@ -44,6 +44,7 @@ import { getFakeBadge } from '../../test-both/helpers/getFakeBadge';
|
||||
import { ThemeType } from '../../types/Util';
|
||||
import { UUID } from '../../types/UUID';
|
||||
import { BadgeCategory } from '../../badges/BadgeCategory';
|
||||
import { PaymentEventKind } from '../../types/Payment';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
@@ -863,6 +864,7 @@ export const LinkPreviewWithQuote = Template.bind({});
|
||||
LinkPreviewWithQuote.args = {
|
||||
quote: {
|
||||
conversationColor: ConversationColors[2],
|
||||
conversationTitle: getDefaultConversation().title,
|
||||
text: 'The quoted message',
|
||||
isFromMe: false,
|
||||
sentAt: Date.now(),
|
||||
@@ -2069,3 +2071,13 @@ GiftBadgeMissingBadge.args = {
|
||||
GiftBadgeMissingBadge.story = {
|
||||
name: 'Gift Badge: Missing Badge',
|
||||
};
|
||||
|
||||
export const PaymentNotification = Template.bind({});
|
||||
PaymentNotification.args = {
|
||||
canReply: false,
|
||||
canReact: false,
|
||||
payment: {
|
||||
kind: PaymentEventKind.Notification,
|
||||
note: 'Hello there',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -78,6 +78,7 @@ export function TimelineMessage(props: Props): JSX.Element {
|
||||
canDeleteForEveryone,
|
||||
canRetryDeleteForEveryone,
|
||||
contact,
|
||||
payment,
|
||||
containerElementRef,
|
||||
containerWidthBreakpoint,
|
||||
deletedForEveryone,
|
||||
@@ -210,7 +211,7 @@ export function TimelineMessage(props: Props): JSX.Element {
|
||||
};
|
||||
|
||||
const canForward =
|
||||
!isTapToView && !deletedForEveryone && !giftBadge && !contact;
|
||||
!isTapToView && !deletedForEveryone && !giftBadge && !contact && !payment;
|
||||
|
||||
const shouldShowAdditional =
|
||||
doesMessageBodyOverflow(text || '') || !isWindowWidthNotNarrow;
|
||||
|
||||
Reference in New Issue
Block a user