Skip to content

feat: offline merchant dashboard — service worker, background sync & PWA install - #662

Open
micmusjnr20 wants to merge 1 commit into
Betta-Pay:mainfrom
micmusjnr20:feat/offline-merchant-dashboard-v2
Open

feat: offline merchant dashboard — service worker, background sync & PWA install#662
micmusjnr20 wants to merge 1 commit into
Betta-Pay:mainfrom
micmusjnr20:feat/offline-merchant-dashboard-v2

Conversation

@micmusjnr20

Copy link
Copy Markdown

概述

为商家仪表盘补齐离线能力:Workbox service worker 预缓存应用外壳 + GET API 列表端点 stale-while-revalidate;离线横幅反映 API 可达性(而非仅 navigator.onLine);支付链接创建与 webhook 测试提交支持 background sync;附带 manifest、图标与安装提示。

说明:本 PR 替代 #661(相同提交,原分支/PR 因权限原因无法关闭,请忽略 #661)。

变更内容

1. Service worker(Workbox)— scripts/sw-template.js + scripts/build-sw.mjs

  • next build 之后运行 build-sw.mjs:bake API origin → rollup 打包 workbox runtime → injectManifest 注入预缓存清单,产出 public/sw.js(451 个资源,约 15.7 MiB)。
  • 预缓存应用外壳(.next/static 哈希资源 + manifest/icons/logo 等稳定 URL)。
  • 导航请求 network-first,失败时回退到同 URL 缓存 → 首页外壳(客户端路由接管),任意路由离线可重载。
  • GET API 响应 stale-while-revalidate(7 天 / 100 条上限);healthz 永远直连网络,保证横幅反映真实 API 可达性。
  • POST /api/payment-links 走 NetworkOnly + BackgroundSyncPlugin,作为客户端队列之外的网络失败兜底。
  • SYNC_NOW / CLEAR_API_CACHE 消息:登出时清空 API 缓存,防止跨账号脏数据;drain 串行化避免重复回放。

2. 离线横幅(API 可达性感知)— components/ui/offline-banner.tsx

  • 复用 offlineStore + useOnlineStatus:10s 可见轮询 healthz(4s 超时),叠加 online/offline/visibilitychange 事件。
  • axios 拦截器在无响应网络错误时同步翻转 isApiReachable,两种状态不会长期矛盾。
  • 显示待同步条数(IndexedDB 队列),提供重试/关闭;状态转换时自动重置关闭状态。

3. Background sync 队列 — lib/offline/syncQueue.ts

  • 客户端与 service worker 共享同一 IndexedDB store(bettapay-offline / sync-queue)。
  • 支付链接创建(app/(merchant)/payments/page.tsx)与 webhook 测试提交(components/developers/WebhookTester.tsx)在离线/不可达时入队,返回队列 id 供 UI 关联。
  • SW 侧 drain:2xx/4xx 落库成功即删;5xx/401/429/网络错误重试(上限 5 次);native sync + SYNC_NOW + SW online 三路触发;回放成功后清除相关列表的 SWR 缓存让新链接立即可见;SYNC_COMPLETE 广播回页面刷新数据。
  • 页面侧:payments 页显示"N 条离线链接等待同步"徽标;WebhookTester 将 pending 条目在回放后翻转为成功/失败。

4. PWA manifest / 图标 / 安装提示

  • public/manifest.webmanifest(standalone、maskable 图标、主题色)。
  • scripts/generate-icons.mjs 纯 Node 生成 4 个图标(无图像依赖)。
  • components/layout/InstallPrompt.tsx 捕获 beforeinstallprompt 挂载于商家布局;components/ui/service-worker-registration.tsx 仅生产环境注册 SW(workbox-window,动态导入)。
  • middleware.ts 豁免 sw.js / manifest.webmanifest / icons / logo.png,避免鉴权重定向破坏 SW 安装。

验收标准达成

验收标准 证据
首次加载后离线渲染 + 缓存数据 + 横幅 npm run verify:offline(Playwright,13 项检查全过):离线重载后外壳/列表来自 SW 缓存,横幅出现
离线创建的支付链接恢复网络后同步 同脚本:离线入队 → 重连后 SW 回放 POST → 列表出现新链接,徽标清零
API 可达性与浏览器在线状态不长期矛盾 healthz 永不缓存 + axios 网络错误翻转 isApiReachable + 10s 轮询收敛
npm run build 通过 next build + build-sw.mjs 全过(451 资源预缓存)

测试

  • npm run build ✅(next build + build-sw.mjs,451 资源 / 15.68 MiB)
  • npm run verify:offline ✅ 13/13(离线渲染、缓存命中、横幅、离线建链、重连回放、徽标清零)
  • npx jest lib/offline ✅ 4/4(无 IndexedDB/SW 环境的优雅降级契约)
  • npx tsc --noEmit:offline 相关代码零错误(仓库内 lib/docslib/i18nlib/status 存在先期无关报错,与本 PR 无关)

备注

…WA install

Adds a Workbox service worker that precaches the app shell and serves GET
API list endpoints stale-while-revalidate, an API-reachability-aware offline
banner, background sync for payment links and webhook tests created while
offline, and a web manifest with icons plus an install prompt for the
merchant dashboard.

Verified end-to-end with `npm run verify:offline` (13/13 checks: the shell
renders offline with cached data and the banner; an offline-created payment
link is replayed on reconnect and appears in the list). `npm run build`
passes; jest shows only pre-existing failures.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
@vercel

vercel Bot commented Aug 29, 2026

Copy link
Copy Markdown

@micmusjnr20 is attempting to deploy a commit to the therealjhay's projects Team on Vercel.

A member of the Team first needs to authorize it.

@therealjhay

Copy link
Copy Markdown
Contributor

kindly resolve conflict

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants