fix(ux): surface hidden notices, bound report waits, add root boundaries
Independent Staging Quality Gate / validate (push) Successful in 12m8s
Independent Staging Quality Gate / publish (push) Successful in 14m29s

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:
Jesse_Chen
2026-08-17 12:52:24 +08:00
parent 2d370f2e9d
commit 9c296f1e3f
23 changed files with 1144 additions and 88 deletions
+35
View File
@@ -0,0 +1,35 @@
.admin-app-shell {
min-height: 100dvh;
background: #f3f2ee;
color: #1d1d1f;
font-family: var(--font-body);
}
.admin-app-shell .ant-layout { background: #f3f2ee; }
.admin-app-shell .ant-layout-sider { border-right: 1px solid #d8d6cf; box-shadow: none !important; }
.admin-app-shell .ant-layout-header { border-bottom: 1px solid #d8d6cf; box-shadow: none !important; }
.admin-app-shell .ant-layout-content { padding: 22px; }
.admin-app-shell .ant-menu { border-inline-end: 0 !important; background: transparent !important; }
.admin-app-shell .ant-menu-item, .admin-app-shell .ant-menu-submenu-title { margin-inline: 8px; width: calc(100% - 16px); }
.admin-app-shell .ant-card { border-color: #d8d6cf; box-shadow: none !important; }
.admin-app-shell .ant-card-head { border-bottom-color: #d8d6cf; }
.admin-app-shell .ant-card .ant-card { border-radius: 0; }
.admin-app-shell .ant-card .ant-card:not(:last-child) { border-bottom: 0; }
.admin-app-shell .ant-list-bordered { border-color: #d8d6cf; border-radius: 6px; }
.admin-app-shell .ant-table-wrapper .ant-table { background: #fbfaf7; }
.admin-app-shell .ant-table-wrapper .ant-table-container { border-radius: 6px; }
.admin-app-shell .ant-table-wrapper .ant-table-thead > tr > th { font-size: 12px; font-weight: 650; }
.admin-app-shell .ant-table-wrapper .ant-table-cell { line-height: 1.45; }
.admin-app-shell .ant-tag { margin-inline-end: 4px; border-radius: 4px; font-weight: 550; }
.admin-app-shell .ant-alert { border-radius: 6px; box-shadow: none; }
.admin-app-shell .ant-statistic-title { color: #5f5f59; font-size: 12px; }
.admin-app-shell .ant-statistic-content { font-size: 22px; font-weight: 650; }
.admin-app-shell .ant-typography h1, .admin-app-shell h1.ant-typography { font-family: var(--font-body); font-size: 26px; font-weight: 680; letter-spacing: -.025em; }
.admin-app-shell .ant-typography h2, .admin-app-shell h2.ant-typography { font-family: var(--font-body); font-size: 21px; font-weight: 650; letter-spacing: -.015em; }
.admin-app-shell .ant-typography h3, .admin-app-shell h3.ant-typography { font-family: var(--font-body); font-size: 17px; font-weight: 650; }
.admin-app-shell code { font-family: var(--font-mono); }
.admin-text-list { max-width: 680px; color: #5f5f59; line-height: 1.65; white-space: normal; overflow-wrap: anywhere; }
.admin-loading { min-height: 100dvh; display: grid; place-content: center; justify-items: center; gap: 12px; background: #f3f2ee; color: #5f5f59; }
@media (max-width: 767px) {
.admin-app-shell .ant-layout-content { padding: 14px; }
}
+7 -2
View File
@@ -1,8 +1,9 @@
import "@refinedev/antd/dist/reset.css";
import "antd/dist/reset.css";
import "./admin.css";
import type { ReactNode } from "react";
import { forbidden, redirect } from "next/navigation";
import { AdminAntdRegistry } from "@/components/admin/admin-antd-registry";
import { AdminApp } from "@/components/admin/admin-app";
import { AdminAuthorizationError, requireAdminSession } from "@/lib/admin/auth";
import { resolveAdminPageAccessFailure } from "@/lib/admin/page-access";
@@ -21,5 +22,9 @@ export default async function AdminLayout({ children }: { children: ReactNode })
}
throw error;
}
return <AdminApp>{children}</AdminApp>;
return (
<AdminAntdRegistry>
<AdminApp>{children}</AdminApp>
</AdminAntdRegistry>
);
}