+
+
+ {message.senderName}
+
+
+ {new Date(
+ Number(
+ message.sentAt.microsSinceUnixEpoch / 1000n
+ )
+ ).toLocaleTimeString()}
+
+ {message.editedAt && (
+ (edited)
+ )}
+ {message.isEphemeral && (
+
+ (disappears in{' '}
+ {Math.max(
+ 0,
+ Math.ceil(
+ (Number(
+ message.ephemeralExpiresAt
+ ?.microsSinceUnixEpoch || 0n
+ ) -
+ Date.now() * 1000) /
+ 1000000
+ )
+ )}
+ s)
+
+ )}
+
+
+ {editingMessageId === message.id ? (
+
+ setEditInput(e.target.value)}
+ onKeyDown={e => {
+ if (e.key === 'Enter') handleEditMessage();
+ if (e.key === 'Escape') cancelEditing();
+ }}
+ style={{ width: '100%', marginBottom: '4px' }}
+ />
+
+
+
+ ) : (
+ message.content
+ )}
+
+
+ {/* Reactions */}
+ {Object.keys(reactions).length > 0 && (
+
+ {Object.entries(reactions).map(([emoji, data]) => (
+
+ handleToggleReaction(message.id, emoji)
+ }
+ >
+ {emoji} {data.count}
+
+ ))}
+
+ )}
+
+ {/* Edit history */}
+ {editHistory.length > 0 &&
+ showEditHistory === message.id && (
+
+ {editHistory.map(edit => (
+
+ {getUserName(edit.editedBy)}{' '}
+ edited at{' '}
+ {new Date(
+ Number(
+ edit.editedAt.microsSinceUnixEpoch / 1000n
+ )
+ ).toLocaleTimeString()}
+
+
+ {edit.previousContent}
+
+ {' → '}
+
+ {edit.newContent}
+
+
+ ))}
+
+ )}
+
+ {/* Message actions */}
+ {isOwnMessage && editingMessageId !== message.id && (
+
+
+ {editHistory.length > 0 && (
+
+ )}
+
+ )}
+
+ {/* Add reaction */}
+
+ {['👍', '❤️', '😂', '😮', '😢'].map(emoji => (
+
+ ))}
+
+
+ {/* Read receipts */}
+ {readReceipts.length > 0 && (
+
+ Seen by{' '}
+ {readReceipts
+ .map(r => getUserName(r.userId))
+ .join(', ')}
+
+ )}
+