Message Requests improvements
This commit is contained in:
parent
b63291507a
commit
81cb7730a5
21 changed files with 302 additions and 263 deletions
|
@ -636,8 +636,6 @@ export class ConversationController {
|
|||
|
||||
await Promise.all(
|
||||
this._conversations.map(async conversation => {
|
||||
conversation.generateProps();
|
||||
|
||||
if (!conversation.get('lastMessage')) {
|
||||
await conversation.updateLastMessage();
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ export function onChange(key: ConfigKeyType, fn: ConfigListenerType) {
|
|||
};
|
||||
}
|
||||
|
||||
const refreshRemoteConfig = async () => {
|
||||
export const refreshRemoteConfig = async () => {
|
||||
const now = Date.now();
|
||||
const server = getServer();
|
||||
const newConfig = await server.getConfig();
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
<util.LeftPaneContext theme={util.theme}>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
title="Someone 🔥 Somewhere"
|
||||
name="Someone 🔥 Somewhere"
|
||||
type={'direct'}
|
||||
phoneNumber="(202) 555-0011"
|
||||
|
@ -25,8 +27,10 @@
|
|||
<util.LeftPaneContext theme={util.theme}>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
type={'direct'}
|
||||
title="Mr. Fire🔥"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -46,9 +50,11 @@
|
|||
<util.LeftPaneContext theme={util.theme}>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
isMe={true}
|
||||
phoneNumber="(202) 555-0011"
|
||||
type={'direct'}
|
||||
title="Mr. Fire🔥"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -69,8 +75,10 @@
|
|||
<div>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
type={'direct'}
|
||||
title="Mr. Fire🔥"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -83,8 +91,10 @@
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId2"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
type={'direct'}
|
||||
title="Mr. Fire🔥"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -97,8 +107,10 @@
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId3"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
type={'direct'}
|
||||
title="Mr. Fire🔥"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -111,8 +123,10 @@
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId4"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
type={'direct'}
|
||||
title="Mr. Fire🔥"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -125,8 +139,10 @@
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId5"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
type={'direct'}
|
||||
title="Mr. Fire🔥"
|
||||
name="Mr. Fire🔥"
|
||||
color="green"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -148,7 +164,9 @@
|
|||
<div>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
unreadCount={4}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -162,7 +180,51 @@
|
|||
<div>
|
||||
<ConversationListItem
|
||||
id="conversationId2"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
unreadCount={4}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
typingContact={{
|
||||
name: 'Someone Here',
|
||||
}}
|
||||
lastMessage={{
|
||||
status: 'read',
|
||||
}}
|
||||
onClick={result => console.log('onClick', result)}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
</util.LeftPaneContext>
|
||||
```
|
||||
|
||||
#### Message Request
|
||||
|
||||
```jsx
|
||||
<util.LeftPaneContext theme={util.theme}>
|
||||
<div>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted={false}
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
unreadCount={4}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
typingContact={{
|
||||
name: 'Someone Here',
|
||||
}}
|
||||
onClick={result => console.log('onClick', result)}
|
||||
i18n={util.i18n}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<ConversationListItem
|
||||
id="conversationId2"
|
||||
isAccepted={false}
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
unreadCount={4}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -188,7 +250,9 @@
|
|||
<div>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
unreadCount={4}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -200,7 +264,9 @@
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId2"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
unreadCount={10}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -212,7 +278,9 @@
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId3"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
unreadCount={250}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -232,7 +300,9 @@
|
|||
<util.LeftPaneContext theme={util.theme}>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
isSelected={true}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -254,7 +324,9 @@ We don't want Jumbomoji or links.
|
|||
<div>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -265,7 +337,9 @@ We don't want Jumbomoji or links.
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId2"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -287,7 +361,9 @@ We only show one line.
|
|||
<div>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
name="Long contact name. Esquire. The third. And stuff. And more! And more!"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -299,7 +375,9 @@ We only show one line.
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId2"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -311,7 +389,9 @@ We only show one line.
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId3"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -325,7 +405,9 @@ We only show one line.
|
|||
|
||||
<ConversationListItem
|
||||
id="conversationId4"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
unreadCount={8}
|
||||
|
@ -338,7 +420,9 @@ We only show one line.
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId5"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -350,7 +434,9 @@ We only show one line.
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId6"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -374,7 +460,9 @@ On platforms that show scrollbars all the time, this is true all the time.
|
|||
<div style={{ width: '280px' }}>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
name="Long contact name. Esquire. The third. And stuff. And more! And more!"
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
|
@ -386,7 +474,9 @@ On platforms that show scrollbars all the time, this is true all the time.
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId2"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -407,7 +497,9 @@ On platforms that show scrollbars all the time, this is true all the time.
|
|||
<div>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -418,7 +510,9 @@ On platforms that show scrollbars all the time, this is true all the time.
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId2"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 24 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -429,7 +523,9 @@ On platforms that show scrollbars all the time, this is true all the time.
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId3"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 7 * 24 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -440,7 +536,9 @@ On platforms that show scrollbars all the time, this is true all the time.
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId4"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 365 * 24 * 60 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -460,7 +558,9 @@ On platforms that show scrollbars all the time, this is true all the time.
|
|||
<div>
|
||||
<ConversationListItem
|
||||
id="conversationId1"
|
||||
isAccepted
|
||||
name="John"
|
||||
title="John"
|
||||
type={'direct'}
|
||||
lastUpdated={null}
|
||||
lastMessage={{
|
||||
|
@ -471,7 +571,9 @@ On platforms that show scrollbars all the time, this is true all the time.
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId2"
|
||||
isAccepted
|
||||
name="Missing message"
|
||||
title="Missing message"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
@ -482,7 +584,9 @@ On platforms that show scrollbars all the time, this is true all the time.
|
|||
/>
|
||||
<ConversationListItem
|
||||
id="conversationId3"
|
||||
isAccepted
|
||||
phoneNumber="(202) 555-0011"
|
||||
title="(202) 555-0011"
|
||||
type={'direct'}
|
||||
lastUpdated={Date.now() - 5 * 60 * 1000}
|
||||
lastMessage={{
|
||||
|
|
|
@ -26,6 +26,7 @@ export type PropsData = {
|
|||
unreadCount?: number;
|
||||
isSelected: boolean;
|
||||
|
||||
isAccepted?: boolean;
|
||||
draftPreview?: string;
|
||||
shouldShowDraft?: boolean;
|
||||
|
||||
|
@ -152,6 +153,7 @@ export class ConversationListItem extends React.PureComponent<Props> {
|
|||
const {
|
||||
draftPreview,
|
||||
i18n,
|
||||
isAccepted,
|
||||
lastMessage,
|
||||
shouldShowDraft,
|
||||
typingContact,
|
||||
|
@ -187,7 +189,11 @@ export class ConversationListItem extends React.PureComponent<Props> {
|
|||
: null
|
||||
)}
|
||||
>
|
||||
{typingContact ? (
|
||||
{!isAccepted ? (
|
||||
<span className="module-conversation-list-item__message-request">
|
||||
{i18n('ConversationListItem--message-request')}
|
||||
</span>
|
||||
) : typingContact ? (
|
||||
<TypingAnimation i18n={i18n} />
|
||||
) : (
|
||||
<>
|
||||
|
|
|
@ -13,6 +13,7 @@ export type Props = {
|
|||
membersCount?: number;
|
||||
phoneNumber?: string;
|
||||
onHeightChange?: () => unknown;
|
||||
updateSharedGroups?: () => unknown;
|
||||
} & Omit<AvatarProps, 'onClick' | 'size' | 'noteToSelf'>;
|
||||
|
||||
const renderMembershipRow = ({
|
||||
|
@ -113,6 +114,7 @@ export const ConversationHero = ({
|
|||
profileName,
|
||||
title,
|
||||
onHeightChange,
|
||||
updateSharedGroups,
|
||||
}: Props) => {
|
||||
const firstRenderRef = React.useRef(true);
|
||||
|
||||
|
@ -121,6 +123,11 @@ export const ConversationHero = ({
|
|||
// component may have changed. The cleanup function notifies listeners of
|
||||
// any potential height changes.
|
||||
return () => {
|
||||
// Kick off the expensive hydration of the current sharedGroupNames
|
||||
if (updateSharedGroups) {
|
||||
updateSharedGroups();
|
||||
}
|
||||
|
||||
if (onHeightChange && !firstRenderRef.current) {
|
||||
onHeightChange();
|
||||
} else {
|
||||
|
@ -135,7 +142,7 @@ export const ConversationHero = ({
|
|||
`mc-${membersCount}`,
|
||||
`n-${name}`,
|
||||
`pn-${profileName}`,
|
||||
...sharedGroupNames.map(g => `g-${g}`),
|
||||
sharedGroupNames.map(g => `g-${g}`).join(' '),
|
||||
]);
|
||||
|
||||
const phoneNumberOnly = Boolean(
|
||||
|
|
|
@ -50,7 +50,11 @@ type PropsHousekeepingType = {
|
|||
actions: Object
|
||||
) => JSX.Element;
|
||||
renderLastSeenIndicator: (id: string) => JSX.Element;
|
||||
renderHeroRow: (id: string, resizeHeroRow: () => unknown) => JSX.Element;
|
||||
renderHeroRow: (
|
||||
id: string,
|
||||
resizeHeroRow: () => unknown,
|
||||
updateSharedGroups: () => unknown
|
||||
) => JSX.Element;
|
||||
renderLoadingRow: (id: string) => JSX.Element;
|
||||
renderTypingBubble: (id: string) => JSX.Element;
|
||||
};
|
||||
|
@ -70,6 +74,7 @@ type PropsActionsType = {
|
|||
markMessageRead: (messageId: string) => unknown;
|
||||
selectMessage: (messageId: string, conversationId: string) => unknown;
|
||||
clearSelectedMessage: () => unknown;
|
||||
updateSharedGroups: () => unknown;
|
||||
} & MessageActionsType &
|
||||
SafetyNumberActionsType;
|
||||
|
||||
|
@ -510,6 +515,7 @@ export class Timeline extends React.PureComponent<Props, State> {
|
|||
renderLoadingRow,
|
||||
renderLastSeenIndicator,
|
||||
renderTypingBubble,
|
||||
updateSharedGroups,
|
||||
} = this.props;
|
||||
|
||||
const styleWithWidth = {
|
||||
|
@ -524,7 +530,7 @@ export class Timeline extends React.PureComponent<Props, State> {
|
|||
if (haveOldest && row === 0) {
|
||||
rowContents = (
|
||||
<div data-row={row} style={styleWithWidth} role="row">
|
||||
{renderHeroRow(id, this.resizeHeroRow)}
|
||||
{renderHeroRow(id, this.resizeHeroRow, updateSharedGroups)}
|
||||
</div>
|
||||
);
|
||||
} else if (!haveOldest && row === 0) {
|
||||
|
|
1
ts/model-types.d.ts
vendored
1
ts/model-types.d.ts
vendored
|
@ -85,7 +85,6 @@ declare class ConversationModelType extends Backbone.Model<
|
|||
cleanup(): Promise<void>;
|
||||
disableProfileSharing(): void;
|
||||
dropProfileKey(): Promise<void>;
|
||||
generateProps(): void;
|
||||
getAccepted(): boolean;
|
||||
getAvatarPath(): string | undefined;
|
||||
getColor(): ColorType | undefined;
|
||||
|
|
|
@ -156,6 +156,8 @@ const dataInterface: ClientInterface = {
|
|||
getTapToViewMessagesNeedingErase,
|
||||
getOlderMessagesByConversation,
|
||||
getNewerMessagesByConversation,
|
||||
getLastConversationActivity,
|
||||
getLastConversationPreview,
|
||||
getMessageMetricsForConversation,
|
||||
migrateConversationMessages,
|
||||
|
||||
|
@ -1022,6 +1024,32 @@ async function getNewerMessagesByConversation(
|
|||
|
||||
return new MessageCollection(handleMessageJSON(messages));
|
||||
}
|
||||
async function getLastConversationActivity(
|
||||
conversationId: string,
|
||||
options: {
|
||||
Message: typeof MessageModelType;
|
||||
}
|
||||
): Promise<MessageModelType | undefined> {
|
||||
const { Message } = options;
|
||||
const result = await channels.getLastConversationActivity(conversationId);
|
||||
if (result) {
|
||||
return new Message(result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
async function getLastConversationPreview(
|
||||
conversationId: string,
|
||||
options: {
|
||||
Message: typeof MessageModelType;
|
||||
}
|
||||
): Promise<MessageModelType | undefined> {
|
||||
const { Message } = options;
|
||||
const result = await channels.getLastConversationPreview(conversationId);
|
||||
if (result) {
|
||||
return new Message(result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
async function getMessageMetricsForConversation(conversationId: string) {
|
||||
const result = await channels.getMessageMetricsForConversation(
|
||||
conversationId
|
||||
|
|
|
@ -210,6 +210,12 @@ export type ServerInterface = DataInterface & {
|
|||
conversationId: string,
|
||||
options?: { limit?: number; receivedAt?: number }
|
||||
) => Promise<Array<MessageTypeUnhydrated>>;
|
||||
getLastConversationActivity: (
|
||||
conversationId: string
|
||||
) => Promise<MessageType | undefined>;
|
||||
getLastConversationPreview: (
|
||||
conversationId: string
|
||||
) => Promise<MessageType | undefined>;
|
||||
getNextExpiringMessage: () => Promise<MessageType>;
|
||||
getNextTapToViewMessageToAgeOut: () => Promise<MessageType>;
|
||||
getOutgoingWithoutExpiresAt: () => Promise<Array<MessageType>>;
|
||||
|
@ -308,6 +314,18 @@ export type ClientInterface = DataInterface & {
|
|||
MessageCollection: typeof MessageModelCollectionType;
|
||||
}
|
||||
) => Promise<MessageModelCollectionType>;
|
||||
getLastConversationActivity: (
|
||||
conversationId: string,
|
||||
options: {
|
||||
Message: typeof MessageModelType;
|
||||
}
|
||||
) => Promise<MessageModelType | undefined>;
|
||||
getLastConversationPreview: (
|
||||
conversationId: string,
|
||||
options: {
|
||||
Message: typeof MessageModelType;
|
||||
}
|
||||
) => Promise<MessageModelType | undefined>;
|
||||
getNextExpiringMessage: ({
|
||||
Message,
|
||||
}: {
|
||||
|
|
|
@ -132,6 +132,8 @@ const dataInterface: ServerInterface = {
|
|||
getOlderMessagesByConversation,
|
||||
getNewerMessagesByConversation,
|
||||
getMessageMetricsForConversation,
|
||||
getLastConversationActivity,
|
||||
getLastConversationPreview,
|
||||
migrateConversationMessages,
|
||||
|
||||
getUnprocessedCount,
|
||||
|
@ -2749,6 +2751,50 @@ async function getNewestMessageForConversation(conversationId: string) {
|
|||
|
||||
return row;
|
||||
}
|
||||
|
||||
async function getLastConversationActivity(
|
||||
conversationId: string
|
||||
): Promise<MessageType | null> {
|
||||
const db = getInstance();
|
||||
const row = await db.get(
|
||||
`SELECT * FROM messages WHERE
|
||||
conversationId = $conversationId AND
|
||||
type NOT IN ('profile-change', 'verified-change', 'message-history-unsynced') AND
|
||||
json_extract(json, '$.expirationTimerUpdate.fromSync') != true
|
||||
ORDER BY received_at DESC
|
||||
LIMIT 1;`,
|
||||
{
|
||||
$conversationId: conversationId,
|
||||
}
|
||||
);
|
||||
|
||||
if (!row) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return jsonToObject(row.json);
|
||||
}
|
||||
async function getLastConversationPreview(
|
||||
conversationId: string
|
||||
): Promise<MessageType | null> {
|
||||
const db = getInstance();
|
||||
const row = await db.get(
|
||||
`SELECT * FROM messages WHERE
|
||||
conversationId = $conversationId AND
|
||||
type NOT IN ('profile-change', 'verified-change', 'message-history-unsynced')
|
||||
ORDER BY received_at DESC
|
||||
LIMIT 1;`,
|
||||
{
|
||||
$conversationId: conversationId,
|
||||
}
|
||||
);
|
||||
|
||||
if (!row) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return jsonToObject(row.json);
|
||||
}
|
||||
async function getOldestUnreadMessageForConversation(conversationId: string) {
|
||||
const db = getInstance();
|
||||
const row = await db.get(
|
||||
|
|
|
@ -68,8 +68,18 @@ function renderEmojiPicker({
|
|||
function renderLastSeenIndicator(id: string): JSX.Element {
|
||||
return <FilteredSmartLastSeenIndicator id={id} />;
|
||||
}
|
||||
function renderHeroRow(id: string, onHeightChange: () => unknown): JSX.Element {
|
||||
return <FilteredSmartHeroRow id={id} onHeightChange={onHeightChange} />;
|
||||
function renderHeroRow(
|
||||
id: string,
|
||||
onHeightChange: () => unknown,
|
||||
updateSharedGroups: () => unknown
|
||||
): JSX.Element {
|
||||
return (
|
||||
<FilteredSmartHeroRow
|
||||
id={id}
|
||||
onHeightChange={onHeightChange}
|
||||
updateSharedGroups={updateSharedGroups}
|
||||
/>
|
||||
);
|
||||
}
|
||||
function renderLoadingRow(id: string): JSX.Element {
|
||||
return <FilteredSmartTimelineLoadingRow id={id} />;
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
import { assert } from 'chai';
|
||||
|
||||
import * as Conversation from '../../types/Conversation';
|
||||
import {
|
||||
IncomingMessage,
|
||||
MessageHistoryUnsyncedMessage,
|
||||
OutgoingMessage,
|
||||
ProfileChangeNotificationMessage,
|
||||
VerifiedChangeMessage,
|
||||
} from '../../types/Message';
|
||||
|
||||
describe('Conversation', () => {
|
||||
describe('createLastMessageUpdate', () => {
|
||||
it('should reset last message if conversation has no messages', () => {
|
||||
const input = {};
|
||||
const expected = {
|
||||
lastMessage: '',
|
||||
lastMessageStatus: null,
|
||||
timestamp: null,
|
||||
};
|
||||
|
||||
const actual = Conversation.createLastMessageUpdate(input);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
|
||||
context('for regular message', () => {
|
||||
it('should update last message text and timestamp', () => {
|
||||
const input = {
|
||||
currentTimestamp: 555,
|
||||
lastMessageStatus: 'read',
|
||||
lastMessage: {
|
||||
type: 'outgoing',
|
||||
conversationId: 'foo',
|
||||
sent_at: 666,
|
||||
timestamp: 666,
|
||||
} as OutgoingMessage,
|
||||
lastMessageNotificationText: 'New outgoing message',
|
||||
};
|
||||
const expected = {
|
||||
lastMessage: 'New outgoing message',
|
||||
lastMessageStatus: 'read',
|
||||
lastMessageDeletedForEveryone: undefined,
|
||||
timestamp: 666,
|
||||
};
|
||||
|
||||
const actual = Conversation.createLastMessageUpdate(input);
|
||||
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,
|
||||
lastMessageDeletedForEveryone: undefined,
|
||||
timestamp: 555,
|
||||
};
|
||||
|
||||
const actual = Conversation.createLastMessageUpdate(input);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
context('for verified change message', () => {
|
||||
it('should skip update', () => {
|
||||
const input = {
|
||||
currentTimestamp: 555,
|
||||
lastMessage: {
|
||||
type: 'verified-change',
|
||||
conversationId: 'foo',
|
||||
sent_at: 666,
|
||||
timestamp: 666,
|
||||
} as VerifiedChangeMessage,
|
||||
lastMessageNotificationText: 'Verified Changed',
|
||||
};
|
||||
const expected = {
|
||||
lastMessage: '',
|
||||
lastMessageStatus: null,
|
||||
lastMessageDeletedForEveryone: undefined,
|
||||
timestamp: 555,
|
||||
};
|
||||
|
||||
const actual = Conversation.createLastMessageUpdate(input);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
context('for expire timer update from sync', () => {
|
||||
it('should update message but not timestamp (to prevent bump to top)', () => {
|
||||
const input = {
|
||||
currentTimestamp: 555,
|
||||
lastMessage: {
|
||||
type: 'incoming',
|
||||
conversationId: 'foo',
|
||||
sent_at: 666,
|
||||
timestamp: 666,
|
||||
expirationTimerUpdate: {
|
||||
expireTimer: 111,
|
||||
fromSync: true,
|
||||
source: '+12223334455',
|
||||
},
|
||||
} as IncomingMessage,
|
||||
lastMessageNotificationText: 'Last message before expired',
|
||||
};
|
||||
const expected = {
|
||||
lastMessage: 'Last message before expired',
|
||||
lastMessageStatus: null,
|
||||
lastMessageDeletedForEveryone: undefined,
|
||||
timestamp: 555,
|
||||
};
|
||||
|
||||
const actual = Conversation.createLastMessageUpdate(input);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
|
||||
context('for profile change message', () => {
|
||||
it('should update message but not timestamp (to prevent bump to top)', () => {
|
||||
const input = {
|
||||
currentTimestamp: 555,
|
||||
lastMessage: {
|
||||
type: 'profile-change',
|
||||
conversationId: 'foo',
|
||||
sent_at: 666,
|
||||
timestamp: 666,
|
||||
} as ProfileChangeNotificationMessage,
|
||||
lastMessageNotificationText: 'John changed their profile name',
|
||||
};
|
||||
const expected = {
|
||||
lastMessage: 'John changed their profile name',
|
||||
lastMessageStatus: null,
|
||||
lastMessageDeletedForEveryone: undefined,
|
||||
timestamp: 555,
|
||||
};
|
||||
|
||||
const actual = Conversation.createLastMessageUpdate(input);
|
||||
assert.deepEqual(actual, expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1401,7 +1401,7 @@ class MessageReceiverInner extends EventTarget {
|
|||
}
|
||||
const to = sentMessage.message.group
|
||||
? `group(${sentMessage.message.group.id.toBinary()})`
|
||||
: sentMessage.destination;
|
||||
: sentMessage.destination || sentMessage.destinationUuid;
|
||||
|
||||
window.log.info(
|
||||
'sent message to',
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
import { Message } from './Message';
|
||||
|
||||
interface ConversationLastMessageUpdate {
|
||||
lastMessage: string;
|
||||
lastMessageStatus: string | null;
|
||||
timestamp: number | null;
|
||||
lastMessageDeletedForEveryone?: boolean;
|
||||
}
|
||||
|
||||
export const createLastMessageUpdate = ({
|
||||
currentTimestamp,
|
||||
lastMessage,
|
||||
lastMessageStatus,
|
||||
lastMessageNotificationText,
|
||||
}: {
|
||||
currentTimestamp?: number;
|
||||
lastMessage?: Message;
|
||||
lastMessageStatus?: string;
|
||||
lastMessageNotificationText?: string;
|
||||
}): ConversationLastMessageUpdate => {
|
||||
if (!lastMessage) {
|
||||
return {
|
||||
lastMessage: '',
|
||||
lastMessageStatus: null,
|
||||
timestamp: null,
|
||||
};
|
||||
}
|
||||
|
||||
const { type, expirationTimerUpdate, deletedForEveryone } = lastMessage;
|
||||
const isMessageHistoryUnsynced = type === 'message-history-unsynced';
|
||||
const isProfileChangedMessage = type === 'profile-change';
|
||||
const isVerifiedChangeMessage = type === 'verified-change';
|
||||
const isExpireTimerUpdateFromSync = Boolean(
|
||||
expirationTimerUpdate && expirationTimerUpdate.fromSync
|
||||
);
|
||||
|
||||
const shouldUpdateTimestamp = Boolean(
|
||||
!isMessageHistoryUnsynced &&
|
||||
!isProfileChangedMessage &&
|
||||
!isVerifiedChangeMessage &&
|
||||
!isExpireTimerUpdateFromSync
|
||||
);
|
||||
const newTimestamp = shouldUpdateTimestamp
|
||||
? lastMessage.sent_at
|
||||
: currentTimestamp;
|
||||
|
||||
const shouldUpdateLastMessageText = !isVerifiedChangeMessage;
|
||||
const newLastMessageText = shouldUpdateLastMessageText
|
||||
? lastMessageNotificationText
|
||||
: '';
|
||||
|
||||
return {
|
||||
lastMessage: deletedForEveryone ? '' : newLastMessageText || '',
|
||||
lastMessageStatus: lastMessageStatus || null,
|
||||
timestamp: newTimestamp || null,
|
||||
lastMessageDeletedForEveryone: deletedForEveryone,
|
||||
};
|
||||
};
|
|
@ -207,7 +207,7 @@
|
|||
"rule": "jQuery-wrap(",
|
||||
"path": "js/models/conversations.js",
|
||||
"line": " await wrap(",
|
||||
"lineNumber": 671,
|
||||
"lineNumber": 665,
|
||||
"reasonCategory": "falseMatch",
|
||||
"updated": "2020-06-09T20:26:46.515Z"
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue