Sort by inbox position to match phone after link
This commit is contained in:
parent
1f5cb9e8af
commit
4830213a12
25 changed files with 707 additions and 1029 deletions
|
@ -1,983 +0,0 @@
|
|||
#### With all result types
|
||||
|
||||
```jsx
|
||||
const items = [
|
||||
{
|
||||
type: 'conversations-header',
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: 'conversation',
|
||||
data: {
|
||||
name: 'Everyone 🌆',
|
||||
conversationType: 'group',
|
||||
phoneNumber: '(202) 555-0011',
|
||||
avatarPath: util.landscapeGreenObjectUrl,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
lastMessage: {
|
||||
text: 'The rabbit hopped silently in the night.',
|
||||
status: 'sent',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'conversation',
|
||||
data: {
|
||||
name: 'Everyone Else 🔥',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0012',
|
||||
avatarPath: util.landscapePurpleObjectUrl,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
lastMessage: {
|
||||
text: "What's going on?",
|
||||
status: 'sent',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'contacts-header',
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: 'contact',
|
||||
data: {
|
||||
name: 'The one Everyone',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0013',
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'contact',
|
||||
data: {
|
||||
name: 'No likey everyone',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0014',
|
||||
color: 'red',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'messages-header',
|
||||
data: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
const messages = [
|
||||
{
|
||||
from: {
|
||||
isMe: true,
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: 'Mr. Fire 🔥',
|
||||
phoneNumber: '(202) 555-0015',
|
||||
},
|
||||
id: '1-guid-guid-guid-guid-guid',
|
||||
conversationId: '(202) 555-0015',
|
||||
receivedAt: Date.now() - 5 * 60 * 1000,
|
||||
snippet: '<<left>>Everyone<<right>>! Get in!',
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
name: 'Jon ❄️',
|
||||
phoneNumber: '(202) 555-0016',
|
||||
color: 'green',
|
||||
},
|
||||
to: {
|
||||
isMe: true,
|
||||
},
|
||||
id: '2-guid-guid-guid-guid-guid',
|
||||
conversationId: '(202) 555-0016',
|
||||
snippet: 'Why is <<left>>everyone<<right>> so frustrated?',
|
||||
receivedAt: Date.now() - 20 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
name: 'Someone',
|
||||
phoneNumber: '(202) 555-0011',
|
||||
color: 'green',
|
||||
avatarPath: util.pngObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: "Y'all 🌆",
|
||||
},
|
||||
id: '3-guid-guid-guid-guid-guid',
|
||||
conversationId: 'EveryoneGroupID',
|
||||
snippet: 'Hello, <<left>>everyone<<right>>! Woohooo!',
|
||||
receivedAt: Date.now() - 24 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
isMe: true,
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: "Y'all 🌆",
|
||||
},
|
||||
id: '4-guid-guid-guid-guid-guid',
|
||||
conversationId: 'EveryoneGroupID',
|
||||
snippet: 'Well, <<left>>everyone<<right>>, happy new year!',
|
||||
receivedAt: Date.now() - 24 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
];
|
||||
|
||||
const messageLookup = util._.fromPairs(
|
||||
util._.map(messages, message => [message.id, message])
|
||||
);
|
||||
messages.forEach(message => {
|
||||
items.push({
|
||||
type: 'message',
|
||||
data: message.id,
|
||||
});
|
||||
});
|
||||
|
||||
<util.LeftPaneContext
|
||||
theme={util.theme}
|
||||
gutterStyle={{ height: '500px', display: 'flex', flexDirection: 'row' }}
|
||||
>
|
||||
<SearchResults
|
||||
items={items}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
startNewConversation={(...args) =>
|
||||
console.log('startNewConversation', args)
|
||||
}
|
||||
onStartNewConversation={(...args) =>
|
||||
console.log('onStartNewConversation', args)
|
||||
}
|
||||
renderMessageSearchResult={id => (
|
||||
<MessageSearchResult
|
||||
{...messageLookup[id]}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</util.LeftPaneContext>;
|
||||
```
|
||||
|
||||
#### With 'start new conversation'
|
||||
|
||||
```jsx
|
||||
const items = [
|
||||
{
|
||||
type: 'start-new-conversation',
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: 'conversations-header',
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: 'conversation',
|
||||
data: {
|
||||
name: 'Everyone 🌆',
|
||||
conversationType: 'group',
|
||||
phoneNumber: '(202) 555-0011',
|
||||
avatarPath: util.landscapeGreenObjectUrl,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
lastMessage: {
|
||||
text: 'The rabbit hopped silently in the night.',
|
||||
status: 'sent',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'conversation',
|
||||
data: {
|
||||
name: 'Everyone Else 🔥',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0012',
|
||||
avatarPath: util.landscapePurpleObjectUrl,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
lastMessage: {
|
||||
text: "What's going on?",
|
||||
status: 'sent',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'contacts-header',
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: 'contact',
|
||||
data: {
|
||||
name: 'The one Everyone',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0013',
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'contact',
|
||||
data: {
|
||||
name: 'No likey everyone',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0014',
|
||||
color: 'red',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'messages-header',
|
||||
data: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
const messages = [
|
||||
{
|
||||
from: {
|
||||
isMe: true,
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: 'Mr. Fire 🔥',
|
||||
phoneNumber: '(202) 555-0015',
|
||||
},
|
||||
id: '1-guid-guid-guid-guid-guid',
|
||||
conversationId: '(202) 555-0015',
|
||||
receivedAt: Date.now() - 5 * 60 * 1000,
|
||||
snippet: '<<left>>Everyone<<right>>! Get in!',
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
name: 'Jon ❄️',
|
||||
phoneNumber: '(202) 555-0016',
|
||||
color: 'green',
|
||||
},
|
||||
to: {
|
||||
isMe: true,
|
||||
},
|
||||
id: '2-guid-guid-guid-guid-guid',
|
||||
conversationId: '(202) 555-0016',
|
||||
snippet: 'Why is <<left>>everyone<<right>> so frustrated?',
|
||||
receivedAt: Date.now() - 20 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
name: 'Someone',
|
||||
phoneNumber: '(202) 555-0011',
|
||||
color: 'green',
|
||||
avatarPath: util.pngObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: "Y'all 🌆",
|
||||
},
|
||||
id: '3-guid-guid-guid-guid-guid',
|
||||
conversationId: 'EveryoneGroupID',
|
||||
snippet: 'Hello, <<left>>everyone<<right>>! Woohooo!',
|
||||
receivedAt: Date.now() - 24 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
isMe: true,
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: "Y'all 🌆",
|
||||
},
|
||||
id: '4-guid-guid-guid-guid-guid',
|
||||
conversationId: 'EveryoneGroupID',
|
||||
snippet: 'Well, <<left>>everyone<<right>>, happy new year!',
|
||||
receivedAt: Date.now() - 24 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
];
|
||||
|
||||
const messageLookup = util._.fromPairs(
|
||||
util._.map(messages, message => [message.id, message])
|
||||
);
|
||||
messages.forEach(message => {
|
||||
items.push({
|
||||
type: 'message',
|
||||
data: message.id,
|
||||
});
|
||||
});
|
||||
|
||||
<util.LeftPaneContext
|
||||
theme={util.theme}
|
||||
gutterStyle={{ height: '500px', display: 'flex', flexDirection: 'row' }}
|
||||
>
|
||||
<SearchResults
|
||||
items={items}
|
||||
i18n={util.i18n}
|
||||
searchTerm="(202) 555-0015"
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
startNewConversation={(...args) =>
|
||||
console.log('startNewConversation', args)
|
||||
}
|
||||
onStartNewConversation={(...args) =>
|
||||
console.log('onStartNewConversation', args)
|
||||
}
|
||||
renderMessageSearchResult={id => (
|
||||
<MessageSearchResult
|
||||
{...messageLookup[id]}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</util.LeftPaneContext>;
|
||||
```
|
||||
|
||||
#### With no conversations
|
||||
|
||||
```jsx
|
||||
const items = [
|
||||
{
|
||||
type: 'contacts-header',
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: 'contact',
|
||||
data: {
|
||||
name: 'The one Everyone',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0013',
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'contact',
|
||||
data: {
|
||||
name: 'No likey everyone',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0014',
|
||||
color: 'red',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'messages-header',
|
||||
data: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
const messages = [
|
||||
{
|
||||
from: {
|
||||
isMe: true,
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: 'Mr. Fire 🔥',
|
||||
phoneNumber: '(202) 555-0015',
|
||||
},
|
||||
id: '1-guid-guid-guid-guid-guid',
|
||||
conversationId: '(202) 555-0015',
|
||||
receivedAt: Date.now() - 5 * 60 * 1000,
|
||||
snippet: '<<left>>Everyone<<right>>! Get in!',
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
name: 'Jon ❄️',
|
||||
phoneNumber: '(202) 555-0016',
|
||||
color: 'green',
|
||||
},
|
||||
to: {
|
||||
isMe: true,
|
||||
},
|
||||
id: '2-guid-guid-guid-guid-guid',
|
||||
conversationId: '(202) 555-0016',
|
||||
snippet: 'Why is <<left>>everyone<<right>> so frustrated?',
|
||||
receivedAt: Date.now() - 20 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
name: 'Someone',
|
||||
phoneNumber: '(202) 555-0011',
|
||||
color: 'green',
|
||||
avatarPath: util.pngObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: "Y'all 🌆",
|
||||
},
|
||||
id: '3-guid-guid-guid-guid-guid',
|
||||
conversationId: 'EveryoneGroupID',
|
||||
snippet: 'Hello, <<left>>everyone<<right>>! Woohooo!',
|
||||
receivedAt: Date.now() - 24 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
isMe: true,
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: "Y'all 🌆",
|
||||
},
|
||||
id: '4-guid-guid-guid-guid-guid',
|
||||
conversationId: 'EveryoneGroupID',
|
||||
snippet: 'Well, <<left>>everyone<<right>>, happy new year!',
|
||||
receivedAt: Date.now() - 24 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
];
|
||||
|
||||
const messageLookup = util._.fromPairs(
|
||||
util._.map(messages, message => [message.id, message])
|
||||
);
|
||||
messages.forEach(message => {
|
||||
items.push({
|
||||
type: 'message',
|
||||
data: message.id,
|
||||
});
|
||||
});
|
||||
|
||||
<util.LeftPaneContext
|
||||
theme={util.theme}
|
||||
gutterStyle={{ height: '500px', display: 'flex', flexDirection: 'row' }}
|
||||
>
|
||||
<SearchResults
|
||||
items={items}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
startNewConversation={(...args) =>
|
||||
console.log('startNewConversation', args)
|
||||
}
|
||||
onStartNewConversation={(...args) =>
|
||||
console.log('onStartNewConversation', args)
|
||||
}
|
||||
renderMessageSearchResult={id => (
|
||||
<MessageSearchResult
|
||||
{...messageLookup[id]}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</util.LeftPaneContext>;
|
||||
```
|
||||
|
||||
#### With no contacts
|
||||
|
||||
```jsx
|
||||
const items = [
|
||||
{
|
||||
type: 'conversations-header',
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: 'conversation',
|
||||
data: {
|
||||
name: 'Everyone 🌆',
|
||||
conversationType: 'group',
|
||||
phoneNumber: '(202) 555-0011',
|
||||
avatarPath: util.landscapeGreenObjectUrl,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
lastMessage: {
|
||||
text: 'The rabbit hopped silently in the night.',
|
||||
status: 'sent',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'conversation',
|
||||
data: {
|
||||
name: 'Everyone Else 🔥',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0012',
|
||||
avatarPath: util.landscapePurpleObjectUrl,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
lastMessage: {
|
||||
text: "What's going on?",
|
||||
status: 'sent',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'messages-header',
|
||||
data: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
const messages = [
|
||||
{
|
||||
from: {
|
||||
isMe: true,
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: 'Mr. Fire 🔥',
|
||||
phoneNumber: '(202) 555-0015',
|
||||
},
|
||||
id: '1-guid-guid-guid-guid-guid',
|
||||
conversationId: '(202) 555-0015',
|
||||
receivedAt: Date.now() - 5 * 60 * 1000,
|
||||
snippet: '<<left>>Everyone<<right>>! Get in!',
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
name: 'Jon ❄️',
|
||||
phoneNumber: '(202) 555-0016',
|
||||
color: 'green',
|
||||
},
|
||||
to: {
|
||||
isMe: true,
|
||||
},
|
||||
id: '2-guid-guid-guid-guid-guid',
|
||||
conversationId: '(202) 555-0016',
|
||||
snippet: 'Why is <<left>>everyone<<right>> so frustrated?',
|
||||
receivedAt: Date.now() - 20 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
name: 'Someone',
|
||||
phoneNumber: '(202) 555-0011',
|
||||
color: 'green',
|
||||
avatarPath: util.pngObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: "Y'all 🌆",
|
||||
},
|
||||
id: '3-guid-guid-guid-guid-guid',
|
||||
conversationId: 'EveryoneGroupID',
|
||||
snippet: 'Hello, <<left>>everyone<<right>>! Woohooo!',
|
||||
receivedAt: Date.now() - 24 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
{
|
||||
from: {
|
||||
isMe: true,
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
to: {
|
||||
name: "Y'all 🌆",
|
||||
},
|
||||
id: '4-guid-guid-guid-guid-guid',
|
||||
conversationId: 'EveryoneGroupID',
|
||||
snippet: 'Well, <<left>>everyone<<right>>, happy new year!',
|
||||
receivedAt: Date.now() - 24 * 60 * 1000,
|
||||
conversationOpenInternal: () => console.log('onClick'),
|
||||
},
|
||||
];
|
||||
|
||||
const messageLookup = util._.fromPairs(
|
||||
util._.map(messages, message => [message.id, message])
|
||||
);
|
||||
messages.forEach(message => {
|
||||
items.push({
|
||||
type: 'message',
|
||||
data: message.id,
|
||||
});
|
||||
});
|
||||
|
||||
<util.LeftPaneContext
|
||||
theme={util.theme}
|
||||
gutterStyle={{ height: '500px', display: 'flex', flexDirection: 'row' }}
|
||||
>
|
||||
<SearchResults
|
||||
items={items}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
startNewConversation={(...args) =>
|
||||
console.log('startNewConversation', args)
|
||||
}
|
||||
onStartNewConversation={(...args) =>
|
||||
console.log('onStartNewConversation', args)
|
||||
}
|
||||
renderMessageSearchResult={id => (
|
||||
<MessageSearchResult
|
||||
{...messageLookup[id]}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</util.LeftPaneContext>;
|
||||
```
|
||||
|
||||
#### With no messages
|
||||
|
||||
```jsx
|
||||
const items = [
|
||||
{
|
||||
type: 'conversations-header',
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: 'conversation',
|
||||
data: {
|
||||
name: 'Everyone 🌆',
|
||||
conversationType: 'group',
|
||||
phoneNumber: '(202) 555-0011',
|
||||
avatarPath: util.landscapeGreenObjectUrl,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
lastMessage: {
|
||||
text: 'The rabbit hopped silently in the night.',
|
||||
status: 'sent',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'conversation',
|
||||
data: {
|
||||
name: 'Everyone Else 🔥',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0012',
|
||||
avatarPath: util.landscapePurpleObjectUrl,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
lastMessage: {
|
||||
text: "What's going on?",
|
||||
status: 'sent',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'contacts-header',
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: 'contact',
|
||||
data: {
|
||||
name: 'The one Everyone',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0013',
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'contact',
|
||||
data: {
|
||||
name: 'No likey everyone',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0014',
|
||||
color: 'red',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
<util.LeftPaneContext
|
||||
theme={util.theme}
|
||||
gutterStyle={{ height: '500px', display: 'flex', flexDirection: 'row' }}
|
||||
>
|
||||
<SearchResults
|
||||
items={items}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
startNewConversation={(...args) =>
|
||||
console.log('startNewConversation', args)
|
||||
}
|
||||
onStartNewConversation={(...args) =>
|
||||
console.log('onStartNewConversation', args)
|
||||
}
|
||||
/>
|
||||
</util.LeftPaneContext>;
|
||||
```
|
||||
|
||||
#### With no results at all
|
||||
|
||||
```jsx
|
||||
<util.LeftPaneContext
|
||||
theme={util.theme}
|
||||
gutterStyle={{ height: '500px', display: 'flex', flexDirection: 'row' }}
|
||||
>
|
||||
<SearchResults
|
||||
items={[]}
|
||||
noResults={true}
|
||||
searchTerm="something"
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
startNewConversation={(...args) =>
|
||||
console.log('startNewConversation', args)
|
||||
}
|
||||
onStartNewConversation={(...args) =>
|
||||
console.log('onStartNewConversation', args)
|
||||
}
|
||||
renderMessageSearchResult={id => (
|
||||
<MessageSearchResult
|
||||
{...messageLookup[id]}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### With no results at all, searching in conversation
|
||||
|
||||
```jsx
|
||||
<util.LeftPaneContext
|
||||
theme={util.theme}
|
||||
gutterStyle={{ height: '500px', display: 'flex', flexDirection: 'row' }}
|
||||
>
|
||||
<SearchResults
|
||||
items={[]}
|
||||
noResults={true}
|
||||
searchTerm="something"
|
||||
searchInConversationName="Everyone 🔥"
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
startNewConversation={(...args) =>
|
||||
console.log('startNewConversation', args)
|
||||
}
|
||||
onStartNewConversation={(...args) =>
|
||||
console.log('onStartNewConversation', args)
|
||||
}
|
||||
renderMessageSearchResult={id => (
|
||||
<MessageSearchResult
|
||||
{...messageLookup[id]}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### Searching in conversation but no search term
|
||||
|
||||
```jsx
|
||||
<util.LeftPaneContext
|
||||
theme={util.theme}
|
||||
gutterStyle={{ height: '500px', display: 'flex', flexDirection: 'row' }}
|
||||
>
|
||||
<SearchResults
|
||||
items={[]}
|
||||
noResults={true}
|
||||
searchTerm=""
|
||||
searchInConversationName="Everyone 🔥"
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
startNewConversation={(...args) =>
|
||||
console.log('startNewConversation', args)
|
||||
}
|
||||
onStartNewConversation={(...args) =>
|
||||
console.log('onStartNewConversation', args)
|
||||
}
|
||||
renderMessageSearchResult={id => (
|
||||
<MessageSearchResult
|
||||
{...messageLookup[id]}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### With a lot of results
|
||||
|
||||
```jsx
|
||||
const items = [
|
||||
{
|
||||
type: 'conversations-header',
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: 'conversation',
|
||||
data: {
|
||||
name: 'Everyone 🌆',
|
||||
conversationType: 'group',
|
||||
phoneNumber: '(202) 555-0011',
|
||||
avatarPath: util.landscapeGreenObjectUrl,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
lastMessage: {
|
||||
text: 'The rabbit hopped silently in the night.',
|
||||
status: 'sent',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'conversation',
|
||||
data: {
|
||||
name: 'Everyone Else 🔥',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0012',
|
||||
avatarPath: util.landscapePurpleObjectUrl,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
lastMessage: {
|
||||
text: "What's going on?",
|
||||
status: 'sent',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'contacts-header',
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: 'contact',
|
||||
data: {
|
||||
name: 'The one Everyone',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0013',
|
||||
avatarPath: util.gifObjectUrl,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'contact',
|
||||
data: {
|
||||
name: 'No likey everyone',
|
||||
conversationType: 'direct',
|
||||
phoneNumber: '(202) 555-0014',
|
||||
color: 'red',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'messages-header',
|
||||
data: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
const messages = [];
|
||||
for (let i = 0; i < 100; i += 1) {
|
||||
messages.push({
|
||||
from: {
|
||||
name: 'Mr. Fire 🔥',
|
||||
phoneNumber: '(202) 555-0015',
|
||||
avatarPath: util.landscapeGreenObjectUrl,
|
||||
},
|
||||
to: {
|
||||
isMe: true,
|
||||
},
|
||||
id: `${i}-guid-guid-guid-guid-guid`,
|
||||
conversationId: '(202) 555-0015',
|
||||
receivedAt: Date.now() - 5 * 60 * 1000,
|
||||
snippet: `${i} <<left>>Everyone<<right>>! Get in!`,
|
||||
conversationOpenInternal: data => console.log('onClick', data),
|
||||
});
|
||||
}
|
||||
|
||||
const messageLookup = util._.fromPairs(
|
||||
util._.map(messages, message => [message.id, message])
|
||||
);
|
||||
messages.forEach(message => {
|
||||
items.push({
|
||||
type: 'message',
|
||||
data: message.id,
|
||||
});
|
||||
});
|
||||
|
||||
<util.LeftPaneContext
|
||||
gutterStyle={{ height: '500px', display: 'flex', flexDirection: 'row' }}
|
||||
theme={util.theme}
|
||||
>
|
||||
<SearchResults
|
||||
items={items}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
startNewConversation={(...args) =>
|
||||
console.log('startNewConversation', args)
|
||||
}
|
||||
onStartNewConversation={(...args) =>
|
||||
console.log('onStartNewConversation', args)
|
||||
}
|
||||
renderMessageSearchResult={id => (
|
||||
<MessageSearchResult
|
||||
{...messageLookup[id]}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</util.LeftPaneContext>;
|
||||
```
|
||||
|
||||
#### With just messages and no header
|
||||
|
||||
```jsx
|
||||
const items = [];
|
||||
|
||||
const messages = [];
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
messages.push({
|
||||
from: {
|
||||
name: 'Mr. Fire 🔥',
|
||||
phoneNumber: '(202) 555-0015',
|
||||
avatarPath: util.landscapeGreenObjectUrl,
|
||||
},
|
||||
to: {
|
||||
isMe: true,
|
||||
},
|
||||
id: `${i}-guid-guid-guid-guid-guid`,
|
||||
conversationId: '(202) 555-0015',
|
||||
receivedAt: Date.now() - 5 * 60 * 1000,
|
||||
snippet: `${i} <<left>>Everyone<<right>>! Get in!`,
|
||||
conversationOpenInternal: data => console.log('onClick', data),
|
||||
});
|
||||
}
|
||||
|
||||
const messageLookup = util._.fromPairs(
|
||||
util._.map(messages, message => [message.id, message])
|
||||
);
|
||||
messages.forEach(message => {
|
||||
items.push({
|
||||
type: 'message',
|
||||
data: message.id,
|
||||
});
|
||||
});
|
||||
|
||||
<util.LeftPaneContext
|
||||
gutterStyle={{ height: '500px', display: 'flex', flexDirection: 'row' }}
|
||||
theme={util.theme}
|
||||
>
|
||||
<SearchResults
|
||||
items={items}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
startNewConversation={(...args) =>
|
||||
console.log('startNewConversation', args)
|
||||
}
|
||||
onStartNewConversation={(...args) =>
|
||||
console.log('onStartNewConversation', args)
|
||||
}
|
||||
renderMessageSearchResult={id => (
|
||||
<MessageSearchResult
|
||||
{...messageLookup[id]}
|
||||
i18n={util.i18n}
|
||||
openConversationInternal={(...args) =>
|
||||
console.log('openConversationInternal', args)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</util.LeftPaneContext>;
|
||||
```
|
423
ts/components/SearchResults.stories.tsx
Normal file
423
ts/components/SearchResults.stories.tsx
Normal file
|
@ -0,0 +1,423 @@
|
|||
import * as React from 'react';
|
||||
import { SearchResults } from './SearchResults';
|
||||
import {
|
||||
MessageSearchResult,
|
||||
PropsDataType as MessageSearchResultPropsType,
|
||||
} from './MessageSearchResult';
|
||||
|
||||
// @ts-ignore
|
||||
import { setup as setupI18n } from '../../js/modules/i18n';
|
||||
// @ts-ignore
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
|
||||
import { storiesOf } from '@storybook/react';
|
||||
//import { boolean, select } from '@storybook/addon-knobs';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
|
||||
// @ts-ignore
|
||||
import gif from '../../fixtures/giphy-GVNvOUpeYmI7e.gif';
|
||||
// @ts-ignore
|
||||
import png from '../../fixtures/freepngs-2cd43b_bed7d1327e88454487397574d87b64dc_mv2.png';
|
||||
// @ts-ignore
|
||||
import landscapeGreen from '../../fixtures/1000x50-green.jpeg';
|
||||
// @ts-ignore
|
||||
import landscapePurple from '../../fixtures/200x50-purple.png';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
function makeObjectUrl(data: ArrayBuffer, contentType: string): string {
|
||||
const blob = new Blob([data], {
|
||||
type: contentType,
|
||||
});
|
||||
|
||||
return URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
// 320x240
|
||||
const gifObjectUrl = makeObjectUrl(gif, 'image/gif');
|
||||
// 800×1200
|
||||
const pngObjectUrl = makeObjectUrl(png, 'image/png');
|
||||
const landscapeGreenObjectUrl = makeObjectUrl(landscapeGreen, 'image/jpeg');
|
||||
const landscapePurpleObjectUrl = makeObjectUrl(landscapePurple, 'image/png');
|
||||
|
||||
const messageLookup: Map<string, MessageSearchResultPropsType> = new Map();
|
||||
|
||||
const CONTACT = 'contact' as 'contact';
|
||||
const CONTACTS_HEADER = 'contacts-header' as 'contacts-header';
|
||||
const CONVERSATION = 'conversation' as 'conversation';
|
||||
const CONVERSATIONS_HEADER = 'conversations-header' as 'conversations-header';
|
||||
const DIRECT = 'direct' as 'direct';
|
||||
const GROUP = 'group' as 'group';
|
||||
const MESSAGE = 'message' as 'message';
|
||||
const MESSAGES_HEADER = 'messages-header' as 'messages-header';
|
||||
const SENT = 'sent' as 'sent';
|
||||
const START_NEW_CONVERSATION = 'start-new-conversation' as 'start-new-conversation';
|
||||
const SMS_MMS_NOT_SUPPORTED = 'sms-mms-not-supported-text' as 'sms-mms-not-supported-text';
|
||||
|
||||
// tslint:disable-next-line no-backbone-get-set-outside-model
|
||||
messageLookup.set('1-guid-guid-guid-guid-guid', {
|
||||
id: '1-guid-guid-guid-guid-guid',
|
||||
conversationId: '(202) 555-0015',
|
||||
sentAt: Date.now() - 5 * 60 * 1000,
|
||||
snippet: '<<left>>Everyone<<right>>! Get in!',
|
||||
|
||||
from: {
|
||||
phoneNumber: '(202) 555-0020',
|
||||
isMe: true,
|
||||
avatarPath: gifObjectUrl,
|
||||
},
|
||||
to: {
|
||||
phoneNumber: '(202) 555-0015',
|
||||
name: 'Mr. Fire 🔥',
|
||||
},
|
||||
});
|
||||
|
||||
// tslint:disable-next-line no-backbone-get-set-outside-model
|
||||
messageLookup.set('2-guid-guid-guid-guid-guid', {
|
||||
id: '2-guid-guid-guid-guid-guid',
|
||||
conversationId: '(202) 555-0016',
|
||||
sentAt: Date.now() - 20 * 60 * 1000,
|
||||
snippet: 'Why is <<left>>everyone<<right>> so frustrated?',
|
||||
from: {
|
||||
phoneNumber: '(202) 555-0016',
|
||||
name: 'Jon ❄️',
|
||||
color: 'green',
|
||||
},
|
||||
to: {
|
||||
phoneNumber: '(202) 555-0020',
|
||||
isMe: true,
|
||||
},
|
||||
});
|
||||
|
||||
// tslint:disable-next-line no-backbone-get-set-outside-model
|
||||
messageLookup.set('3-guid-guid-guid-guid-guid', {
|
||||
id: '3-guid-guid-guid-guid-guid',
|
||||
conversationId: 'EveryoneGroupID',
|
||||
sentAt: Date.now() - 24 * 60 * 1000,
|
||||
snippet: 'Hello, <<left>>everyone<<right>>! Woohooo!',
|
||||
from: {
|
||||
phoneNumber: '(202) 555-0011',
|
||||
name: 'Someone',
|
||||
color: 'green',
|
||||
avatarPath: pngObjectUrl,
|
||||
},
|
||||
to: {
|
||||
phoneNumber: '(202) 555-0016',
|
||||
name: "Y'all 🌆",
|
||||
},
|
||||
});
|
||||
|
||||
// tslint:disable-next-line no-backbone-get-set-outside-model
|
||||
messageLookup.set('4-guid-guid-guid-guid-guid', {
|
||||
id: '4-guid-guid-guid-guid-guid',
|
||||
conversationId: 'EveryoneGroupID',
|
||||
sentAt: Date.now() - 24 * 60 * 1000,
|
||||
snippet: 'Well, <<left>>everyone<<right>>, happy new year!',
|
||||
from: {
|
||||
phoneNumber: '(202) 555-0020',
|
||||
isMe: true,
|
||||
avatarPath: gifObjectUrl,
|
||||
},
|
||||
to: {
|
||||
phoneNumber: '(202) 555-0016',
|
||||
name: "Y'all 🌆",
|
||||
},
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
discussionsLoading: false,
|
||||
items: [],
|
||||
i18n,
|
||||
messagesLoading: false,
|
||||
noResults: false,
|
||||
openConversationInternal: action('open-conversation-internal'),
|
||||
regionCode: 'US',
|
||||
renderMessageSearchResult(id: string): JSX.Element {
|
||||
const messageProps = messageLookup.get(id) as MessageSearchResultPropsType;
|
||||
|
||||
return (
|
||||
<MessageSearchResult
|
||||
{...messageProps}
|
||||
i18n={i18n}
|
||||
openConversationInternal={action(
|
||||
'MessageSearchResult-open-conversation-internal'
|
||||
)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
searchConversationName: undefined,
|
||||
searchTerm: '1234567890',
|
||||
selectedConversationId: undefined,
|
||||
selectedMessageId: undefined,
|
||||
startNewConversation: action('start-new-conversation'),
|
||||
};
|
||||
|
||||
const conversations = [
|
||||
{
|
||||
type: CONVERSATION,
|
||||
data: {
|
||||
id: '+12025550011',
|
||||
phoneNumber: '(202) 555-0011',
|
||||
name: 'Everyone 🌆',
|
||||
type: GROUP,
|
||||
avatarPath: landscapeGreenObjectUrl,
|
||||
isMe: false,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
unreadCount: 0,
|
||||
isSelected: false,
|
||||
lastMessage: {
|
||||
text: 'The rabbit hopped silently in the night.',
|
||||
status: SENT,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: CONVERSATION,
|
||||
data: {
|
||||
id: '+12025550012',
|
||||
phoneNumber: '(202) 555-0012',
|
||||
name: 'Everyone Else 🔥',
|
||||
type: DIRECT,
|
||||
avatarPath: landscapePurpleObjectUrl,
|
||||
isMe: false,
|
||||
lastUpdated: Date.now() - 5 * 60 * 1000,
|
||||
unreadCount: 0,
|
||||
isSelected: false,
|
||||
lastMessage: {
|
||||
text: "What's going on?",
|
||||
status: SENT,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const contacts = [
|
||||
{
|
||||
type: CONTACT,
|
||||
data: {
|
||||
id: '+12025550013',
|
||||
phoneNumber: '(202) 555-0013',
|
||||
name: 'The one Everyone',
|
||||
type: DIRECT,
|
||||
avatarPath: gifObjectUrl,
|
||||
isMe: false,
|
||||
lastUpdated: Date.now() - 10 * 60 * 1000,
|
||||
unreadCount: 0,
|
||||
isSelected: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: CONTACT,
|
||||
data: {
|
||||
id: '+12025550014',
|
||||
phoneNumber: '(202) 555-0014',
|
||||
name: 'No likey everyone',
|
||||
type: DIRECT,
|
||||
color: 'red',
|
||||
isMe: false,
|
||||
lastUpdated: Date.now() - 11 * 60 * 1000,
|
||||
unreadCount: 0,
|
||||
isSelected: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const messages = [
|
||||
{
|
||||
type: MESSAGE,
|
||||
data: '1-guid-guid-guid-guid-guid',
|
||||
},
|
||||
{
|
||||
type: MESSAGE,
|
||||
data: '2-guid-guid-guid-guid-guid',
|
||||
},
|
||||
{
|
||||
type: MESSAGE,
|
||||
data: '3-guid-guid-guid-guid-guid',
|
||||
},
|
||||
{
|
||||
type: MESSAGE,
|
||||
data: '4-guid-guid-guid-guid-guid',
|
||||
},
|
||||
];
|
||||
|
||||
const messagesMany = Array.from(Array(100), (_, i) => messages[i % 4]);
|
||||
|
||||
const permutations = [
|
||||
{
|
||||
title: 'SMS/MMS Not Supported Text',
|
||||
props: {
|
||||
items: [
|
||||
{
|
||||
type: START_NEW_CONVERSATION,
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: SMS_MMS_NOT_SUPPORTED,
|
||||
data: undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'All Result Types',
|
||||
props: {
|
||||
items: [
|
||||
{
|
||||
type: CONVERSATIONS_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...conversations,
|
||||
{
|
||||
type: CONTACTS_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...contacts,
|
||||
{
|
||||
type: MESSAGES_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...messages,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Start new Conversation',
|
||||
props: {
|
||||
items: [
|
||||
{
|
||||
type: START_NEW_CONVERSATION,
|
||||
data: undefined,
|
||||
},
|
||||
{
|
||||
type: CONVERSATIONS_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...conversations,
|
||||
{
|
||||
type: CONTACTS_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...contacts,
|
||||
{
|
||||
type: MESSAGES_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...messages,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'No Conversations',
|
||||
props: {
|
||||
items: [
|
||||
{
|
||||
type: CONTACTS_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...contacts,
|
||||
{
|
||||
type: MESSAGES_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...messages,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'No Contacts',
|
||||
props: {
|
||||
items: [
|
||||
{
|
||||
type: CONVERSATIONS_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...conversations,
|
||||
{
|
||||
type: MESSAGES_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...messages,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'No Messages',
|
||||
props: {
|
||||
items: [
|
||||
{
|
||||
type: CONVERSATIONS_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...conversations,
|
||||
{
|
||||
type: CONTACTS_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...contacts,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'No Results',
|
||||
props: {
|
||||
noResults: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'No Results, Searching in Conversation',
|
||||
props: {
|
||||
noResults: true,
|
||||
searchInConversationName: 'Everyone 🔥',
|
||||
searchTerm: 'something',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Searching in Conversation no search term',
|
||||
props: {
|
||||
noResults: true,
|
||||
searchInConversationName: 'Everyone 🔥',
|
||||
searchTerm: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Lots of results',
|
||||
props: {
|
||||
items: [
|
||||
{
|
||||
type: CONVERSATIONS_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...conversations,
|
||||
{
|
||||
type: CONTACTS_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...contacts,
|
||||
{
|
||||
type: MESSAGES_HEADER,
|
||||
data: undefined,
|
||||
},
|
||||
...messagesMany,
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Messages, no header',
|
||||
props: {
|
||||
items: messages,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
storiesOf('Components/SearchResults', module).add('Iterations', () => {
|
||||
return permutations.map(({ props, title }) => (
|
||||
<>
|
||||
<h3>{title}</h3>
|
||||
<div className="module-left-pane">
|
||||
<SearchResults {...defaultProps} {...props} />
|
||||
</div>
|
||||
<hr />
|
||||
</>
|
||||
));
|
||||
});
|
|
@ -35,6 +35,10 @@ type StartNewConversationType = {
|
|||
type: 'start-new-conversation';
|
||||
data: undefined;
|
||||
};
|
||||
type NotSupportedSMS = {
|
||||
type: 'sms-mms-not-supported-text';
|
||||
data: undefined;
|
||||
};
|
||||
type ConversationHeaderType = {
|
||||
type: 'conversations-header';
|
||||
data: undefined;
|
||||
|
@ -66,6 +70,7 @@ type SpinnerType = {
|
|||
|
||||
export type SearchResultRowType =
|
||||
| StartNewConversationType
|
||||
| NotSupportedSMS
|
||||
| ConversationHeaderType
|
||||
| ContactsHeaderType
|
||||
| MessagesHeaderType
|
||||
|
@ -368,6 +373,12 @@ export class SearchResults extends React.Component<PropsType, StateType> {
|
|||
onClick={this.handleStartNewConversation}
|
||||
/>
|
||||
);
|
||||
} else if (row.type === 'sms-mms-not-supported-text') {
|
||||
return (
|
||||
<div className="module-search-results__sms-not-supported">
|
||||
{i18n('notSupportedSMS')}
|
||||
</div>
|
||||
);
|
||||
} else if (row.type === 'conversations-header') {
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -167,6 +167,10 @@ window.itemLookup = {
|
|||
'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 = {
|
||||
|
|
|
@ -32,6 +32,10 @@ import {
|
|||
} from './GroupNotification';
|
||||
import { ResetSessionNotification } from './ResetSessionNotification';
|
||||
|
||||
type LinkNotificationType = {
|
||||
type: 'linkNotification';
|
||||
data: null;
|
||||
};
|
||||
type MessageType = {
|
||||
type: 'message';
|
||||
data: MessageProps;
|
||||
|
@ -61,12 +65,13 @@ type ResetSessionNotificationType = {
|
|||
data: null;
|
||||
};
|
||||
export type TimelineItemType =
|
||||
| LinkNotificationType
|
||||
| MessageType
|
||||
| UnsupportedMessageType
|
||||
| TimerNotificationType
|
||||
| SafetyNumberNotificationType
|
||||
| VerificationNotificationType
|
||||
| ResetSessionNotificationType
|
||||
| SafetyNumberNotificationType
|
||||
| TimerNotificationType
|
||||
| UnsupportedMessageType
|
||||
| VerificationNotificationType
|
||||
| GroupNotificationType;
|
||||
|
||||
type PropsLocalType = {
|
||||
|
@ -112,6 +117,13 @@ export class TimelineItem extends React.PureComponent<PropsType> {
|
|||
notification = (
|
||||
<UnsupportedMessage {...this.props} {...item.data} i18n={i18n} />
|
||||
);
|
||||
} else if (item.type === 'linkNotification') {
|
||||
notification = (
|
||||
<div className="module-message-unsynced">
|
||||
<div className="module-message-unsynced__icon" />
|
||||
{i18n('messageHistoryUnsynced')}
|
||||
</div>
|
||||
);
|
||||
} else if (item.type === 'timerNotification') {
|
||||
notification = (
|
||||
<TimerNotification {...this.props} {...item.data} i18n={i18n} />
|
||||
|
|
|
@ -5,6 +5,7 @@ type TextSecureType = {
|
|||
user: {
|
||||
getNumber: () => string;
|
||||
};
|
||||
get: (item: string) => any;
|
||||
};
|
||||
messaging: {
|
||||
sendStickerPackSync: (
|
||||
|
|
|
@ -27,6 +27,7 @@ export type ConversationType = {
|
|||
isArchived: boolean;
|
||||
activeAt?: number;
|
||||
timestamp: number;
|
||||
inboxPosition: number;
|
||||
lastMessage?: {
|
||||
status: 'error' | 'sending' | 'sent' | 'delivered' | 'read';
|
||||
text: string;
|
||||
|
@ -56,7 +57,13 @@ export type MessageType = {
|
|||
id: string;
|
||||
conversationId: string;
|
||||
source: string;
|
||||
type: 'incoming' | 'outgoing' | 'group' | 'keychange' | 'verified-change';
|
||||
type:
|
||||
| 'incoming'
|
||||
| 'outgoing'
|
||||
| 'group'
|
||||
| 'keychange'
|
||||
| 'verified-change'
|
||||
| 'message-history-unsynced';
|
||||
quote?: { author: string };
|
||||
received_at: number;
|
||||
hasSignalAccount?: boolean;
|
||||
|
|
|
@ -117,6 +117,21 @@ export const _getConversationComparator = (
|
|||
return rightTimestamp - leftTimestamp;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof left.inboxPosition === 'number' &&
|
||||
typeof right.inboxPosition === 'number'
|
||||
) {
|
||||
return right.inboxPosition > left.inboxPosition ? -1 : 1;
|
||||
}
|
||||
|
||||
if (typeof left.inboxPosition === 'number' && right.inboxPosition == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (typeof right.inboxPosition === 'number' && left.inboxPosition == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const leftTitle = getConversationTitle(left, {
|
||||
i18n,
|
||||
ourRegionCode,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import memoizee from 'memoizee';
|
||||
import { createSelector } from 'reselect';
|
||||
import { getSearchResultsProps } from '../../shims/Whisper';
|
||||
import { instance } from '../../util/libphonenumberInstance';
|
||||
|
||||
import { StateType } from '../reducer';
|
||||
|
||||
|
@ -20,7 +21,7 @@ import {
|
|||
} from '../../components/SearchResults';
|
||||
import { PropsDataType as MessageSearchResultPropsDataType } from '../../components/MessageSearchResult';
|
||||
|
||||
import { getRegionCode, getUserNumber } from './user';
|
||||
import { getRegionCode, getUserAgent, getUserNumber } from './user';
|
||||
import {
|
||||
GetConversationByIdType,
|
||||
getConversationLookup,
|
||||
|
@ -72,6 +73,7 @@ export const getSearchResults = createSelector(
|
|||
[
|
||||
getSearch,
|
||||
getRegionCode,
|
||||
getUserAgent,
|
||||
getConversationLookup,
|
||||
getSelectedConversation,
|
||||
getSelectedMessage,
|
||||
|
@ -79,6 +81,7 @@ export const getSearchResults = createSelector(
|
|||
(
|
||||
state: SearchStateType,
|
||||
regionCode: string,
|
||||
userAgent: string,
|
||||
lookup: ConversationLookupType,
|
||||
selectedConversationId?: string,
|
||||
selectedMessageId?: string
|
||||
|
@ -114,6 +117,17 @@ export const getSearchResults = createSelector(
|
|||
type: 'start-new-conversation',
|
||||
data: undefined,
|
||||
});
|
||||
|
||||
const isIOS = userAgent === 'OWI';
|
||||
const parsedNumber = instance.parse(state.query, regionCode);
|
||||
const isValidNumber = instance.isValidNumber(parsedNumber);
|
||||
|
||||
if (!isIOS && isValidNumber) {
|
||||
items.push({
|
||||
type: 'sms-mms-not-supported-text',
|
||||
data: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (haveConversations) {
|
||||
|
|
|
@ -4,9 +4,12 @@ import { LocalizerType } from '../../types/Util';
|
|||
|
||||
import { StateType } from '../reducer';
|
||||
import { UserStateType } from '../ducks/user';
|
||||
import { ItemsStateType } from '../ducks/items';
|
||||
|
||||
export const getUser = (state: StateType): UserStateType => state.user;
|
||||
|
||||
export const getItems = (state: StateType): ItemsStateType => state.items;
|
||||
|
||||
export const getUserNumber = createSelector(
|
||||
getUser,
|
||||
(state: UserStateType): string => state.ourNumber
|
||||
|
@ -27,6 +30,11 @@ export const getUserUuid = createSelector(
|
|||
(state: UserStateType): string => state.ourUuid
|
||||
);
|
||||
|
||||
export const getUserAgent = createSelector(
|
||||
getItems,
|
||||
(state: ItemsStateType): string => state.userAgent
|
||||
);
|
||||
|
||||
export const getIntl = createSelector(
|
||||
getUser,
|
||||
(state: UserStateType): LocalizerType => state.i18n
|
||||
|
|
|
@ -17,6 +17,7 @@ describe('state/selectors/conversations', () => {
|
|||
activeAt: Date.now(),
|
||||
name: 'No timestamp',
|
||||
timestamp: 0,
|
||||
inboxPosition: 0,
|
||||
phoneNumber: 'notused',
|
||||
isArchived: false,
|
||||
|
||||
|
@ -36,6 +37,7 @@ describe('state/selectors/conversations', () => {
|
|||
activeAt: Date.now(),
|
||||
name: 'B',
|
||||
timestamp: 20,
|
||||
inboxPosition: 21,
|
||||
phoneNumber: 'notused',
|
||||
isArchived: false,
|
||||
|
||||
|
@ -55,6 +57,7 @@ describe('state/selectors/conversations', () => {
|
|||
activeAt: Date.now(),
|
||||
name: 'C',
|
||||
timestamp: 20,
|
||||
inboxPosition: 22,
|
||||
phoneNumber: 'notused',
|
||||
isArchived: false,
|
||||
|
||||
|
@ -74,6 +77,7 @@ describe('state/selectors/conversations', () => {
|
|||
activeAt: Date.now(),
|
||||
name: 'Á',
|
||||
timestamp: 20,
|
||||
inboxPosition: 20,
|
||||
phoneNumber: 'notused',
|
||||
isArchived: false,
|
||||
|
||||
|
@ -93,6 +97,7 @@ describe('state/selectors/conversations', () => {
|
|||
activeAt: Date.now(),
|
||||
name: 'First!',
|
||||
timestamp: 30,
|
||||
inboxPosition: 30,
|
||||
phoneNumber: 'notused',
|
||||
isArchived: false,
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import { assert } from 'chai';
|
|||
import * as Conversation from '../../types/Conversation';
|
||||
import {
|
||||
IncomingMessage,
|
||||
MessageHistoryUnsyncedMessage,
|
||||
OutgoingMessage,
|
||||
VerifiedChangeMessage,
|
||||
} from '../../types/Message';
|
||||
|
@ -44,6 +45,30 @@ describe('Conversation', () => {
|
|||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
context('for message history unsynced message', () => {
|
||||
it('should skip update', () => {
|
||||
const input = {
|
||||
currentTimestamp: 555,
|
||||
lastMessage: {
|
||||
type: 'message-history-unsynced',
|
||||
conversationId: 'foo',
|
||||
sent_at: 666,
|
||||
timestamp: 666,
|
||||
} as MessageHistoryUnsyncedMessage,
|
||||
lastMessageNotificationText: 'xoxoxoxo',
|
||||
};
|
||||
const expected = {
|
||||
lastMessage: 'xoxoxoxo',
|
||||
lastMessageStatus: null,
|
||||
timestamp: 555,
|
||||
};
|
||||
|
||||
const actual = Conversation.createLastMessageUpdate(input);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
context('for verified change message', () => {
|
||||
it('should skip update', () => {
|
||||
const input = {
|
||||
|
|
|
@ -26,13 +26,16 @@ export const createLastMessageUpdate = ({
|
|||
}
|
||||
|
||||
const { type, expirationTimerUpdate } = lastMessage;
|
||||
const isMessageHistoryUnsynced = type === 'message-history-unsynced';
|
||||
const isVerifiedChangeMessage = type === 'verified-change';
|
||||
const isExpireTimerUpdateFromSync = Boolean(
|
||||
expirationTimerUpdate && expirationTimerUpdate.fromSync
|
||||
);
|
||||
|
||||
const shouldUpdateTimestamp = Boolean(
|
||||
!isVerifiedChangeMessage && !isExpireTimerUpdateFromSync
|
||||
!isMessageHistoryUnsynced &&
|
||||
!isVerifiedChangeMessage &&
|
||||
!isExpireTimerUpdateFromSync
|
||||
);
|
||||
const newTimestamp = shouldUpdateTimestamp
|
||||
? lastMessage.sent_at
|
||||
|
|
|
@ -2,7 +2,10 @@ import { Attachment } from './Attachment';
|
|||
import { ContactType } from './Contact';
|
||||
import { IndexableBoolean, IndexablePresence } from './IndexedDB';
|
||||
|
||||
export type Message = UserMessage | VerifiedChangeMessage;
|
||||
export type Message =
|
||||
| UserMessage
|
||||
| VerifiedChangeMessage
|
||||
| MessageHistoryUnsyncedMessage;
|
||||
export type UserMessage = IncomingMessage | OutgoingMessage;
|
||||
|
||||
export type IncomingMessage = Readonly<
|
||||
|
@ -65,6 +68,14 @@ export type VerifiedChangeMessage = Readonly<
|
|||
ExpirationTimerUpdate
|
||||
>;
|
||||
|
||||
export type MessageHistoryUnsyncedMessage = Readonly<
|
||||
{
|
||||
type: 'message-history-unsynced';
|
||||
} & SharedMessageProperties &
|
||||
MessageSchemaVersion5 &
|
||||
ExpirationTimerUpdate
|
||||
>;
|
||||
|
||||
type SharedMessageProperties = Readonly<{
|
||||
conversationId: string;
|
||||
sent_at: number;
|
||||
|
|
|
@ -16,6 +16,9 @@ export const initializeAttachmentMetadata = async (
|
|||
if (message.type === 'verified-change') {
|
||||
return message;
|
||||
}
|
||||
if (message.type === 'message-history-unsynced') {
|
||||
return message;
|
||||
}
|
||||
if (message.messageTimer || message.isViewOnce) {
|
||||
return message;
|
||||
}
|
||||
|
|
|
@ -570,7 +570,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#qr img').remove();",
|
||||
"lineNumber": 135,
|
||||
"lineNumber": 136,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -579,7 +579,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#qr .container').show();",
|
||||
"lineNumber": 137,
|
||||
"lineNumber": 138,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -588,7 +588,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " if ($('#qr').length === 0) {",
|
||||
"lineNumber": 141,
|
||||
"lineNumber": 142,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -597,25 +597,25 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#qr .container').hide();",
|
||||
"lineNumber": 146,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.qr = new QRCode(this.$('#qr')[0]).makeCode(url);",
|
||||
"lineNumber": 147,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.qr = new QRCode(this.$('#qr')[0]).makeCode(url);",
|
||||
"lineNumber": 148,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
},
|
||||
{
|
||||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#qr').addClass('ready');",
|
||||
"lineNumber": 149,
|
||||
"lineNumber": 150,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -624,7 +624,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$(DEVICE_NAME_SELECTOR).val(deviceName || window.getHostName());",
|
||||
"lineNumber": 154,
|
||||
"lineNumber": 155,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -633,7 +633,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#link-phone').submit();",
|
||||
"lineNumber": 159,
|
||||
"lineNumber": 160,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -642,7 +642,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$('#link-phone').submit(e => {",
|
||||
"lineNumber": 169,
|
||||
"lineNumber": 170,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -651,7 +651,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " let name = this.$(DEVICE_NAME_SELECTOR).val();",
|
||||
"lineNumber": 173,
|
||||
"lineNumber": 174,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -660,7 +660,7 @@
|
|||
"rule": "jQuery-$(",
|
||||
"path": "js/views/install_view.js",
|
||||
"line": " this.$(DEVICE_NAME_SELECTOR).focus();",
|
||||
"lineNumber": 176,
|
||||
"lineNumber": 177,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2018-09-19T21:59:32.770Z",
|
||||
"reasonDetail": "Protected from arbitrary input"
|
||||
|
@ -11812,7 +11812,7 @@
|
|||
"rule": "jQuery-wrap(",
|
||||
"path": "ts/shims/textsecure.ts",
|
||||
"line": " wrap(",
|
||||
"lineNumber": 63,
|
||||
"lineNumber": 64,
|
||||
"reasonCategory": "falseMatch",
|
||||
"updated": "2020-02-07T19:52:28.522Z"
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue