Show group replies icon for stories with replies
This commit is contained in:
parent
ba55285c74
commit
471a9e2e98
13 changed files with 170 additions and 136 deletions
|
@ -1009,8 +1009,11 @@ export async function startApp(): Promise<void> {
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// This needs to load before we prime the data because we expect
|
||||||
|
// ConversationController to be loaded and ready to use by then.
|
||||||
|
await window.ConversationController.load();
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
window.ConversationController.load(),
|
|
||||||
Stickers.load(),
|
Stickers.load(),
|
||||||
loadRecentEmojis(),
|
loadRecentEmojis(),
|
||||||
loadInitialBadgesState(),
|
loadInitialBadgesState(),
|
||||||
|
|
|
@ -179,6 +179,8 @@ export const StoriesPane = ({
|
||||||
conversationId={story.conversationId}
|
conversationId={story.conversationId}
|
||||||
group={story.group}
|
group={story.group}
|
||||||
getPreferredBadge={getPreferredBadge}
|
getPreferredBadge={getPreferredBadge}
|
||||||
|
hasReplies={story.hasReplies}
|
||||||
|
hasRepliesFromSelf={story.hasRepliesFromSelf}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
key={story.storyView.timestamp}
|
key={story.storyView.timestamp}
|
||||||
onHideStory={toggleHideStories}
|
onHideStory={toggleHideStories}
|
||||||
|
|
|
@ -45,12 +45,12 @@ const Template: Story<PropsType> = args => <StoryListItem {...args} />;
|
||||||
|
|
||||||
export const SomeonesStory = Template.bind({});
|
export const SomeonesStory = Template.bind({});
|
||||||
SomeonesStory.args = {
|
SomeonesStory.args = {
|
||||||
|
hasReplies: true,
|
||||||
group: getDefaultConversation({ title: 'Sports Group' }),
|
group: getDefaultConversation({ title: 'Sports Group' }),
|
||||||
story: {
|
story: {
|
||||||
attachment: fakeAttachment({
|
attachment: fakeAttachment({
|
||||||
thumbnail: fakeThumbnail('/fixtures/tina-rolf-269345-unsplash.jpg'),
|
thumbnail: fakeThumbnail('/fixtures/tina-rolf-269345-unsplash.jpg'),
|
||||||
}),
|
}),
|
||||||
hasReplies: true,
|
|
||||||
isUnread: true,
|
isUnread: true,
|
||||||
messageId: '123',
|
messageId: '123',
|
||||||
messageIdForLogging: 'for logging 123',
|
messageIdForLogging: 'for logging 123',
|
||||||
|
|
|
@ -21,6 +21,8 @@ import { getAvatarColor } from '../types/Colors';
|
||||||
export type PropsType = Pick<ConversationStoryType, 'group' | 'isHidden'> & {
|
export type PropsType = Pick<ConversationStoryType, 'group' | 'isHidden'> & {
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
getPreferredBadge: PreferredBadgeSelectorType;
|
getPreferredBadge: PreferredBadgeSelectorType;
|
||||||
|
hasReplies?: boolean;
|
||||||
|
hasRepliesFromSelf?: boolean;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
onGoToConversation: (conversationId: string) => unknown;
|
onGoToConversation: (conversationId: string) => unknown;
|
||||||
onHideStory: (conversationId: string) => unknown;
|
onHideStory: (conversationId: string) => unknown;
|
||||||
|
@ -79,6 +81,8 @@ export const StoryListItem = ({
|
||||||
conversationId,
|
conversationId,
|
||||||
getPreferredBadge,
|
getPreferredBadge,
|
||||||
group,
|
group,
|
||||||
|
hasReplies,
|
||||||
|
hasRepliesFromSelf,
|
||||||
i18n,
|
i18n,
|
||||||
isHidden,
|
isHidden,
|
||||||
onGoToConversation,
|
onGoToConversation,
|
||||||
|
@ -89,14 +93,7 @@ export const StoryListItem = ({
|
||||||
}: PropsType): JSX.Element => {
|
}: PropsType): JSX.Element => {
|
||||||
const [hasConfirmHideStory, setHasConfirmHideStory] = useState(false);
|
const [hasConfirmHideStory, setHasConfirmHideStory] = useState(false);
|
||||||
|
|
||||||
const {
|
const { attachment, isUnread, sender, timestamp } = story;
|
||||||
attachment,
|
|
||||||
hasReplies,
|
|
||||||
hasRepliesFromSelf,
|
|
||||||
isUnread,
|
|
||||||
sender,
|
|
||||||
timestamp,
|
|
||||||
} = story;
|
|
||||||
|
|
||||||
const { firstName, title } = sender;
|
const { firstName, title } = sender;
|
||||||
|
|
||||||
|
|
|
@ -11,16 +11,51 @@ import { getAttachmentsForMessage } from '../state/selectors/message';
|
||||||
import { isNotNil } from '../util/isNotNil';
|
import { isNotNil } from '../util/isNotNil';
|
||||||
import { strictAssert } from '../util/assert';
|
import { strictAssert } from '../util/assert';
|
||||||
import { dropNull } from '../util/dropNull';
|
import { dropNull } from '../util/dropNull';
|
||||||
|
import { isGroup } from '../util/whatTypeOfConversation';
|
||||||
|
|
||||||
let storyData: Array<MessageAttributesType> | undefined;
|
let storyData:
|
||||||
|
| Array<
|
||||||
|
MessageAttributesType & {
|
||||||
|
hasReplies?: boolean;
|
||||||
|
hasRepliesFromSelf?: boolean;
|
||||||
|
}
|
||||||
|
>
|
||||||
|
| undefined;
|
||||||
|
|
||||||
export async function loadStories(): Promise<void> {
|
export async function loadStories(): Promise<void> {
|
||||||
storyData = await dataInterface.getOlderStories({});
|
const stories = await dataInterface.getAllStories({});
|
||||||
|
|
||||||
|
storyData = await Promise.all(
|
||||||
|
stories.map(async story => {
|
||||||
|
const conversation = window.ConversationController.get(
|
||||||
|
story.conversationId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isGroup(conversation?.attributes)) {
|
||||||
|
return story;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [hasReplies, hasRepliesFromSelf] = await Promise.all([
|
||||||
|
dataInterface.hasStoryReplies(story.id),
|
||||||
|
dataInterface.hasStoryRepliesFromSelf(story.id),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...story,
|
||||||
|
hasReplies,
|
||||||
|
hasRepliesFromSelf,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
await repairUnexpiredStories();
|
await repairUnexpiredStories();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getStoryDataFromMessageAttributes(
|
export function getStoryDataFromMessageAttributes(
|
||||||
message: MessageAttributesType
|
message: MessageAttributesType & {
|
||||||
|
hasReplies?: boolean;
|
||||||
|
hasRepliesFromSelf?: boolean;
|
||||||
|
}
|
||||||
): StoryDataType | undefined {
|
): StoryDataType | undefined {
|
||||||
const { attachments, deletedForEveryone } = message;
|
const { attachments, deletedForEveryone } = message;
|
||||||
const unresolvedAttachment = attachments ? attachments[0] : undefined;
|
const unresolvedAttachment = attachments ? attachments[0] : undefined;
|
||||||
|
@ -43,6 +78,8 @@ export function getStoryDataFromMessageAttributes(
|
||||||
'canReplyToStory',
|
'canReplyToStory',
|
||||||
'conversationId',
|
'conversationId',
|
||||||
'deletedForEveryone',
|
'deletedForEveryone',
|
||||||
|
'hasReplies',
|
||||||
|
'hasRepliesFromSelf',
|
||||||
'reactions',
|
'reactions',
|
||||||
'readAt',
|
'readAt',
|
||||||
'readStatus',
|
'readStatus',
|
||||||
|
|
|
@ -256,7 +256,9 @@ const dataInterface: ClientInterface = {
|
||||||
getNextTapToViewMessageTimestampToAgeOut,
|
getNextTapToViewMessageTimestampToAgeOut,
|
||||||
getTapToViewMessagesNeedingErase,
|
getTapToViewMessagesNeedingErase,
|
||||||
getOlderMessagesByConversation,
|
getOlderMessagesByConversation,
|
||||||
getOlderStories,
|
getAllStories,
|
||||||
|
hasStoryReplies,
|
||||||
|
hasStoryRepliesFromSelf,
|
||||||
getNewerMessagesByConversation,
|
getNewerMessagesByConversation,
|
||||||
getMessageMetricsForConversation,
|
getMessageMetricsForConversation,
|
||||||
getConversationRangeCenteredOnMessage,
|
getConversationRangeCenteredOnMessage,
|
||||||
|
@ -1349,14 +1351,20 @@ async function getOlderMessagesByConversation(
|
||||||
|
|
||||||
return handleMessageJSON(messages);
|
return handleMessageJSON(messages);
|
||||||
}
|
}
|
||||||
async function getOlderStories(options: {
|
|
||||||
|
async function getAllStories(options: {
|
||||||
conversationId?: string;
|
conversationId?: string;
|
||||||
limit?: number;
|
|
||||||
receivedAt?: number;
|
|
||||||
sentAt?: number;
|
|
||||||
sourceUuid?: UUIDStringType;
|
sourceUuid?: UUIDStringType;
|
||||||
}): Promise<Array<MessageType>> {
|
}): Promise<Array<MessageType>> {
|
||||||
return channels.getOlderStories(options);
|
return channels.getAllStories(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hasStoryReplies(storyId: string): Promise<boolean> {
|
||||||
|
return channels.hasStoryReplies(storyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hasStoryRepliesFromSelf(storyId: string): Promise<boolean> {
|
||||||
|
return channels.hasStoryRepliesFromSelf(storyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getNewerMessagesByConversation(
|
async function getNewerMessagesByConversation(
|
||||||
|
|
|
@ -508,13 +508,12 @@ export type DataInterface = {
|
||||||
getNextTapToViewMessageTimestampToAgeOut: () => Promise<undefined | number>;
|
getNextTapToViewMessageTimestampToAgeOut: () => Promise<undefined | number>;
|
||||||
getTapToViewMessagesNeedingErase: () => Promise<Array<MessageType>>;
|
getTapToViewMessagesNeedingErase: () => Promise<Array<MessageType>>;
|
||||||
// getOlderMessagesByConversation is JSON on server, full message on Client
|
// getOlderMessagesByConversation is JSON on server, full message on Client
|
||||||
getOlderStories: (options: {
|
getAllStories: (options: {
|
||||||
conversationId?: string;
|
conversationId?: string;
|
||||||
limit?: number;
|
|
||||||
receivedAt?: number;
|
|
||||||
sentAt?: number;
|
|
||||||
sourceUuid?: UUIDStringType;
|
sourceUuid?: UUIDStringType;
|
||||||
}) => Promise<Array<MessageType>>;
|
}) => Promise<Array<MessageType>>;
|
||||||
|
hasStoryReplies: (storyId: string) => Promise<boolean>;
|
||||||
|
hasStoryRepliesFromSelf: (storyId: string) => Promise<boolean>;
|
||||||
// getNewerMessagesByConversation is JSON on server, full message on Client
|
// getNewerMessagesByConversation is JSON on server, full message on Client
|
||||||
getMessageMetricsForConversation: (
|
getMessageMetricsForConversation: (
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
|
|
|
@ -246,7 +246,9 @@ const dataInterface: ServerInterface = {
|
||||||
getNextTapToViewMessageTimestampToAgeOut,
|
getNextTapToViewMessageTimestampToAgeOut,
|
||||||
getTapToViewMessagesNeedingErase,
|
getTapToViewMessagesNeedingErase,
|
||||||
getOlderMessagesByConversation,
|
getOlderMessagesByConversation,
|
||||||
getOlderStories,
|
getAllStories,
|
||||||
|
hasStoryReplies,
|
||||||
|
hasStoryRepliesFromSelf,
|
||||||
getNewerMessagesByConversation,
|
getNewerMessagesByConversation,
|
||||||
getTotalUnreadForConversation,
|
getTotalUnreadForConversation,
|
||||||
getMessageMetricsForConversation,
|
getMessageMetricsForConversation,
|
||||||
|
@ -2501,17 +2503,11 @@ function getOlderMessagesByConversationSync(
|
||||||
.reverse();
|
.reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getOlderStories({
|
async function getAllStories({
|
||||||
conversationId,
|
conversationId,
|
||||||
limit = 9999,
|
|
||||||
receivedAt = Number.MAX_VALUE,
|
|
||||||
sentAt,
|
|
||||||
sourceUuid,
|
sourceUuid,
|
||||||
}: {
|
}: {
|
||||||
conversationId?: string;
|
conversationId?: string;
|
||||||
limit?: number;
|
|
||||||
receivedAt?: number;
|
|
||||||
sentAt?: number;
|
|
||||||
sourceUuid?: UUIDStringType;
|
sourceUuid?: UUIDStringType;
|
||||||
}): Promise<Array<MessageType>> {
|
}): Promise<Array<MessageType>> {
|
||||||
const db = getInstance();
|
const db = getInstance();
|
||||||
|
@ -2523,25 +2519,50 @@ async function getOlderStories({
|
||||||
WHERE
|
WHERE
|
||||||
type IS 'story' AND
|
type IS 'story' AND
|
||||||
($conversationId IS NULL OR conversationId IS $conversationId) AND
|
($conversationId IS NULL OR conversationId IS $conversationId) AND
|
||||||
($sourceUuid IS NULL OR sourceUuid IS $sourceUuid) AND
|
($sourceUuid IS NULL OR sourceUuid IS $sourceUuid)
|
||||||
(received_at < $receivedAt
|
ORDER BY received_at ASC, sent_at ASC;
|
||||||
OR (received_at IS $receivedAt AND sent_at < $sentAt)
|
|
||||||
)
|
|
||||||
ORDER BY received_at ASC, sent_at ASC
|
|
||||||
LIMIT $limit;
|
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
.all({
|
.all({
|
||||||
conversationId: conversationId || null,
|
conversationId: conversationId || null,
|
||||||
receivedAt,
|
|
||||||
sentAt: sentAt || null,
|
|
||||||
sourceUuid: sourceUuid || null,
|
sourceUuid: sourceUuid || null,
|
||||||
limit,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return rows.map(row => jsonToObject(row.json));
|
return rows.map(row => jsonToObject(row.json));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function hasStoryReplies(storyId: string): Promise<boolean> {
|
||||||
|
const db = getInstance();
|
||||||
|
|
||||||
|
const row: { count: number } = db
|
||||||
|
.prepare<Query>(
|
||||||
|
`
|
||||||
|
SELECT COUNT(*) as count
|
||||||
|
FROM messages
|
||||||
|
WHERE storyId IS $storyId;
|
||||||
|
`
|
||||||
|
)
|
||||||
|
.get({ storyId });
|
||||||
|
|
||||||
|
return row.count !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function hasStoryRepliesFromSelf(storyId: string): Promise<boolean> {
|
||||||
|
const db = getInstance();
|
||||||
|
|
||||||
|
const sql = `
|
||||||
|
SELECT COUNT(*) as count
|
||||||
|
FROM messages
|
||||||
|
WHERE
|
||||||
|
storyId IS $storyId AND
|
||||||
|
type IS 'outgoing'
|
||||||
|
`;
|
||||||
|
|
||||||
|
const row: { count: number } = db.prepare<Query>(sql).get({ storyId });
|
||||||
|
|
||||||
|
return row.count !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
async function getNewerMessagesByConversation(
|
async function getNewerMessagesByConversation(
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
options: {
|
options: {
|
||||||
|
|
|
@ -55,6 +55,8 @@ import { viewedReceiptsJobQueue } from '../../jobs/viewedReceiptsJobQueue';
|
||||||
|
|
||||||
export type StoryDataType = {
|
export type StoryDataType = {
|
||||||
attachment?: AttachmentType;
|
attachment?: AttachmentType;
|
||||||
|
hasReplies?: boolean;
|
||||||
|
hasRepliesFromSelf?: boolean;
|
||||||
messageId: string;
|
messageId: string;
|
||||||
startedDownload?: boolean;
|
startedDownload?: boolean;
|
||||||
} & Pick<
|
} & Pick<
|
||||||
|
@ -156,7 +158,10 @@ type QueueStoryDownloadActionType = {
|
||||||
|
|
||||||
type ReplyToStoryActionType = {
|
type ReplyToStoryActionType = {
|
||||||
type: typeof REPLY_TO_STORY;
|
type: typeof REPLY_TO_STORY;
|
||||||
payload: MessageAttributesType;
|
payload: {
|
||||||
|
message: MessageAttributesType;
|
||||||
|
storyId: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type ResolveAttachmentUrlActionType = {
|
type ResolveAttachmentUrlActionType = {
|
||||||
|
@ -470,7 +475,10 @@ function replyToStory(
|
||||||
if (messageAttributes) {
|
if (messageAttributes) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: REPLY_TO_STORY,
|
type: REPLY_TO_STORY,
|
||||||
payload: messageAttributes,
|
payload: {
|
||||||
|
message: messageAttributes,
|
||||||
|
storyId: story.messageId,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1211,6 +1219,8 @@ export function reducer(
|
||||||
'deletedForEveryone',
|
'deletedForEveryone',
|
||||||
'expirationStartTimestamp',
|
'expirationStartTimestamp',
|
||||||
'expireTimer',
|
'expireTimer',
|
||||||
|
'hasReplies',
|
||||||
|
'hasRepliesFromSelf',
|
||||||
'messageId',
|
'messageId',
|
||||||
'reactions',
|
'reactions',
|
||||||
'readAt',
|
'readAt',
|
||||||
|
@ -1311,6 +1321,19 @@ export function reducer(
|
||||||
if (action.type === LOAD_STORY_REPLIES) {
|
if (action.type === LOAD_STORY_REPLIES) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
stories: state.stories.map(story => {
|
||||||
|
if (story.messageId === action.payload.messageId) {
|
||||||
|
return {
|
||||||
|
...story,
|
||||||
|
hasReplies: action.payload.replies.length > 0,
|
||||||
|
hasRepliesFromSelf: action.payload.replies.some(
|
||||||
|
reply => reply.type === 'outgoing'
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return story;
|
||||||
|
}),
|
||||||
replyState: action.payload,
|
replyState: action.payload,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1373,15 +1396,31 @@ export function reducer(
|
||||||
|
|
||||||
if (action.type === REPLY_TO_STORY) {
|
if (action.type === REPLY_TO_STORY) {
|
||||||
const { replyState } = state;
|
const { replyState } = state;
|
||||||
|
|
||||||
|
const stories = state.stories.map(story => {
|
||||||
|
if (story.messageId === action.payload.storyId) {
|
||||||
|
return {
|
||||||
|
...story,
|
||||||
|
hasRepliesFromSelf: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return story;
|
||||||
|
});
|
||||||
|
|
||||||
if (!replyState) {
|
if (!replyState) {
|
||||||
return state;
|
return {
|
||||||
|
...state,
|
||||||
|
stories,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
stories,
|
||||||
replyState: {
|
replyState: {
|
||||||
messageId: replyState.messageId,
|
messageId: replyState.messageId,
|
||||||
replies: [...replyState.replies, action.payload],
|
replies: [...replyState.replies, action.payload.message],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,6 +249,8 @@ export function getConversationStory(
|
||||||
return {
|
return {
|
||||||
conversationId: conversation.id,
|
conversationId: conversation.id,
|
||||||
group: conversation.id !== sender.id ? conversation : undefined,
|
group: conversation.id !== sender.id ? conversation : undefined,
|
||||||
|
hasReplies: story.hasReplies,
|
||||||
|
hasRepliesFromSelf: story.hasRepliesFromSelf,
|
||||||
isHidden: Boolean(sender.hideStory),
|
isHidden: Boolean(sender.hideStory),
|
||||||
storyView,
|
storyView,
|
||||||
};
|
};
|
||||||
|
@ -430,6 +432,11 @@ export const getStories = createSelector(
|
||||||
storiesMap.set(conversationStory.conversationId, {
|
storiesMap.set(conversationStory.conversationId, {
|
||||||
...existingConversationStory,
|
...existingConversationStory,
|
||||||
...conversationStory,
|
...conversationStory,
|
||||||
|
hasReplies:
|
||||||
|
existingConversationStory?.hasReplies || conversationStory.hasReplies,
|
||||||
|
hasRepliesFromSelf:
|
||||||
|
existingConversationStory?.hasRepliesFromSelf ||
|
||||||
|
conversationStory.hasRepliesFromSelf,
|
||||||
storyView: conversationStory.storyView,
|
storyView: conversationStory.storyView,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -49,7 +49,6 @@ export function getFakeStoryView(
|
||||||
attachment: getAttachmentWithThumbnail(
|
attachment: getAttachmentWithThumbnail(
|
||||||
attachmentUrl || '/fixtures/tina-rolf-269345-unsplash.jpg'
|
attachmentUrl || '/fixtures/tina-rolf-269345-unsplash.jpg'
|
||||||
),
|
),
|
||||||
hasReplies: Boolean(casual.coin_flip),
|
|
||||||
isUnread: Boolean(casual.coin_flip),
|
isUnread: Boolean(casual.coin_flip),
|
||||||
messageId,
|
messageId,
|
||||||
messageIdForLogging: `${messageId} (for logging)`,
|
messageIdForLogging: `${messageId} (for logging)`,
|
||||||
|
@ -70,8 +69,14 @@ export function getFakeStory({
|
||||||
}): ConversationStoryType {
|
}): ConversationStoryType {
|
||||||
const storyView = getFakeStoryView(attachmentUrl, timestamp);
|
const storyView = getFakeStoryView(attachmentUrl, timestamp);
|
||||||
|
|
||||||
|
const hasReplies = group ? Boolean(casual.coin_flip) : false;
|
||||||
|
const hasRepliesFromSelf =
|
||||||
|
group && hasReplies ? Boolean(casual.coin_flip) : false;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
conversationId: storyView.sender.id,
|
conversationId: storyView.sender.id,
|
||||||
|
hasReplies,
|
||||||
|
hasRepliesFromSelf,
|
||||||
group,
|
group,
|
||||||
storyView,
|
storyView,
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ import type { UUIDStringType } from '../../types/UUID';
|
||||||
|
|
||||||
import type { MessageAttributesType } from '../../model-types.d';
|
import type { MessageAttributesType } from '../../model-types.d';
|
||||||
|
|
||||||
const { removeAll, _getAllMessages, saveMessages, getOlderStories } =
|
const { removeAll, _getAllMessages, saveMessages, getAllStories } =
|
||||||
dataInterface;
|
dataInterface;
|
||||||
|
|
||||||
function getUuid(): UUIDStringType {
|
function getUuid(): UUIDStringType {
|
||||||
|
@ -21,7 +21,7 @@ describe('sql/stories', () => {
|
||||||
await removeAll();
|
await removeAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getOlderStories', () => {
|
describe('getAllStories', () => {
|
||||||
it('returns N most recent stories overall, or in converation, or by author', async () => {
|
it('returns N most recent stories overall, or in converation, or by author', async () => {
|
||||||
assert.lengthOf(await _getAllMessages(), 0);
|
assert.lengthOf(await _getAllMessages(), 0);
|
||||||
|
|
||||||
|
@ -88,9 +88,7 @@ describe('sql/stories', () => {
|
||||||
|
|
||||||
assert.lengthOf(await _getAllMessages(), 5);
|
assert.lengthOf(await _getAllMessages(), 5);
|
||||||
|
|
||||||
const stories = await getOlderStories({
|
const stories = await getAllStories({});
|
||||||
limit: 5,
|
|
||||||
});
|
|
||||||
assert.lengthOf(stories, 4, 'expect four total stories');
|
assert.lengthOf(stories, 4, 'expect four total stories');
|
||||||
|
|
||||||
// They are in ASC order
|
// They are in ASC order
|
||||||
|
@ -105,9 +103,8 @@ describe('sql/stories', () => {
|
||||||
'stories last should be story1'
|
'stories last should be story1'
|
||||||
);
|
);
|
||||||
|
|
||||||
const storiesInConversation = await getOlderStories({
|
const storiesInConversation = await getAllStories({
|
||||||
conversationId,
|
conversationId,
|
||||||
limit: 5,
|
|
||||||
});
|
});
|
||||||
assert.lengthOf(
|
assert.lengthOf(
|
||||||
storiesInConversation,
|
storiesInConversation,
|
||||||
|
@ -127,9 +124,8 @@ describe('sql/stories', () => {
|
||||||
'storiesInConversation last should be story1'
|
'storiesInConversation last should be story1'
|
||||||
);
|
);
|
||||||
|
|
||||||
const storiesByAuthor = await getOlderStories({
|
const storiesByAuthor = await getAllStories({
|
||||||
sourceUuid,
|
sourceUuid,
|
||||||
limit: 5,
|
|
||||||
});
|
});
|
||||||
assert.lengthOf(storiesByAuthor, 2, 'expect two stories by author');
|
assert.lengthOf(storiesByAuthor, 2, 'expect two stories by author');
|
||||||
|
|
||||||
|
@ -145,85 +141,5 @@ describe('sql/stories', () => {
|
||||||
'storiesByAuthor last should be story2'
|
'storiesByAuthor last should be story2'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns N stories older than provided receivedAt/sentAt', async () => {
|
|
||||||
assert.lengthOf(await _getAllMessages(), 0);
|
|
||||||
|
|
||||||
const start = Date.now();
|
|
||||||
const conversationId = getUuid();
|
|
||||||
const ourUuid = getUuid();
|
|
||||||
|
|
||||||
const story1: MessageAttributesType = {
|
|
||||||
id: getUuid(),
|
|
||||||
body: 'message 1',
|
|
||||||
type: 'incoming',
|
|
||||||
conversationId,
|
|
||||||
sent_at: start - 2,
|
|
||||||
received_at: start - 2,
|
|
||||||
timestamp: start - 2,
|
|
||||||
};
|
|
||||||
const story2: MessageAttributesType = {
|
|
||||||
id: getUuid(),
|
|
||||||
body: 'story 2',
|
|
||||||
type: 'story',
|
|
||||||
conversationId,
|
|
||||||
sent_at: start - 1,
|
|
||||||
received_at: start - 1,
|
|
||||||
timestamp: start - 1,
|
|
||||||
};
|
|
||||||
const story3: MessageAttributesType = {
|
|
||||||
id: getUuid(),
|
|
||||||
body: 'story 3',
|
|
||||||
type: 'story',
|
|
||||||
conversationId,
|
|
||||||
sent_at: start - 1,
|
|
||||||
received_at: start,
|
|
||||||
timestamp: start,
|
|
||||||
};
|
|
||||||
const story4: MessageAttributesType = {
|
|
||||||
id: getUuid(),
|
|
||||||
body: 'story 4',
|
|
||||||
type: 'story',
|
|
||||||
conversationId,
|
|
||||||
sent_at: start,
|
|
||||||
received_at: start,
|
|
||||||
timestamp: start,
|
|
||||||
};
|
|
||||||
const story5: MessageAttributesType = {
|
|
||||||
id: getUuid(),
|
|
||||||
body: 'story 5',
|
|
||||||
type: 'story',
|
|
||||||
conversationId,
|
|
||||||
sent_at: start + 1,
|
|
||||||
received_at: start + 1,
|
|
||||||
timestamp: start + 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
await saveMessages([story1, story2, story3, story4, story5], {
|
|
||||||
forceSave: true,
|
|
||||||
ourUuid,
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.lengthOf(await _getAllMessages(), 5);
|
|
||||||
|
|
||||||
const stories = await getOlderStories({
|
|
||||||
receivedAt: story4.received_at,
|
|
||||||
sentAt: story4.sent_at,
|
|
||||||
limit: 5,
|
|
||||||
});
|
|
||||||
assert.lengthOf(stories, 2, 'expect two stories');
|
|
||||||
|
|
||||||
// They are in ASC order
|
|
||||||
assert.strictEqual(
|
|
||||||
stories[0].id,
|
|
||||||
story2.id,
|
|
||||||
'stories first should be story3'
|
|
||||||
);
|
|
||||||
assert.strictEqual(
|
|
||||||
stories[1].id,
|
|
||||||
story3.id,
|
|
||||||
'stories last should be story2'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,6 +42,8 @@ export type ReplyStateType = {
|
||||||
|
|
||||||
export type ConversationStoryType = {
|
export type ConversationStoryType = {
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
|
hasReplies?: boolean;
|
||||||
|
hasRepliesFromSelf?: boolean;
|
||||||
group?: Pick<
|
group?: Pick<
|
||||||
ConversationType,
|
ConversationType,
|
||||||
| 'acceptedMessageRequest'
|
| 'acceptedMessageRequest'
|
||||||
|
@ -70,8 +72,6 @@ export type StorySendStateType = {
|
||||||
export type StoryViewType = {
|
export type StoryViewType = {
|
||||||
attachment?: AttachmentType;
|
attachment?: AttachmentType;
|
||||||
canReply?: boolean;
|
canReply?: boolean;
|
||||||
hasReplies?: boolean;
|
|
||||||
hasRepliesFromSelf?: boolean;
|
|
||||||
isHidden?: boolean;
|
isHidden?: boolean;
|
||||||
isUnread?: boolean;
|
isUnread?: boolean;
|
||||||
messageId: string;
|
messageId: string;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue