Migrate Timeline, TimelineLoadingRow to storybook
This commit is contained in:
parent
25dabd56fd
commit
1894ff0dc1
6 changed files with 396 additions and 388 deletions
|
@ -1,358 +0,0 @@
|
||||||
## With oldest and newest
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
window.itemLookup = {
|
|
||||||
'id-1': {
|
|
||||||
type: 'message',
|
|
||||||
data: {
|
|
||||||
id: 'id-1',
|
|
||||||
direction: 'incoming',
|
|
||||||
timestamp: Date.now(),
|
|
||||||
authorPhoneNumber: '(202) 555-2001',
|
|
||||||
authorColor: 'green',
|
|
||||||
text: '🔥',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-2': {
|
|
||||||
type: 'message',
|
|
||||||
data: {
|
|
||||||
id: 'id-2',
|
|
||||||
conversationType: 'group',
|
|
||||||
direction: 'incoming',
|
|
||||||
timestamp: Date.now(),
|
|
||||||
authorColor: 'green',
|
|
||||||
text: 'Hello there from the new world! http://somewhere.com',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-2.5': {
|
|
||||||
type: 'unsupportedMessage',
|
|
||||||
data: {
|
|
||||||
id: 'id-2.5',
|
|
||||||
canProcessNow: false,
|
|
||||||
contact: {
|
|
||||||
phoneNumber: '(202) 555-1000',
|
|
||||||
profileName: 'Mr. Pig',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-3': {
|
|
||||||
type: 'message',
|
|
||||||
data: {
|
|
||||||
id: 'id-3',
|
|
||||||
collapseMetadata: true,
|
|
||||||
direction: 'incoming',
|
|
||||||
timestamp: Date.now(),
|
|
||||||
authorColor: 'red',
|
|
||||||
text: 'Hello there from the new world!',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-4': {
|
|
||||||
type: 'timerNotification',
|
|
||||||
data: {
|
|
||||||
type: 'fromMe',
|
|
||||||
timespan: '5 minutes',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-5': {
|
|
||||||
type: 'timerNotification',
|
|
||||||
data: {
|
|
||||||
type: 'fromOther',
|
|
||||||
phoneNumber: '(202) 555-0000',
|
|
||||||
timespan: '1 hour',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-6': {
|
|
||||||
type: 'safetyNumberNotification',
|
|
||||||
data: {
|
|
||||||
contact: {
|
|
||||||
id: '+1202555000',
|
|
||||||
phoneNumber: '(202) 555-0000',
|
|
||||||
profileName: 'Mr. Fire',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-7': {
|
|
||||||
type: 'verificationNotification',
|
|
||||||
data: {
|
|
||||||
contact: {
|
|
||||||
phoneNumber: '(202) 555-0001',
|
|
||||||
name: 'Mrs. Ice',
|
|
||||||
},
|
|
||||||
isLocal: true,
|
|
||||||
type: 'markVerified',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-8': {
|
|
||||||
type: 'groupNotification',
|
|
||||||
data: {
|
|
||||||
changes: [
|
|
||||||
{
|
|
||||||
type: 'name',
|
|
||||||
newName: 'Squirrels and their uses',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'add',
|
|
||||||
contacts: [
|
|
||||||
{
|
|
||||||
phoneNumber: '(202) 555-0002',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
phoneNumber: '(202) 555-0003',
|
|
||||||
profileName: 'Ms. Water',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
isMe: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-9': {
|
|
||||||
type: 'resetSessionNotification',
|
|
||||||
data: null,
|
|
||||||
},
|
|
||||||
'id-10': {
|
|
||||||
type: 'message',
|
|
||||||
data: {
|
|
||||||
id: 'id-6',
|
|
||||||
direction: 'outgoing',
|
|
||||||
timestamp: Date.now(),
|
|
||||||
status: 'sent',
|
|
||||||
authorColor: 'pink',
|
|
||||||
text: '🔥',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-11': {
|
|
||||||
type: 'message',
|
|
||||||
data: {
|
|
||||||
id: 'id-7',
|
|
||||||
direction: 'outgoing',
|
|
||||||
timestamp: Date.now(),
|
|
||||||
status: 'read',
|
|
||||||
authorColor: 'pink',
|
|
||||||
text: 'Hello there from the new world! http://somewhere.com',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-12': {
|
|
||||||
type: 'message',
|
|
||||||
data: {
|
|
||||||
id: 'id-8',
|
|
||||||
collapseMetadata: true,
|
|
||||||
direction: 'outgoing',
|
|
||||||
status: 'sent',
|
|
||||||
timestamp: Date.now(),
|
|
||||||
text: 'Hello there from the new world! 🔥',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-13': {
|
|
||||||
type: 'message',
|
|
||||||
data: {
|
|
||||||
id: 'id-9',
|
|
||||||
direction: 'outgoing',
|
|
||||||
status: 'sent',
|
|
||||||
timestamp: Date.now(),
|
|
||||||
authorColor: 'blue',
|
|
||||||
text:
|
|
||||||
'Hello there from the new world! And this is multiple lines of text. Lines and lines and lines.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-14': {
|
|
||||||
type: 'message',
|
|
||||||
data: {
|
|
||||||
id: 'id-10',
|
|
||||||
direction: 'outgoing',
|
|
||||||
status: 'read',
|
|
||||||
timestamp: Date.now(),
|
|
||||||
collapseMetadata: true,
|
|
||||||
text:
|
|
||||||
'Hello there from the new world! And this is multiple lines of text. Lines and lines and lines.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'id-15': {
|
|
||||||
type: 'linkNotification',
|
|
||||||
data: null,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
window.actions = {
|
|
||||||
// For messages
|
|
||||||
downloadAttachment: options => console.log('onDownload', options),
|
|
||||||
replyToitem: id => console.log('onReply', id),
|
|
||||||
showMessageDetail: id => console.log('onShowDetail', id),
|
|
||||||
deleteMessage: id => console.log('onDelete', id),
|
|
||||||
downloadNewVersion: () => console.log('downloadNewVersion'),
|
|
||||||
|
|
||||||
// For Timeline
|
|
||||||
clearChangedMessages: (...args) => console.log('clearChangedMessages', args),
|
|
||||||
setLoadCountdownStart: (...args) =>
|
|
||||||
console.log('setLoadCountdownStart', args),
|
|
||||||
|
|
||||||
loadAndScroll: (...args) => console.log('loadAndScroll', args),
|
|
||||||
loadOlderMessages: (...args) => console.log('loadOlderMessages', args),
|
|
||||||
loadNewerMessages: (...args) => console.log('loadNewerMessages', args),
|
|
||||||
loadNewestMessages: (...args) => console.log('loadNewestMessages', args),
|
|
||||||
markMessageRead: (...args) => console.log('markMessageRead', args),
|
|
||||||
};
|
|
||||||
|
|
||||||
const props = {
|
|
||||||
id: 'conversationId-1',
|
|
||||||
haveNewest: true,
|
|
||||||
haveOldest: true,
|
|
||||||
isLoadingMessages: false,
|
|
||||||
items: util._.keys(window.itemLookup),
|
|
||||||
messagesHaveChanged: false,
|
|
||||||
oldestUnreadIndex: null,
|
|
||||||
resetCounter: 0,
|
|
||||||
scrollToIndex: null,
|
|
||||||
scrollToIndexCounter: 0,
|
|
||||||
totalUnread: 0,
|
|
||||||
|
|
||||||
renderItem: id => (
|
|
||||||
<TimelineItem item={window.itemLookup[id]} i18n={util.i18n} {...actions} />
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
<div style={{ height: '300px' }}>
|
|
||||||
<Timeline {...props} {...window.actions} i18n={util.i18n} />
|
|
||||||
</div>;
|
|
||||||
```
|
|
||||||
|
|
||||||
## With last seen indicator
|
|
||||||
|
|
||||||
```
|
|
||||||
const props = {
|
|
||||||
id: 'conversationId-1',
|
|
||||||
haveNewest: true,
|
|
||||||
haveOldest: true,
|
|
||||||
isLoadingMessages: false,
|
|
||||||
items: util._.keys(window.itemLookup),
|
|
||||||
messagesHaveChanged: false,
|
|
||||||
oldestUnreadIndex: 2,
|
|
||||||
resetCounter: 0,
|
|
||||||
scrollToIndex: null,
|
|
||||||
scrollToIndexCounter: 0,
|
|
||||||
totalUnread: 2,
|
|
||||||
|
|
||||||
renderItem: id => (
|
|
||||||
<TimelineItem item={window.itemLookup[id]} i18n={util.i18n} {...actions} />
|
|
||||||
),
|
|
||||||
renderLastSeenIndicator: () => (
|
|
||||||
<LastSeenIndicator count={2} i18n={util.i18n} />
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
<div style={{ height: '300px' }}>
|
|
||||||
<Timeline {...props} {...window.actions} i18n={util.i18n} />
|
|
||||||
</div>;
|
|
||||||
```
|
|
||||||
|
|
||||||
## With target index = 0
|
|
||||||
|
|
||||||
```
|
|
||||||
const props = {
|
|
||||||
id: 'conversationId-1',
|
|
||||||
haveNewest: true,
|
|
||||||
haveOldest: true,
|
|
||||||
isLoadingMessages: false,
|
|
||||||
items: util._.keys(window.itemLookup),
|
|
||||||
messagesHaveChanged: false,
|
|
||||||
oldestUnreadIndex: null,
|
|
||||||
resetCounter: 0,
|
|
||||||
scrollToIndex: 0,
|
|
||||||
scrollToIndexCounter: 0,
|
|
||||||
totalUnread: 0,
|
|
||||||
|
|
||||||
renderItem: id => (
|
|
||||||
<TimelineItem item={window.itemLookup[id]} i18n={util.i18n} {...actions} />
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
<div style={{ height: '300px' }}>
|
|
||||||
<Timeline {...props} {...window.actions} i18n={util.i18n} />
|
|
||||||
</div>;
|
|
||||||
```
|
|
||||||
|
|
||||||
## With typing indicator
|
|
||||||
|
|
||||||
```
|
|
||||||
const props = {
|
|
||||||
id: 'conversationId-1',
|
|
||||||
haveNewest: true,
|
|
||||||
haveOldest: true,
|
|
||||||
isLoadingMessages: false,
|
|
||||||
items: util._.keys(window.itemLookup),
|
|
||||||
messagesHaveChanged: false,
|
|
||||||
oldestUnreadIndex: null,
|
|
||||||
resetCounter: 0,
|
|
||||||
scrollToIndex: null,
|
|
||||||
scrollToIndexCounter: 0,
|
|
||||||
totalUnread: 0,
|
|
||||||
|
|
||||||
typingContact: true,
|
|
||||||
|
|
||||||
renderItem: id => (
|
|
||||||
<TimelineItem item={window.itemLookup[id]} i18n={util.i18n} {...actions} />
|
|
||||||
),
|
|
||||||
renderTypingBubble: () => (
|
|
||||||
<TypingBubble color="red" conversationType="direct" phoneNumber="+18005552222" i18n={util.i18n} />
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
<div style={{ height: '300px' }}>
|
|
||||||
<Timeline {...props} {...window.actions} i18n={util.i18n} />
|
|
||||||
</div>;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Without newest message
|
|
||||||
|
|
||||||
```
|
|
||||||
const props = {
|
|
||||||
id: 'conversationId-1',
|
|
||||||
haveNewest: false,
|
|
||||||
haveOldest: true,
|
|
||||||
isLoadingMessages: false,
|
|
||||||
items: util._.keys(window.itemLookup),
|
|
||||||
messagesHaveChanged: false,
|
|
||||||
oldestUnreadIndex: null,
|
|
||||||
resetCounter: 0,
|
|
||||||
scrollToIndex: 3,
|
|
||||||
scrollToIndexCounter: 0,
|
|
||||||
totalUnread: 0,
|
|
||||||
|
|
||||||
renderItem: id => (
|
|
||||||
<TimelineItem item={window.itemLookup[id]} i18n={util.i18n} {...actions} />
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
<div style={{ height: '300px' }}>
|
|
||||||
<Timeline {...props} {...window.actions} i18n={util.i18n} />
|
|
||||||
</div>;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Without oldest message
|
|
||||||
|
|
||||||
```
|
|
||||||
const props = {
|
|
||||||
id: 'conversationId-1',
|
|
||||||
haveNewest: true,
|
|
||||||
haveOldest: false,
|
|
||||||
isLoadingMessages: false,
|
|
||||||
items: util._.keys(window.itemLookup),
|
|
||||||
messagesHaveChanged: false,
|
|
||||||
oldestUnreadIndex: null,
|
|
||||||
resetCounter: 0,
|
|
||||||
scrollToIndex: null,
|
|
||||||
scrollToIndexCounter: 0,
|
|
||||||
totalUnread: 0,
|
|
||||||
|
|
||||||
renderItem: id => (
|
|
||||||
<TimelineItem item={window.itemLookup[id]} i18n={util.i18n} {...actions} />
|
|
||||||
),
|
|
||||||
renderLoadingRow: () => (
|
|
||||||
<TimelineLoadingRow state="idle" />
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
<div style={{ height: '300px' }}>
|
|
||||||
<Timeline {...props} {...window.actions} i18n={util.i18n} />
|
|
||||||
</div>;
|
|
||||||
```
|
|
353
ts/components/conversation/Timeline.stories.tsx
Normal file
353
ts/components/conversation/Timeline.stories.tsx
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { storiesOf } from '@storybook/react';
|
||||||
|
import { boolean, number } from '@storybook/addon-knobs';
|
||||||
|
import { action } from '@storybook/addon-actions';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { setup as setupI18n } from '../../../js/modules/i18n';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import enMessages from '../../../_locales/en/messages.json';
|
||||||
|
|
||||||
|
import { Props, Timeline } from './Timeline';
|
||||||
|
import { TimelineItem, TimelineItemType } from './TimelineItem';
|
||||||
|
import { LastSeenIndicator } from './LastSeenIndicator';
|
||||||
|
import { TimelineLoadingRow } from './TimelineLoadingRow';
|
||||||
|
import { TypingBubble } from './TypingBubble';
|
||||||
|
|
||||||
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
|
const story = storiesOf('Components/Conversation/Timeline', module);
|
||||||
|
|
||||||
|
// tslint:disable-next-line
|
||||||
|
const noop = () => {};
|
||||||
|
|
||||||
|
Object.assign(window, {
|
||||||
|
registerForActive: noop,
|
||||||
|
unregisterForActive: noop,
|
||||||
|
});
|
||||||
|
|
||||||
|
const items: Record<string, TimelineItemType> = {
|
||||||
|
'id-1': {
|
||||||
|
type: 'message',
|
||||||
|
data: {
|
||||||
|
id: 'id-1',
|
||||||
|
direction: 'incoming',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
authorPhoneNumber: '(202) 555-2001',
|
||||||
|
authorColor: 'green',
|
||||||
|
text: '🔥',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-2': {
|
||||||
|
type: 'message',
|
||||||
|
data: {
|
||||||
|
id: 'id-2',
|
||||||
|
conversationType: 'group',
|
||||||
|
direction: 'incoming',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
authorColor: 'green',
|
||||||
|
text: 'Hello there from the new world! http://somewhere.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-2.5': {
|
||||||
|
type: 'unsupportedMessage',
|
||||||
|
data: {
|
||||||
|
id: 'id-2.5',
|
||||||
|
canProcessNow: false,
|
||||||
|
contact: {
|
||||||
|
phoneNumber: '(202) 555-1000',
|
||||||
|
profileName: 'Mr. Pig',
|
||||||
|
title: 'Mr. Pig',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-3': {
|
||||||
|
type: 'message',
|
||||||
|
data: {
|
||||||
|
id: 'id-3',
|
||||||
|
collapseMetadata: true,
|
||||||
|
direction: 'incoming',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
authorColor: 'red',
|
||||||
|
text: 'Hello there from the new world!',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-4': {
|
||||||
|
type: 'timerNotification',
|
||||||
|
data: {
|
||||||
|
type: 'fromMe',
|
||||||
|
timespan: '5 minutes',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-5': {
|
||||||
|
type: 'timerNotification',
|
||||||
|
data: {
|
||||||
|
type: 'fromOther',
|
||||||
|
title: '(202) 555-0000',
|
||||||
|
phoneNumber: '(202) 555-0000',
|
||||||
|
timespan: '1 hour',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-6': {
|
||||||
|
type: 'safetyNumberNotification',
|
||||||
|
data: {
|
||||||
|
contact: {
|
||||||
|
id: '+1202555000',
|
||||||
|
phoneNumber: '(202) 555-0000',
|
||||||
|
profileName: 'Mr. Fire',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-7': {
|
||||||
|
type: 'verificationNotification',
|
||||||
|
data: {
|
||||||
|
contact: {
|
||||||
|
phoneNumber: '(202) 555-0001',
|
||||||
|
name: 'Mrs. Ice',
|
||||||
|
},
|
||||||
|
isLocal: true,
|
||||||
|
type: 'markVerified',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-8': {
|
||||||
|
type: 'groupNotification',
|
||||||
|
data: {
|
||||||
|
changes: [
|
||||||
|
{
|
||||||
|
type: 'name',
|
||||||
|
newName: 'Squirrels and their uses',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'add',
|
||||||
|
contacts: [
|
||||||
|
{
|
||||||
|
phoneNumber: '(202) 555-0002',
|
||||||
|
profileName: 'Mr. Fire',
|
||||||
|
title: 'Mr. Fire',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
phoneNumber: '(202) 555-0003',
|
||||||
|
profileName: 'Ms. Water',
|
||||||
|
title: 'Ms. Water',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
from: {
|
||||||
|
phoneNumber: '(202) 555-0001',
|
||||||
|
name: 'Mrs. Ice',
|
||||||
|
title: 'Mrs. Ice',
|
||||||
|
},
|
||||||
|
isMe: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-9': {
|
||||||
|
type: 'resetSessionNotification',
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
'id-10': {
|
||||||
|
type: 'message',
|
||||||
|
data: {
|
||||||
|
id: 'id-6',
|
||||||
|
direction: 'outgoing',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
status: 'sent',
|
||||||
|
authorColor: 'pink',
|
||||||
|
text: '🔥',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-11': {
|
||||||
|
type: 'message',
|
||||||
|
data: {
|
||||||
|
id: 'id-7',
|
||||||
|
direction: 'outgoing',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
status: 'read',
|
||||||
|
authorColor: 'pink',
|
||||||
|
text: 'Hello there from the new world! http://somewhere.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-12': {
|
||||||
|
type: 'message',
|
||||||
|
data: {
|
||||||
|
id: 'id-8',
|
||||||
|
collapseMetadata: true,
|
||||||
|
direction: 'outgoing',
|
||||||
|
status: 'sent',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
text: 'Hello there from the new world! 🔥',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-13': {
|
||||||
|
type: 'message',
|
||||||
|
data: {
|
||||||
|
id: 'id-9',
|
||||||
|
direction: 'outgoing',
|
||||||
|
status: 'sent',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
authorColor: 'blue',
|
||||||
|
text:
|
||||||
|
'Hello there from the new world! And this is multiple lines of text. Lines and lines and lines.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-14': {
|
||||||
|
type: 'message',
|
||||||
|
data: {
|
||||||
|
id: 'id-10',
|
||||||
|
direction: 'outgoing',
|
||||||
|
status: 'read',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
collapseMetadata: true,
|
||||||
|
text:
|
||||||
|
'Hello there from the new world! And this is multiple lines of text. Lines and lines and lines.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'id-15': {
|
||||||
|
type: 'linkNotification',
|
||||||
|
data: null,
|
||||||
|
},
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const actions = () => ({
|
||||||
|
clearChangedMessages: action('clearChangedMessages'),
|
||||||
|
setLoadCountdownStart: action('setLoadCountdownStart'),
|
||||||
|
setIsNearBottom: action('setIsNearBottom'),
|
||||||
|
loadAndScroll: action('loadAndScroll'),
|
||||||
|
loadOlderMessages: action('loadOlderMessages'),
|
||||||
|
loadNewerMessages: action('loadNewerMessages'),
|
||||||
|
loadNewestMessages: action('loadNewestMessages'),
|
||||||
|
markMessageRead: action('markMessageRead'),
|
||||||
|
selectMessage: action('selectMessage'),
|
||||||
|
clearSelectedMessage: action('clearSelectedMessage'),
|
||||||
|
updateSharedGroups: action('updateSharedGroups'),
|
||||||
|
|
||||||
|
reactToMessage: action('reactToMessage'),
|
||||||
|
replyToMessage: action('replyToMessage'),
|
||||||
|
retrySend: action('retrySend'),
|
||||||
|
deleteMessage: action('deleteMessage'),
|
||||||
|
showMessageDetail: action('showMessageDetail'),
|
||||||
|
openConversation: action('openConversation'),
|
||||||
|
showContactDetail: action('showContactDetail'),
|
||||||
|
showVisualAttachment: action('showVisualAttachment'),
|
||||||
|
downloadAttachment: action('downloadAttachment'),
|
||||||
|
displayTapToViewMessage: action('displayTapToViewMessage'),
|
||||||
|
|
||||||
|
openLink: action('openLink'),
|
||||||
|
scrollToQuotedMessage: action('scrollToQuotedMessage'),
|
||||||
|
showExpiredIncomingTapToViewToast: action(
|
||||||
|
'showExpiredIncomingTapToViewToast'
|
||||||
|
),
|
||||||
|
showExpiredOutgoingTapToViewToast: action(
|
||||||
|
'showExpiredOutgoingTapToViewToast'
|
||||||
|
),
|
||||||
|
|
||||||
|
showIdentity: action('showIdentity'),
|
||||||
|
|
||||||
|
downloadNewVersion: action('downloadNewVersion'),
|
||||||
|
});
|
||||||
|
|
||||||
|
const renderItem = (id: string) => (
|
||||||
|
<TimelineItem
|
||||||
|
id=""
|
||||||
|
isSelected={false}
|
||||||
|
renderEmojiPicker={() => <div />}
|
||||||
|
item={items[id]}
|
||||||
|
i18n={i18n}
|
||||||
|
conversationId=""
|
||||||
|
conversationAccepted
|
||||||
|
{...actions()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderLastSeenIndicator = () => (
|
||||||
|
<LastSeenIndicator count={2} i18n={i18n} />
|
||||||
|
);
|
||||||
|
const renderHeroRow = () => <div />;
|
||||||
|
const renderLoadingRow = () => <TimelineLoadingRow state="loading" />;
|
||||||
|
const renderTypingBubble = () => (
|
||||||
|
<TypingBubble
|
||||||
|
color="red"
|
||||||
|
conversationType="direct"
|
||||||
|
phoneNumber="+18005552222"
|
||||||
|
i18n={i18n}
|
||||||
|
title="title"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||||
|
i18n,
|
||||||
|
|
||||||
|
haveNewest: boolean('haveNewest', overrideProps.haveNewest !== false),
|
||||||
|
haveOldest: boolean('haveOldest', overrideProps.haveOldest !== false),
|
||||||
|
isLoadingMessages: false,
|
||||||
|
items: Object.keys(items),
|
||||||
|
resetCounter: 0,
|
||||||
|
scrollToIndex: overrideProps.scrollToIndex,
|
||||||
|
scrollToIndexCounter: 0,
|
||||||
|
totalUnread: number('totalUnread', overrideProps.totalUnread || 0),
|
||||||
|
oldestUnreadIndex:
|
||||||
|
number('oldestUnreadIndex', overrideProps.oldestUnreadIndex || 0) ||
|
||||||
|
undefined,
|
||||||
|
|
||||||
|
id: '',
|
||||||
|
renderItem,
|
||||||
|
renderLastSeenIndicator,
|
||||||
|
renderHeroRow,
|
||||||
|
renderLoadingRow,
|
||||||
|
renderTypingBubble,
|
||||||
|
typingContact: boolean(
|
||||||
|
'typingContact',
|
||||||
|
!!overrideProps.typingContact || false
|
||||||
|
),
|
||||||
|
|
||||||
|
...actions(),
|
||||||
|
});
|
||||||
|
|
||||||
|
story.add('Oldest and Newest', () => {
|
||||||
|
const props = createProps();
|
||||||
|
|
||||||
|
return <Timeline {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
story.add('Last Seen', () => {
|
||||||
|
const props = createProps({
|
||||||
|
oldestUnreadIndex: 13,
|
||||||
|
totalUnread: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
return <Timeline {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
story.add('Target Index to Top', () => {
|
||||||
|
const props = createProps({
|
||||||
|
scrollToIndex: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
return <Timeline {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
story.add('Typing Indicator', () => {
|
||||||
|
const props = createProps({
|
||||||
|
typingContact: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return <Timeline {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
story.add('Without Newest Message', () => {
|
||||||
|
const props = createProps({
|
||||||
|
haveNewest: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return <Timeline {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
story.add('Without Oldest Message', () => {
|
||||||
|
const props = createProps({
|
||||||
|
haveOldest: false,
|
||||||
|
scrollToIndex: -1,
|
||||||
|
});
|
||||||
|
|
||||||
|
return <Timeline {...props} />;
|
||||||
|
});
|
|
@ -78,7 +78,7 @@ type PropsActionsType = {
|
||||||
} & MessageActionsType &
|
} & MessageActionsType &
|
||||||
SafetyNumberActionsType;
|
SafetyNumberActionsType;
|
||||||
|
|
||||||
type Props = PropsDataType & PropsHousekeepingType & PropsActionsType;
|
export type Props = PropsDataType & PropsHousekeepingType & PropsActionsType;
|
||||||
|
|
||||||
// from https://github.com/bvaughn/react-virtualized/blob/fb3484ed5dcc41bffae8eab029126c0fb8f7abc0/source/List/types.js#L5
|
// from https://github.com/bvaughn/react-virtualized/blob/fb3484ed5dcc41bffae8eab029126c0fb8f7abc0/source/List/types.js#L5
|
||||||
type RowRendererParamsType = {
|
type RowRendererParamsType = {
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
### Idle
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
|
||||||
<TimelineLoadingRow state="idle" />
|
|
||||||
</util.ConversationContext>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Countdown
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
|
||||||
<TimelineLoadingRow
|
|
||||||
state="countdown"
|
|
||||||
duration={30000}
|
|
||||||
expiresAt={Date.now() + 20000}
|
|
||||||
onComplete={() => console.log('onComplete')}
|
|
||||||
/>
|
|
||||||
</util.ConversationContext>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Loading
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
<util.ConversationContext theme={util.theme} ios={util.ios}>
|
|
||||||
<TimelineLoadingRow state="loading" />
|
|
||||||
</util.ConversationContext>
|
|
||||||
```
|
|
41
ts/components/conversation/TimelineLoadingRow.stories.tsx
Normal file
41
ts/components/conversation/TimelineLoadingRow.stories.tsx
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { storiesOf } from '@storybook/react';
|
||||||
|
import { date, number, select } from '@storybook/addon-knobs';
|
||||||
|
import { action } from '@storybook/addon-actions';
|
||||||
|
|
||||||
|
import { Props, TimelineLoadingRow } from './TimelineLoadingRow';
|
||||||
|
|
||||||
|
const story = storiesOf('Components/Conversation/TimelineLoadingRow', module);
|
||||||
|
|
||||||
|
const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||||
|
state: select(
|
||||||
|
'state',
|
||||||
|
{ idle: 'idle', countdown: 'countdown', loading: 'loading' },
|
||||||
|
overrideProps.state || 'idle'
|
||||||
|
),
|
||||||
|
duration: number('duration', overrideProps.duration || 0),
|
||||||
|
expiresAt: date('expiresAt', new Date(overrideProps.expiresAt || Date.now())),
|
||||||
|
onComplete: action('onComplete'),
|
||||||
|
});
|
||||||
|
|
||||||
|
story.add('Idle', () => {
|
||||||
|
const props = createProps();
|
||||||
|
|
||||||
|
return <TimelineLoadingRow {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
story.add('Countdown', () => {
|
||||||
|
const props = createProps({
|
||||||
|
state: 'countdown',
|
||||||
|
duration: 40000,
|
||||||
|
expiresAt: Date.now() + 20000,
|
||||||
|
});
|
||||||
|
|
||||||
|
return <TimelineLoadingRow {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
story.add('Loading', () => {
|
||||||
|
const props = createProps({ state: 'loading' });
|
||||||
|
|
||||||
|
return <TimelineLoadingRow {...props} />;
|
||||||
|
});
|
|
@ -6,7 +6,7 @@ import { Spinner } from '../Spinner';
|
||||||
|
|
||||||
export type STATE_ENUM = 'idle' | 'countdown' | 'loading';
|
export type STATE_ENUM = 'idle' | 'countdown' | 'loading';
|
||||||
|
|
||||||
type Props = {
|
export type Props = {
|
||||||
state: STATE_ENUM;
|
state: STATE_ENUM;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
expiresAt?: number;
|
expiresAt?: number;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue