563 lines
14 KiB
TypeScript
563 lines
14 KiB
TypeScript
// Copyright 2020 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import * as React from 'react';
|
|
|
|
import { action } from '@storybook/addon-actions';
|
|
|
|
import { EmojiPicker } from '../emoji/EmojiPicker';
|
|
import { setupI18n } from '../../util/setupI18n';
|
|
import { DurationInSeconds } from '../../util/durations';
|
|
import enMessages from '../../../_locales/en/messages.json';
|
|
import type { PropsType as TimelineItemProps } from './TimelineItem';
|
|
import { TimelineItem } from './TimelineItem';
|
|
import { UniversalTimerNotification } from './UniversalTimerNotification';
|
|
import { CallMode } from '../../types/Calling';
|
|
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);
|
|
|
|
const renderEmojiPicker: TimelineItemProps['renderEmojiPicker'] = ({
|
|
onClose,
|
|
onPickEmoji,
|
|
ref,
|
|
}) => (
|
|
<EmojiPicker
|
|
i18n={setupI18n('en', enMessages)}
|
|
skinTone={0}
|
|
onSetSkinTone={action('EmojiPicker::onSetSkinTone')}
|
|
ref={ref}
|
|
onClose={onClose}
|
|
onPickEmoji={onPickEmoji}
|
|
/>
|
|
);
|
|
|
|
const renderReactionPicker: TimelineItemProps['renderReactionPicker'] = () => (
|
|
<div />
|
|
);
|
|
|
|
const renderContact = (conversationId: string) => (
|
|
<React.Fragment key={conversationId}>{conversationId}</React.Fragment>
|
|
);
|
|
|
|
const renderUniversalTimerNotification = () => (
|
|
<UniversalTimerNotification
|
|
i18n={i18n}
|
|
expireTimer={DurationInSeconds.HOUR}
|
|
/>
|
|
);
|
|
|
|
const getDefaultProps = () => ({
|
|
containerElementRef: React.createRef<HTMLElement>(),
|
|
containerWidthBreakpoint: WidthBreakpoint.Wide,
|
|
conversationId: 'conversation-id',
|
|
getPreferredBadge: () => undefined,
|
|
id: 'asdf',
|
|
isNextItemCallingNotification: false,
|
|
isSelected: false,
|
|
interactionMode: 'keyboard' as const,
|
|
theme: ThemeType.light,
|
|
selectMessage: action('selectMessage'),
|
|
reactToMessage: action('reactToMessage'),
|
|
checkForAccount: action('checkForAccount'),
|
|
clearSelectedMessage: action('clearSelectedMessage'),
|
|
setQuoteByMessageId: action('setQuoteByMessageId'),
|
|
retryDeleteForEveryone: action('retryDeleteForEveryone'),
|
|
retryMessageSend: action('retryMessageSend'),
|
|
blockGroupLinkRequests: action('blockGroupLinkRequests'),
|
|
deleteMessage: action('deleteMessage'),
|
|
deleteMessageForEveryone: action('deleteMessageForEveryone'),
|
|
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
|
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
|
messageExpanded: action('messageExpanded'),
|
|
showConversation: action('showConversation'),
|
|
openGiftBadge: action('openGiftBadge'),
|
|
saveAttachment: action('saveAttachment'),
|
|
pushPanelForConversation: action('pushPanelForConversation'),
|
|
showContactModal: action('showContactModal'),
|
|
showLightbox: action('showLightbox'),
|
|
toggleForwardMessageModal: action('toggleForwardMessageModal'),
|
|
showLightboxForViewOnceMedia: action('showLightboxForViewOnceMedia'),
|
|
doubleCheckMissingQuoteReference: action('doubleCheckMissingQuoteReference'),
|
|
showExpiredIncomingTapToViewToast: action(
|
|
'showExpiredIncomingTapToViewToast'
|
|
),
|
|
showExpiredOutgoingTapToViewToast: action(
|
|
'showExpiredIncomingTapToViewToast'
|
|
),
|
|
scrollToQuotedMessage: action('scrollToQuotedMessage'),
|
|
toggleSafetyNumberModal: action('toggleSafetyNumberModal'),
|
|
startCallingLobby: action('startCallingLobby'),
|
|
startConversation: action('startConversation'),
|
|
returnToActiveCall: action('returnToActiveCall'),
|
|
shouldCollapseAbove: false,
|
|
shouldCollapseBelow: false,
|
|
shouldHideMetadata: false,
|
|
shouldRenderDateHeader: false,
|
|
|
|
now: Date.now(),
|
|
|
|
renderContact,
|
|
renderUniversalTimerNotification,
|
|
renderEmojiPicker,
|
|
renderReactionPicker,
|
|
renderAudioAttachment: () => <div>*AudioAttachment*</div>,
|
|
viewStory: action('viewStory'),
|
|
});
|
|
|
|
export default {
|
|
title: 'Components/Conversation/TimelineItem',
|
|
};
|
|
|
|
export function PlainMessage(): JSX.Element {
|
|
const item = {
|
|
type: 'message',
|
|
data: {
|
|
id: 'id-1',
|
|
direction: 'incoming',
|
|
timestamp: Date.now(),
|
|
author: {
|
|
phoneNumber: '(202) 555-2001',
|
|
color: AvatarColors[0],
|
|
},
|
|
text: '🔥',
|
|
},
|
|
} as TimelineItemProps['item'];
|
|
|
|
return <TimelineItem {...getDefaultProps()} item={item} i18n={i18n} />;
|
|
}
|
|
|
|
export function Notification(): JSX.Element {
|
|
const items = [
|
|
{
|
|
type: 'timerNotification',
|
|
data: {
|
|
phoneNumber: '(202) 555-0000',
|
|
expireTimer: DurationInSeconds.MINUTE,
|
|
...getDefaultConversation(),
|
|
type: 'fromOther',
|
|
},
|
|
},
|
|
{
|
|
type: 'universalTimerNotification',
|
|
data: null,
|
|
},
|
|
{
|
|
type: 'chatSessionRefreshed',
|
|
},
|
|
{
|
|
type: 'safetyNumberNotification',
|
|
data: {
|
|
isGroup: false,
|
|
contact: getDefaultConversation(),
|
|
},
|
|
},
|
|
{
|
|
type: 'deliveryIssue',
|
|
data: {
|
|
sender: getDefaultConversation(),
|
|
},
|
|
},
|
|
{
|
|
type: 'changeNumberNotification',
|
|
data: {
|
|
sender: getDefaultConversation(),
|
|
timestamp: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// declined incoming audio
|
|
callMode: CallMode.Direct,
|
|
wasDeclined: true,
|
|
wasIncoming: true,
|
|
wasVideoCall: false,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// declined incoming video
|
|
callMode: CallMode.Direct,
|
|
wasDeclined: true,
|
|
wasIncoming: true,
|
|
wasVideoCall: true,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// accepted incoming audio
|
|
callMode: CallMode.Direct,
|
|
acceptedTime: Date.now() - 300,
|
|
wasDeclined: false,
|
|
wasIncoming: true,
|
|
wasVideoCall: false,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// accepted incoming video
|
|
callMode: CallMode.Direct,
|
|
acceptedTime: Date.now() - 400,
|
|
wasDeclined: false,
|
|
wasIncoming: true,
|
|
wasVideoCall: true,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// missed (neither accepted nor declined) incoming audio
|
|
callMode: CallMode.Direct,
|
|
wasDeclined: false,
|
|
wasIncoming: true,
|
|
wasVideoCall: false,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// missed (neither accepted nor declined) incoming video
|
|
callMode: CallMode.Direct,
|
|
wasDeclined: false,
|
|
wasIncoming: true,
|
|
wasVideoCall: true,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// accepted outgoing audio
|
|
callMode: CallMode.Direct,
|
|
acceptedTime: Date.now() - 200,
|
|
wasDeclined: false,
|
|
wasIncoming: false,
|
|
wasVideoCall: false,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// accepted outgoing video
|
|
callMode: CallMode.Direct,
|
|
acceptedTime: Date.now() - 200,
|
|
wasDeclined: false,
|
|
wasIncoming: false,
|
|
wasVideoCall: true,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// declined outgoing audio
|
|
callMode: CallMode.Direct,
|
|
wasDeclined: true,
|
|
wasIncoming: false,
|
|
wasVideoCall: false,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// declined outgoing video
|
|
callMode: CallMode.Direct,
|
|
wasDeclined: true,
|
|
wasIncoming: false,
|
|
wasVideoCall: true,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// unanswered (neither accepted nor declined) outgoing audio
|
|
callMode: CallMode.Direct,
|
|
wasDeclined: false,
|
|
wasIncoming: false,
|
|
wasVideoCall: false,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// unanswered (neither accepted nor declined) outgoing video
|
|
callMode: CallMode.Direct,
|
|
wasDeclined: false,
|
|
wasIncoming: false,
|
|
wasVideoCall: true,
|
|
endedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// ongoing group call
|
|
callMode: CallMode.Group,
|
|
conversationId: 'abc123',
|
|
creator: {
|
|
firstName: 'Luigi',
|
|
isMe: false,
|
|
title: 'Luigi Mario',
|
|
},
|
|
ended: false,
|
|
deviceCount: 1,
|
|
maxDevices: 16,
|
|
startedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// ongoing group call started by you
|
|
callMode: CallMode.Group,
|
|
conversationId: 'abc123',
|
|
creator: {
|
|
firstName: 'Peach',
|
|
isMe: true,
|
|
title: 'Princess Peach',
|
|
},
|
|
ended: false,
|
|
deviceCount: 1,
|
|
maxDevices: 16,
|
|
startedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// ongoing group call, creator unknown
|
|
callMode: CallMode.Group,
|
|
conversationId: 'abc123',
|
|
ended: false,
|
|
deviceCount: 1,
|
|
maxDevices: 16,
|
|
startedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// ongoing and active group call
|
|
callMode: CallMode.Group,
|
|
activeCallConversationId: 'abc123',
|
|
conversationId: 'abc123',
|
|
creator: {
|
|
firstName: 'Luigi',
|
|
isMe: false,
|
|
title: 'Luigi Mario',
|
|
},
|
|
ended: false,
|
|
deviceCount: 1,
|
|
maxDevices: 16,
|
|
startedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// ongoing group call, but you're in another one
|
|
callMode: CallMode.Group,
|
|
activeCallConversationId: 'abc123',
|
|
conversationId: 'xyz987',
|
|
creator: {
|
|
firstName: 'Luigi',
|
|
isMe: false,
|
|
title: 'Luigi Mario',
|
|
},
|
|
ended: false,
|
|
deviceCount: 1,
|
|
maxDevices: 16,
|
|
startedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// ongoing full group call
|
|
callMode: CallMode.Group,
|
|
conversationId: 'abc123',
|
|
creator: {
|
|
firstName: 'Luigi',
|
|
isMe: false,
|
|
title: 'Luigi Mario',
|
|
},
|
|
ended: false,
|
|
deviceCount: 16,
|
|
maxDevices: 16,
|
|
startedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'callHistory',
|
|
data: {
|
|
// finished call
|
|
callMode: CallMode.Group,
|
|
conversationId: 'abc123',
|
|
creator: {
|
|
firstName: 'Luigi',
|
|
isMe: false,
|
|
title: 'Luigi Mario',
|
|
},
|
|
ended: true,
|
|
deviceCount: 0,
|
|
maxDevices: 16,
|
|
startedTime: Date.now(),
|
|
},
|
|
},
|
|
{
|
|
type: 'profileChange',
|
|
data: {
|
|
change: {
|
|
type: 'name',
|
|
oldName: 'Fred',
|
|
newName: 'John',
|
|
},
|
|
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,
|
|
},
|
|
{
|
|
type: 'unsupportedMessage',
|
|
data: {
|
|
canProcessNow: true,
|
|
contact: getDefaultConversation(),
|
|
},
|
|
},
|
|
{
|
|
type: 'unsupportedMessage',
|
|
data: {
|
|
canProcessNow: false,
|
|
contact: getDefaultConversation(),
|
|
},
|
|
},
|
|
{
|
|
type: 'verificationNotification',
|
|
data: {
|
|
type: 'markVerified',
|
|
isLocal: false,
|
|
contact: getDefaultConversation(),
|
|
},
|
|
},
|
|
{
|
|
type: 'verificationNotification',
|
|
data: {
|
|
type: 'markVerified',
|
|
isLocal: true,
|
|
contact: getDefaultConversation(),
|
|
},
|
|
},
|
|
{
|
|
type: 'verificationNotification',
|
|
data: {
|
|
type: 'markNotVerified',
|
|
isLocal: false,
|
|
contact: getDefaultConversation(),
|
|
},
|
|
},
|
|
{
|
|
type: 'verificationNotification',
|
|
data: {
|
|
type: 'markNotVerified',
|
|
isLocal: true,
|
|
contact: getDefaultConversation(),
|
|
},
|
|
},
|
|
];
|
|
|
|
return (
|
|
<>
|
|
{items.map((item, index) => (
|
|
<React.Fragment key={index}>
|
|
<TimelineItem
|
|
{...getDefaultProps()}
|
|
item={item as TimelineItemProps['item']}
|
|
i18n={i18n}
|
|
/>
|
|
</React.Fragment>
|
|
))}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export function UnknownType(): JSX.Element {
|
|
const item = {
|
|
type: 'random',
|
|
data: {
|
|
somethin: 'somethin',
|
|
},
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
} as any as TimelineItemProps['item'];
|
|
|
|
return <TimelineItem {...getDefaultProps()} item={item} i18n={i18n} />;
|
|
}
|
|
|
|
export function MissingItem(): JSX.Element {
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const item = null as any as TimelineItemProps['item'];
|
|
|
|
return <TimelineItem {...getDefaultProps()} item={item} i18n={i18n} />;
|
|
}
|