feat(web): offline/reconnect/realname top banners (README §3.7)
Four states, one shown at a time (offline > reconnecting > just-reconnected > realname-reminder priority): no-network (navigator.onLine + online/offline listeners), reconnecting-with-countdown, just-reconnected, and a skippable realname-verification reminder (bootstrap.security.realname). - connection.ts: claims Tinode's onAutoreconnectIteration(timeoutMs, promise?) callback (single-slot, same pattern as onConnect/onDisconnect) and runs its own 1s-tick countdown off the first call's timeout -- the SDK gives the backoff length once per iteration, it doesn't push a running countdown. Verified the callback's exact three-shape contract (timeoutMs alone starts a countdown; 0+promise means a retry is now in flight; -1 means retrying stopped) by reading the SDK's own Connection class, not guessed. retryReconnectNow() backs "立即重试": clears the countdown and calls tinode.reconnect(true). - "已重新连接,正在同步 N 条新消息" intentionally shown without a fake N -- confirmed via research that the old app never implemented this state at all, and there's no reliable signal here for how many messages arrived while disconnected; inventing a count would be dishonest data. Verified live: toggling browser online/offline events correctly shows and clears the no-network banner. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
80bf0aa41f
commit
bccbdff9b2
@@ -4,6 +4,7 @@ import { Outlet, useParams } from 'react-router-dom';
|
||||
|
||||
import { ChatListColumn } from '@/features/messages/ChatListColumn';
|
||||
import { DetailColumn } from '@/features/messages/DetailColumn';
|
||||
import { OfflineBanner } from '@/features/messages/OfflineBanner';
|
||||
import { useChatList } from '@/lib/tinode/hooks';
|
||||
|
||||
/**
|
||||
@@ -23,11 +24,16 @@ export function MessagesLayout() {
|
||||
|
||||
return (
|
||||
<div className="relative flex h-full w-full">
|
||||
<div className={`h-full w-full md:w-auto md:shrink-0 ${showListOnNarrow ? '' : 'hidden md:flex'}`}>
|
||||
<ChatListColumn />
|
||||
</div>
|
||||
<div className={`h-full min-w-0 flex-1 ${showListOnNarrow ? 'hidden md:block' : ''}`}>
|
||||
<Outlet context={{ onToggleDetail: () => setDetailOpen((v) => !v) }} />
|
||||
<div className="relative flex h-full min-w-0 flex-1">
|
||||
<div className="absolute inset-x-0 top-0 z-10">
|
||||
<OfflineBanner />
|
||||
</div>
|
||||
<div className={`h-full w-full md:w-auto md:shrink-0 ${showListOnNarrow ? '' : 'hidden md:flex'}`}>
|
||||
<ChatListColumn />
|
||||
</div>
|
||||
<div className={`h-full min-w-0 flex-1 ${showListOnNarrow ? 'hidden md:block' : ''}`}>
|
||||
<Outlet context={{ onToggleDetail: () => setDetailOpen((v) => !v) }} />
|
||||
</div>
|
||||
</div>
|
||||
{topicId ? (
|
||||
<div className="hidden h-full lg:block">
|
||||
|
||||
Reference in New Issue
Block a user