57 lines
1.9 KiB
TypeScript
57 lines
1.9 KiB
TypeScript
import {
|
|
chatConnectionStateLabelKey,
|
|
type ChatChannelDetailVM,
|
|
type ChatMessageDayGroupVM,
|
|
type ChatMessageVM,
|
|
type ChatPresenceVM,
|
|
} from "@hivegrid/view-models";
|
|
|
|
import type { ChatRealtimeConnection } from "./chatChannelRealtimeReducer";
|
|
|
|
export type ChatChannelRealtimeViewOverlay = {
|
|
readonly messages: readonly ChatMessageVM[];
|
|
readonly messageGroups: readonly ChatMessageDayGroupVM[];
|
|
readonly presence: readonly ChatPresenceVM[];
|
|
readonly typingLabels: readonly string[];
|
|
readonly connection: ChatRealtimeConnection;
|
|
};
|
|
|
|
/** Applies transport-only state to the loader-owned render contract. Repository
|
|
* records never cross this boundary. */
|
|
export function overlayChatChannelDetailRealtime(vm: ChatChannelDetailVM, overlay: ChatChannelRealtimeViewOverlay): ChatChannelDetailVM {
|
|
if (vm.status !== "ready") return vm;
|
|
const canRetry = overlay.connection.state === "offline" || overlay.connection.state === "reconnecting";
|
|
const composer =
|
|
overlay.connection.state === "blocked"
|
|
? {
|
|
...vm.data.composer,
|
|
enabled: false,
|
|
disabledReasonKey: "chat.composer.connectionBlocked",
|
|
canSend: false,
|
|
canAttachFiles: false,
|
|
canRecordVoice: false,
|
|
canMention: false,
|
|
canMarkAsTask: false,
|
|
}
|
|
: vm.data.composer;
|
|
return {
|
|
status: "ready",
|
|
data: {
|
|
...vm.data,
|
|
messages: overlay.messages,
|
|
messageGroups: overlay.messageGroups,
|
|
presence: overlay.presence.map(({ userId, status }) => ({ userId, status })),
|
|
typingLabels: overlay.typingLabels,
|
|
composer,
|
|
connection: {
|
|
...vm.data.connection,
|
|
state: overlay.connection.state,
|
|
stateLabelKey: chatConnectionStateLabelKey(overlay.connection.state),
|
|
reconnectAttempt: overlay.connection.reconnectAttempt,
|
|
retryAtIso: overlay.connection.retryAtIso,
|
|
canRetry,
|
|
},
|
|
},
|
|
};
|
|
}
|