diff --git a/lib/shared/dm-ops/create-thread-spec.js b/lib/shared/dm-ops/create-thread-spec.js --- a/lib/shared/dm-ops/create-thread-spec.js +++ b/lib/shared/dm-ops/create-thread-spec.js @@ -29,6 +29,7 @@ import { updateTypes } from '../../types/update-types-enum.js'; import { generatePendingThreadColor } from '../color-utils.js'; import { rawMessageInfoFromMessageData } from '../message-utils.js'; +import { createThreadTimestamps } from '../thread-utils.js'; function createRoleAndPermissionForThickThreads( threadType: ThickThreadType, @@ -78,11 +79,8 @@ pinnedCount, } = input; - const threadColor = - color ?? - generatePendingThreadColor( - allMemberIDsWithSubscriptions.map(({ id }) => id), - ); + const memberIDs = allMemberIDsWithSubscriptions.map(({ id }) => id); + const threadColor = color ?? generatePendingThreadColor(memberIDs); const { membershipPermissions, role } = createRoleAndPermissionForThickThreads(threadType, threadID, roleID); @@ -119,6 +117,7 @@ avatar, description, containingThreadID, + timestamps: createThreadTimestamps(creationTime, memberIDs), }; if (sourceMessageID) { newThread.sourceMessageID = sourceMessageID; diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js --- a/lib/shared/thread-utils.js +++ b/lib/shared/thread-utils.js @@ -86,6 +86,7 @@ UserProfileThreadInfo, MixedRawThreadInfos, LegacyThinRawThreadInfo, + ThreadTimestamps, } from '../types/thread-types.js'; import { updateTypes } from '../types/update-types-enum.js'; import { type ClientUpdateInfo } from '../types/update-types.js'; @@ -521,6 +522,7 @@ repliesCount: 0, sourceMessageID, pinnedCount: 0, + timestamps: createThreadTimestamps(now, memberIDs), }; } else { const thinThreadType = assertThinThreadType(threadType); @@ -1685,6 +1687,24 @@ return editableVisibleThreadInfos; } +function createThreadTimestamps( + timestamp: number, + memberIDs: $ReadOnlyArray, +): ThreadTimestamps { + return { + name: timestamp, + avatar: timestamp, + description: timestamp, + color: timestamp, + members: Object.fromEntries( + memberIDs.map(id => [id, { role: timestamp, subscription: timestamp }]), + ), + currentUser: { + unread: timestamp, + }, + }; +} + export { threadHasPermission, useCommunityRootMembersToRole, @@ -1750,4 +1770,5 @@ useOnScreenEntryEditableThreadInfos, extractMentionedMembers, isMemberActive, + createThreadTimestamps, }; diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js --- a/lib/types/thread-types.js +++ b/lib/types/thread-types.js @@ -119,6 +119,40 @@ +isSender: boolean, }; +export type ThreadTimestamps = { + +name: number, + +avatar: number, + +description: number, + +color: number, + +members: { + +[id: string]: { + +role: number, + +subscription: number, + }, + }, + +currentUser: { + +unread: number, + }, +}; + +export const threadTimestampsValidator: TInterface = + tShape({ + name: t.Number, + avatar: t.Number, + description: t.Number, + color: t.Number, + members: t.dict( + tUserID, + tShape({ + role: t.Number, + subscription: t.Number, + }), + ), + currentUser: tShape({ + unread: t.Number, + }), + }); + export type LegacyThickRawThreadInfo = { +thick: true, +id: string, @@ -136,6 +170,7 @@ +sourceMessageID?: string, +repliesCount: number, +pinnedCount?: number, + +timestamps: ThreadTimestamps, }; export type LegacyRawThreadInfo = diff --git a/lib/utils/thread-ops-utils.js b/lib/utils/thread-ops-utils.js --- a/lib/utils/thread-ops-utils.js +++ b/lib/utils/thread-ops-utils.js @@ -2,6 +2,7 @@ import invariant from 'invariant'; +import { assertWithValidator } from './validation-utils.js'; import { memberInfoWithPermissionsValidator, persistedRoleInfoValidator, @@ -31,6 +32,7 @@ type LegacyRawThreadInfo, clientLegacyRoleInfoValidator, legacyThreadCurrentUserInfoValidator, + threadTimestampsValidator, } from '../types/thread-types.js'; function convertRawThreadInfoToClientDBThreadInfo( @@ -45,6 +47,9 @@ currentUser: JSON.stringify(rawThreadInfo.currentUser), avatar: rawThreadInfo.avatar ? JSON.stringify(rawThreadInfo.avatar) : null, community: rawThreadInfo.community, + timestamps: rawThreadInfo.timestamps + ? JSON.stringify(rawThreadInfo.timestamps) + : null, }; } @@ -98,6 +103,14 @@ const threadType = assertThreadType(clientDBThreadInfo.type); if (threadTypeIsThick(threadType)) { const thickThreadType = assertThickThreadType(threadType); + invariant( + clientDBThreadInfo.timestamps, + 'Thick thread info must contain the timestamps', + ); + const threadTimestamps = assertWithValidator( + JSON.parse(clientDBThreadInfo.timestamps), + threadTimestampsValidator, + ); rawThreadInfo = { minimallyEncoded: true, thick: true, @@ -114,6 +127,7 @@ currentUser: minimallyEncodedCurrentUser, repliesCount: clientDBThreadInfo.repliesCount, pinnedCount: clientDBThreadInfo.pinnedCount, + timestamps: threadTimestamps, }; } else { const thinThreadType = assertThinThreadType(threadType); diff --git a/lib/utils/thread-ops-utils.test.js b/lib/utils/thread-ops-utils.test.js --- a/lib/utils/thread-ops-utils.test.js +++ b/lib/utils/thread-ops-utils.test.js @@ -385,6 +385,7 @@ community: '1', avatar: null, pinnedCount: 0, + timestamps: null, }; describe('convertRawThreadInfoToClientDBThreadInfo', () => {