/** * One-line rendering for the non-`Default` message kinds the backend writes into * a room (`ChatMessageType`). These are events, not posts, so they render as a * compact grey line instead of a message row — and a webhook/bot post carries * real content, which must not be swallowed by the system styling. */ import type { ChatMessage } from '@app/domains/chat/model' import { t } from '@app/i18n' export function systemLine(message: ChatMessage, nameOf: (userId: number | null | undefined) => string): string { const who = nameOf(message.author_id) if (message.author_type !== 'User') { // Bots and webhooks post normal text; the label keeps it attributable. const label = message.author?.display_name || message.author?.username || t('chat.system.integration') return message.content ? t('chat.system.postWithContent', { author: label, content: message.content }) : t('chat.system.post', { author: label }) } switch (message.message_type) { case 'ThreadCreated': return t('chat.system.threadCreated', { author: who }) case 'ChannelJoin': return t('chat.system.joined', { author: who }) case 'ChannelLeave': return t('chat.system.left', { author: who }) case 'ChannelTopic': return message.content ? t('chat.system.topicChanged', { author: who, topic: message.content }) : t('chat.system.topicUpdated', { author: who }) case 'ChannelPinnedItem': return t('chat.system.pinned', { author: who }) case 'Reminder': return message.content ? t('chat.system.reminder', { author: who, content: message.content }) : t('chat.system.reminderSet', { author: who }) case 'System': return message.content || t('chat.system.message') default: return message.content || t('chat.system.sent', { author: who }) } }