Files
cinny/src/app/features/room/thread/threadSummary.ts
T

56 lines
1.8 KiB
TypeScript
Raw Normal View History

import { EventStatus, IThreadBundledRelationship, MatrixEvent, RelationType } from 'matrix-js-sdk';
export type ThreadSummaryData = {
count: number;
latestTs: number | undefined;
};
/**
* Summary data for a thread root's "N replies" chip.
*
* Prefers the live {@link Thread} object when it exists (it reflects local
* echo + pagination), otherwise falls back to the server-aggregated bundle
* (`unsigned['m.relations']['m.thread']`) so the chip renders before any
* Thread object has been created. Returns `undefined` when the root has no
* thread at all.
*/
export const getThreadSummary = (rootEvent: MatrixEvent): ThreadSummaryData | undefined => {
const thread = rootEvent.getThread();
if (thread) {
const lastReply = thread.lastReply();
return {
count: thread.length,
latestTs: lastReply?.getTs(),
};
}
const bundle = rootEvent.getServerAggregatedRelation<IThreadBundledRelationship>(
RelationType.Thread,
);
if (bundle) {
return {
count: bundle.count,
latestTs: bundle.latest_event?.origin_server_ts,
};
}
return undefined;
};
/**
* True when `event` is a still-in-flight (local echo) reply belonging to the
* given thread root. Used to render the pending strip, since pending thread
* sends never enter the thread's timelineSet.
*/
export const isPendingThreadReply = (event: MatrixEvent, threadRootId: string): boolean => {
const { status } = event;
if (status !== EventStatus.SENDING && status !== EventStatus.NOT_SENT) return false;
// Prefer the SDK's resolved thread root id; fall back to the raw relation
// content for events the SDK hasn't associated with a thread yet.
if (event.threadRootId === threadRootId) return true;
const relation = event.getRelation();
return relation?.rel_type === RelationType.Thread && relation.event_id === threadRootId;
};