feat: render history_loaded in web UI with earlier messages divider

- store: handle history_loaded event — prepend gossipped messages,
  dedup by mid, sort by ts, record cutoff timestamp per room
- MessagePane: show "earlier messages" divider between history and
  live messages based on the cutoff timestamp
- types: add history_loaded, room_created, create_room to IpcMsgType;
  add messages field to IpcMessage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Fredrik Johansson
2026-06-28 23:50:48 +02:00
parent 15306dc0c2
commit 9de625d617
4 changed files with 42 additions and 5 deletions

View File

@@ -2,10 +2,11 @@ import { useEffect, useRef, useState } from 'react'
import { useWaste } from '../store'
export function MessagePane() {
const { messages, activeRoom, activeNetworkId, localPeer, connectedPeers, send } = useWaste()
const { messages, historyCutoff, activeRoom, activeNetworkId, localPeer, connectedPeers, send } = useWaste()
const [draft, setDraft] = useState('')
const bottomRef = useRef<HTMLDivElement>(null)
const roomMessages = messages[activeRoom] ?? []
const cutoff = historyCutoff[activeRoom] ?? 0
useEffect(() => {
bottomRef.current?.scrollIntoView({ behavior: 'smooth' })
@@ -46,11 +47,19 @@ export function MessagePane() {
const mine = msg.from === localPeer?.id
const alias = aliasFor(msg.from)
const time = new Date(msg.ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false })
const showDivider = cutoff > 0 && i > 0 && roomMessages[i - 1].ts <= cutoff && msg.ts > cutoff
return (
<div key={msg.mid ?? i} className={`message ${mine ? 'mine' : ''}`}>
<span className="message-ts">{time}</span>
<span className="message-alias">{alias}</span>
<span className="message-text">{msg.text}</span>
<div key={msg.mid ?? i}>
{showDivider && (
<div className="history-divider">
<span>earlier messages</span>
</div>
)}
<div className={`message ${mine ? 'mine' : ''}`}>
<span className="message-ts">{time}</span>
<span className="message-alias">{alias}</span>
<span className="message-text">{msg.text}</span>
</div>
</div>
)
})}