fix(ux): surface hidden notices, bound report waits, add root boundaries
Framework-level UX fixes found while auditing staging (BUG-216..220).
- chat: route 44 previously discarded composer notices to sonner with
dedupe, so recovery, cancel and archive feedback is actually visible
(BUG-216)
- chat: anchor stream auto-scroll to bottom proximity and add a
jump-to-latest control, so reading history is no longer interrupted
on every token (BUG-218)
- reports: replace the silent 120s poll cutoff with an explicit
timed-out state, an 8m budget, stepped backoff and an elapsed
counter (BUG-217)
- reports: pause polling while the tab is hidden, via a shared hook
- app: add root error, global-error and not-found boundaries (BUG-219)
- admin: add antd SSR style extraction and the React 19 render adapter,
and move admin-only css out of the global stylesheet (BUG-220)
- membership: run bootstrap fetches concurrently and pause payment
polling while hidden
- build: configure optimizePackageImports
Verified on top of 2d370f2e: tsc, eslint, next build, and the related
frontend contract suites.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import { toast } from "sonner";
|
||||
|
||||
export const chatNoticeToastId = "chat-notice";
|
||||
|
||||
export type NoticeTone = "info" | "success" | "error";
|
||||
|
||||
const ongoingNotice = /正在|请稍候|请先|联网后/;
|
||||
const failedNotice = /失败|无法|不可用|未找到/;
|
||||
const settledNotice = /^已|^回答已恢复/;
|
||||
|
||||
export function noticeTone(message: string): NoticeTone {
|
||||
if (ongoingNotice.test(message)) return "info";
|
||||
if (failedNotice.test(message)) return "error";
|
||||
if (settledNotice.test(message)) return "success";
|
||||
return "info";
|
||||
}
|
||||
|
||||
let lastNotice = "";
|
||||
|
||||
export function showChatNotice(message: string) {
|
||||
if (!message.trim()) {
|
||||
if (!lastNotice) return;
|
||||
lastNotice = "";
|
||||
toast.dismiss(chatNoticeToastId);
|
||||
return;
|
||||
}
|
||||
if (lastNotice === message) return;
|
||||
lastNotice = message;
|
||||
const tone = noticeTone(message);
|
||||
if (tone === "success") {
|
||||
toast.success(message, { id: chatNoticeToastId });
|
||||
return;
|
||||
}
|
||||
if (tone === "error") {
|
||||
toast.error(message, { id: chatNoticeToastId });
|
||||
return;
|
||||
}
|
||||
toast(message, { id: chatNoticeToastId });
|
||||
}
|
||||
Reference in New Issue
Block a user