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, }, }, }; }