signal-desktop/ts/components/conversation/Quote.stories.tsx

505 lines
12 KiB
TypeScript
Raw Normal View History

// Copyright 2020-2021 Signal Messenger, LLC
2020-10-30 20:34:04 +00:00
// SPDX-License-Identifier: AGPL-3.0-only
2020-08-27 17:02:25 +00:00
import * as React from 'react';
import { isString } from 'lodash';
2020-08-27 17:02:25 +00:00
import { action } from '@storybook/addon-actions';
import { boolean, text } from '@storybook/addon-knobs';
import { storiesOf } from '@storybook/react';
2021-05-28 16:15:17 +00:00
import { ConversationColors } from '../../types/Colors';
2020-08-27 17:02:25 +00:00
import { pngUrl } from '../../storybook/Fixtures';
import type { Props as MessagesProps } from './Message';
import { Message } from './Message';
import {
AUDIO_MP3,
IMAGE_PNG,
LONG_MESSAGE,
VIDEO_MP4,
2021-08-09 20:06:21 +00:00
stringToMIMEType,
} from '../../types/MIME';
import type { Props } from './Quote';
import { Quote } from './Quote';
import { ReadStatus } from '../../messages/MessageReadStatus';
2021-09-18 00:30:08 +00:00
import { setupI18n } from '../../util/setupI18n';
2020-08-27 17:02:25 +00:00
import enMessages from '../../../_locales/en/messages.json';
2021-05-07 22:21:10 +00:00
import { getDefaultConversation } from '../../test-both/helpers/getDefaultConversation';
import { WidthBreakpoint } from '../_util';
import { ThemeType } from '../../types/Util';
2020-09-14 19:51:27 +00:00
2020-08-27 17:02:25 +00:00
const i18n = setupI18n('en', enMessages);
const story = storiesOf('Components/Conversation/Quote', module);
const defaultMessageProps: MessagesProps = {
2021-05-07 22:21:10 +00:00
author: getDefaultConversation({
2021-04-27 19:55:21 +00:00
id: 'some-id',
title: 'Person X',
2021-05-07 22:21:10 +00:00
}),
canReact: true,
2020-08-27 17:02:25 +00:00
canReply: true,
canDeleteForEveryone: true,
canDownload: true,
checkForAccount: action('checkForAccount'),
clearSelectedMessage: action('default--clearSelectedMessage'),
containerElementRef: React.createRef<HTMLElement>(),
containerWidthBreakpoint: WidthBreakpoint.Wide,
2021-05-28 16:15:17 +00:00
conversationColor: 'crimson',
2020-08-27 17:02:25 +00:00
conversationId: 'conversationId',
conversationType: 'direct', // override
deleteMessage: action('default--deleteMessage'),
deleteMessageForEveryone: action('default--deleteMessageForEveryone'),
2020-08-27 17:02:25 +00:00
direction: 'incoming',
displayTapToViewMessage: action('default--displayTapToViewMessage'),
downloadAttachment: action('default--downloadAttachment'),
doubleCheckMissingQuoteReference: action(
'default--doubleCheckMissingQuoteReference'
),
2021-11-17 21:11:46 +00:00
getPreferredBadge: () => undefined,
2020-08-27 17:02:25 +00:00
i18n,
id: 'messageId',
renderingContext: 'storybook',
2020-08-27 17:02:25 +00:00
interactionMode: 'keyboard',
isBlocked: false,
isMessageRequestAccepted: true,
kickOffAttachmentDownload: action('default--kickOffAttachmentDownload'),
markAttachmentAsCorrupted: action('default--markAttachmentAsCorrupted'),
markViewed: action('default--markViewed'),
messageExpanded: action('dafult--message-expanded'),
onHeightChange: action('default--onHeightChange'),
openConversation: action('default--openConversation'),
openLink: action('default--openLink'),
2020-08-27 17:02:25 +00:00
previews: [],
reactToMessage: action('default--reactToMessage'),
readStatus: ReadStatus.Read,
2020-08-27 17:02:25 +00:00
renderEmojiPicker: () => <div />,
renderReactionPicker: () => <div />,
renderAudioAttachment: () => <div>*AudioAttachment*</div>,
replyToMessage: action('default--replyToMessage'),
retrySend: action('default--retrySend'),
scrollToQuotedMessage: action('default--scrollToQuotedMessage'),
selectMessage: action('default--selectMessage'),
showContactDetail: action('default--showContactDetail'),
showContactModal: action('default--showContactModal'),
showExpiredIncomingTapToViewToast: action(
'showExpiredIncomingTapToViewToast'
),
showExpiredOutgoingTapToViewToast: action(
'showExpiredOutgoingTapToViewToast'
),
showForwardMessageModal: action('default--showForwardMessageModal'),
showMessageDetail: action('default--showMessageDetail'),
showVisualAttachment: action('default--showVisualAttachment'),
2020-08-27 17:02:25 +00:00
status: 'sent',
text: 'This is really interesting.',
theme: ThemeType.light,
2020-08-27 17:02:25 +00:00
timestamp: Date.now(),
};
const renderInMessage = ({
authorTitle,
2021-05-28 16:15:17 +00:00
conversationColor,
2020-08-27 17:02:25 +00:00
isFromMe,
rawAttachment,
isViewOnce,
2020-08-27 17:02:25 +00:00
referencedMessageNotFound,
text: quoteText,
}: Props) => {
const messageProps = {
...defaultMessageProps,
2021-05-28 16:15:17 +00:00
conversationColor,
2020-08-27 17:02:25 +00:00
quote: {
authorId: 'an-author',
authorTitle,
2021-05-28 16:15:17 +00:00
conversationColor,
2020-08-27 17:02:25 +00:00
isFromMe,
rawAttachment,
isViewOnce,
2020-08-27 17:02:25 +00:00
referencedMessageNotFound,
sentAt: Date.now() - 30 * 1000,
text: quoteText,
},
};
return (
<div style={{ overflow: 'hidden' }}>
<Message {...messageProps} />
<br />
<Message {...messageProps} direction="outgoing" />
</div>
);
};
const createProps = (overrideProps: Partial<Props> = {}): Props => ({
authorTitle: text('authorTitle', overrideProps.authorTitle || ''),
2021-05-28 16:15:17 +00:00
conversationColor: overrideProps.conversationColor || 'forest',
doubleCheckMissingQuoteReference:
overrideProps.doubleCheckMissingQuoteReference ||
action('doubleCheckMissingQuoteReference'),
2020-08-27 17:02:25 +00:00
i18n,
isFromMe: boolean('isFromMe', overrideProps.isFromMe || false),
isIncoming: boolean('isIncoming', overrideProps.isIncoming || false),
onClick: action('onClick'),
onClose: action('onClose'),
rawAttachment: overrideProps.rawAttachment || undefined,
2020-08-27 17:02:25 +00:00
referencedMessageNotFound: boolean(
'referencedMessageNotFound',
overrideProps.referencedMessageNotFound || false
),
isViewOnce: boolean('isViewOnce', overrideProps.isViewOnce || false),
text: text(
'text',
isString(overrideProps.text)
? overrideProps.text
: 'A sample message from a pal'
),
2020-08-27 17:02:25 +00:00
});
story.add('Outgoing by Another Author', () => {
const props = createProps({
authorTitle: 'Terrence Malick',
});
return <Quote {...props} />;
});
story.add('Outgoing by Me', () => {
const props = createProps({
isFromMe: true,
});
return <Quote {...props} />;
});
story.add('Incoming by Another Author', () => {
const props = createProps({
authorTitle: 'Terrence Malick',
isIncoming: true,
});
return <Quote {...props} />;
});
story.add('Incoming by Me', () => {
const props = createProps({
isFromMe: true,
isIncoming: true,
});
return <Quote {...props} />;
});
story.add('Incoming/Outgoing Colors', () => {
const props = createProps({});
return (
<>
2021-05-28 16:15:17 +00:00
{ConversationColors.map(color =>
renderInMessage({ ...props, conversationColor: color })
)}
2020-08-27 17:02:25 +00:00
</>
);
});
story.add('Image Only', () => {
const props = createProps({
text: '',
rawAttachment: {
2020-08-27 17:02:25 +00:00
contentType: IMAGE_PNG,
fileName: 'sax.png',
isVoiceMessage: false,
thumbnail: {
contentType: IMAGE_PNG,
objectUrl: pngUrl,
},
},
});
return <Quote {...props} />;
});
story.add('Image Attachment', () => {
const props = createProps({
rawAttachment: {
2020-08-27 17:02:25 +00:00
contentType: IMAGE_PNG,
fileName: 'sax.png',
isVoiceMessage: false,
thumbnail: {
contentType: IMAGE_PNG,
objectUrl: pngUrl,
},
},
});
return <Quote {...props} />;
});
story.add('Image Attachment w/o Thumbnail', () => {
const props = createProps({
rawAttachment: {
2020-08-27 17:02:25 +00:00
contentType: IMAGE_PNG,
fileName: 'sax.png',
isVoiceMessage: false,
},
});
return <Quote {...props} />;
});
story.add('Image Tap-to-View', () => {
const props = createProps({
text: '',
isViewOnce: true,
rawAttachment: {
contentType: IMAGE_PNG,
fileName: 'sax.png',
isVoiceMessage: false,
},
});
return <Quote {...props} />;
});
2020-08-27 17:02:25 +00:00
story.add('Video Only', () => {
const props = createProps({
rawAttachment: {
2020-08-27 17:02:25 +00:00
contentType: VIDEO_MP4,
fileName: 'great-video.mp4',
isVoiceMessage: false,
thumbnail: {
contentType: IMAGE_PNG,
objectUrl: pngUrl,
},
},
});
2020-09-14 19:51:27 +00:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2020-08-27 17:02:25 +00:00
props.text = undefined as any;
return <Quote {...props} />;
});
story.add('Video Attachment', () => {
const props = createProps({
rawAttachment: {
2020-08-27 17:02:25 +00:00
contentType: VIDEO_MP4,
fileName: 'great-video.mp4',
isVoiceMessage: false,
thumbnail: {
contentType: IMAGE_PNG,
objectUrl: pngUrl,
},
},
});
return <Quote {...props} />;
});
story.add('Video Attachment w/o Thumbnail', () => {
const props = createProps({
rawAttachment: {
2020-08-27 17:02:25 +00:00
contentType: VIDEO_MP4,
fileName: 'great-video.mp4',
isVoiceMessage: false,
},
});
return <Quote {...props} />;
});
story.add('Video Tap-to-View', () => {
const props = createProps({
text: '',
isViewOnce: true,
rawAttachment: {
contentType: VIDEO_MP4,
fileName: 'great-video.mp4',
isVoiceMessage: false,
},
});
return <Quote {...props} />;
});
2020-08-27 17:02:25 +00:00
story.add('Audio Only', () => {
const props = createProps({
rawAttachment: {
2020-08-27 17:02:25 +00:00
contentType: AUDIO_MP3,
fileName: 'great-video.mp3',
isVoiceMessage: false,
},
});
2020-09-14 19:51:27 +00:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2020-08-27 17:02:25 +00:00
props.text = undefined as any;
return <Quote {...props} />;
});
story.add('Audio Attachment', () => {
const props = createProps({
rawAttachment: {
2020-08-27 17:02:25 +00:00
contentType: AUDIO_MP3,
fileName: 'great-video.mp3',
isVoiceMessage: false,
},
});
return <Quote {...props} />;
});
story.add('Voice Message Only', () => {
const props = createProps({
rawAttachment: {
2020-08-27 17:02:25 +00:00
contentType: AUDIO_MP3,
fileName: 'great-video.mp3',
isVoiceMessage: true,
},
});
2020-09-14 19:51:27 +00:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2020-08-27 17:02:25 +00:00
props.text = undefined as any;
return <Quote {...props} />;
});
story.add('Voice Message Attachment', () => {
const props = createProps({
rawAttachment: {
2020-08-27 17:02:25 +00:00
contentType: AUDIO_MP3,
fileName: 'great-video.mp3',
isVoiceMessage: true,
},
});
return <Quote {...props} />;
});
story.add('Other File Only', () => {
const props = createProps({
rawAttachment: {
2021-08-09 20:06:21 +00:00
contentType: stringToMIMEType('application/json'),
2020-08-27 17:02:25 +00:00
fileName: 'great-data.json',
isVoiceMessage: false,
},
});
2020-09-14 19:51:27 +00:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2020-08-27 17:02:25 +00:00
props.text = undefined as any;
return <Quote {...props} />;
});
story.add('Media Tap-to-View', () => {
const props = createProps({
text: '',
isViewOnce: true,
rawAttachment: {
contentType: AUDIO_MP3,
fileName: 'great-video.mp3',
isVoiceMessage: false,
},
});
return <Quote {...props} />;
});
2020-08-27 17:02:25 +00:00
story.add('Other File Attachment', () => {
const props = createProps({
rawAttachment: {
2021-08-09 20:06:21 +00:00
contentType: stringToMIMEType('application/json'),
2020-08-27 17:02:25 +00:00
fileName: 'great-data.json',
isVoiceMessage: false,
},
});
return <Quote {...props} />;
});
story.add('Long message attachment (should be hidden)', () => {
const props = createProps({
rawAttachment: {
contentType: LONG_MESSAGE,
fileName: 'signal-long-message-123.txt',
isVoiceMessage: false,
},
});
return <Quote {...props} />;
});
2020-08-27 17:02:25 +00:00
story.add('No Close Button', () => {
const props = createProps();
props.onClose = undefined;
return <Quote {...props} />;
});
story.add('Message Not Found', () => {
const props = createProps({
referencedMessageNotFound: true,
});
return renderInMessage(props);
});
story.add('Missing Text & Attachment', () => {
const props = createProps();
2020-09-14 19:51:27 +00:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2020-08-27 17:02:25 +00:00
props.text = undefined as any;
return <Quote {...props} />;
});
2020-09-16 22:42:48 +00:00
story.add('@mention + outgoing + another author', () => {
const props = createProps({
authorTitle: 'Tony Stark',
text: '@Captain America Lunch later?',
});
return <Quote {...props} />;
});
story.add('@mention + outgoing + me', () => {
const props = createProps({
isFromMe: true,
text: '@Captain America Lunch later?',
});
return <Quote {...props} />;
});
story.add('@mention + incoming + another author', () => {
const props = createProps({
authorTitle: 'Captain America',
isIncoming: true,
text: '@Tony Stark sure',
});
return <Quote {...props} />;
});
story.add('@mention + incoming + me', () => {
const props = createProps({
isFromMe: true,
isIncoming: true,
text: '@Tony Stark sure',
});
return <Quote {...props} />;
});
2021-05-28 16:15:17 +00:00
story.add('Custom Color', () => (
<>
<Quote
{...createProps({ isIncoming: true, text: 'Solid + Gradient' })}
customColor={{
start: { hue: 82, saturation: 35 },
}}
/>
<Quote
{...createProps()}
customColor={{
deg: 192,
start: { hue: 304, saturation: 85 },
end: { hue: 231, saturation: 76 },
}}
/>
</>
));