Skip to content

Chat conversation state is lost on mobile every time the chat sheet is closed, contradicting the component's own documented intent #7792

Description

@JSONbored

Context

ChatRail's own header comment (apps/loopover-miner-ui/src/components/chat-rail.tsx:1-5) and in-code comment at line 68 state the design intent explicitly: "Collapsing only hides it (never unmounts it), so any future in-rail state is preserved across an expand/collapse cycle." On desktop (lines 76-85) this is true — the <aside hidden={!open}> wrapper keeps RailBody/ChatConversation mounted, just visually hidden.

On mobile (lines 36-56), the same RailBody is instead rendered inside @loopover/ui-kit's Sheet/SheetContent (packages/loopover-ui-kit/src/components/sheet.tsx:10,52+), which wraps Radix's Dialog.Root/Dialog.Content. Radix's Dialog.Content uses Presence internally and unmounts its subtree when open becomes false unless forceMount is passed — which it isn't anywhere in this codebase (confirmed via repo-wide grep for forceMount across apps/loopover-miner-ui, apps/loopover-ui, packages/loopover-ui-kit: zero hits).

So on a mobile viewport, closing the chat sheet (accidental tap-outside, Escape, explicit toggle) discards ChatConversation's entire messages/activeSource/streaming state (apps/loopover-miner-ui/src/components/chat/conversation.tsx:70-73) — the whole conversation and any in-progress typed draft (ChatComposer's own value state) is silently lost and reinitializes empty on reopen. Desktop and mobile behave inconsistently despite the code explicitly claiming otherwise.

Untested branch: apps/loopover-miner-ui/src/chat-rail.test.tsx covers docked-vs-sheet rendering, the toggle, and open-state persistence across route navigation, but nothing asserts that conversation content survives a mobile sheet close/reopen cycle — precisely the gap that would have caught this.

Requirements

Make mobile behavior match the documented intent (state survives close/reopen), the same way desktop already does. The most direct fix is passing forceMount to the relevant Radix Dialog.Content (via SheetContent's existing prop passthrough, if it has one — check before adding a new prop) combined with the existing hidden/visibility toggle pattern desktop already uses, so the sheet's content stays mounted but visually hidden when closed, matching the desktop <aside hidden={!open}> approach.

Deliverables

  • Closing and reopening the mobile chat sheet preserves ChatConversation's messages/activeSource/streaming state and any in-progress composer draft, matching desktop behavior.
  • A regression test in chat-rail.test.tsx asserting conversation content survives a mobile sheet close/reopen cycle.

Test Coverage Requirements

apps/loopover-miner-ui is not covered by the src/** 99% patch gate - the new regression test is this issue's own coverage deliverable.

Expected Outcome

A mobile user's in-progress chat conversation and draft message survive closing and reopening the chat sheet, matching the component's own documented intent and desktop's actual behavior.

Links & Resources

apps/loopover-miner-ui/src/components/chat-rail.tsx:1-5,36-56,68,76-85, packages/loopover-ui-kit/src/components/sheet.tsx:10,52+, apps/loopover-miner-ui/src/components/chat/conversation.tsx:70-73

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions