Files
ThreadNet-Web/apps/web/src/viewmodels/room/timeline/event-tile/EventTileThreadState.ts
T
rbondessonandGitHub 03360eb260 Refactor EventTile using the MVVM pattern - #5a (#33587)
* Extract EventTile receipt state

* Extract EventTile thread state

* Extract EventTile reaction relation state

* Extract EventTile reply-chain state

* Keep reply chain collapse wiring in EventTile

* Reuse message event eligibility for receipts
2026-05-22 18:25:32 +00:00

97 lines
3.3 KiB
TypeScript

/*
Copyright 2026 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import { type MatrixEvent, type Thread } from "matrix-js-sdk/src/matrix";
import { TimelineRenderingType } from "../../../../contexts/RoomContext";
/** Minimal room surface used to look up a thread for an event. */
export interface EventTileThreadLookup {
/** Finds the thread associated with an event. */
findThreadForEvent(mxEvent: MatrixEvent): Thread | null | undefined;
}
/** Search thread-info rendering kind. */
export type SearchThreadInfoKind = "none" | "text" | "link";
/** Search timeline thread-info display state. */
export interface EventTileSearchThreadInfo {
/** Kind of search thread info to render. */
kind: SearchThreadInfoKind;
/** Link target when rendering linked thread info. */
href?: string;
}
/** Inputs for deriving EventTile thread display state. */
export interface EventTileThreadStateInput {
/** Matrix event rendered by the tile. */
mxEvent: MatrixEvent;
/** Thread associated with the event, when available. */
thread: Thread | null;
/** Current timeline rendering mode. */
timelineRenderingType: TimelineRenderingType;
/** Optional search-result link for thread info. */
highlightLink?: string;
}
/** EventTile thread display state. */
export interface EventTileThreadState {
/** Thread associated with the event, when available. */
thread: Thread | null;
/** Whether EventTile should render the main thread summary. */
shouldShowThreadSummary: boolean;
/** Whether EventTile should render the thread panel reply summary. */
shouldShowThreadPanelSummary: boolean;
/** Timestamp of the latest thread reply, when available. */
threadReplyEventTs?: number;
/** Search timeline thread-info display state. */
searchThreadInfo: EventTileSearchThreadInfo;
}
/**
* Finds the thread associated with an event.
*
* Accessing the thread through the room covers a race where the event has not
* discovered its thread yet during sync.
*/
export function getEventTileThread(mxEvent: MatrixEvent, room?: EventTileThreadLookup | null): Thread | null {
return mxEvent.getThread() ?? room?.findThreadForEvent(mxEvent) ?? null;
}
function getSearchThreadInfo(shouldShowSearchThreadInfo: boolean, highlightLink?: string): EventTileSearchThreadInfo {
if (!shouldShowSearchThreadInfo) {
return { kind: "none" };
}
if (highlightLink) {
return { kind: "link", href: highlightLink };
}
return { kind: "text" };
}
/** Derives thread display state for EventTile. */
export function getEventTileThreadState({
mxEvent,
thread,
timelineRenderingType,
highlightLink,
}: EventTileThreadStateInput): EventTileThreadState {
const shouldShowThreadSummary = !!thread && thread.id === mxEvent.getId();
const shouldShowSearchThreadInfo =
!shouldShowThreadSummary && timelineRenderingType === TimelineRenderingType.Search && !!mxEvent.threadRootId;
const searchThreadInfo = getSearchThreadInfo(shouldShowSearchThreadInfo, highlightLink);
return {
thread,
shouldShowThreadSummary,
shouldShowThreadPanelSummary: !!thread,
threadReplyEventTs: thread?.replyToEvent?.getTs(),
searchThreadInfo,
};
}