admin 10e6c69af8 fix(pwa): prepare beforeinstallprompt listener early to avoid event loss
The previous install flow had a timing race: the
`beforeinstallprompt` event fires at unpredictable times after
page load (often ~30s+ into the session, when Chrome's heuristic
finally decides the user is engaged). If the listener was
attached only inside the dialog's onClick handler, by the time
the user clicked OK the event had already fired into the void
and the deferred prompt was null — so `install()` returned
"unavailable" every time.

The new flow attaches the listener as early as possible:

1. `pwaUtil.prepareInstallPrompt()` — new public method that
   calls the private `attachListener()`. Idempotent (guard via
   `listenersAttached`).

2. `pwaUtil.canPromptInstall()` — companion getter that returns
   whether a deferred event is currently cached. Useful for UI
   to decide whether to even show the install CTA.

3. `pwa-install-overlay.tsx` — calls `prepareInstallPrompt()`
   right after the isSupported / isInstalled guards. The overlay
   mounts when the user enters /chat, so this is the earliest
   practical point in the user flow.

4. `pwa-screen.tsx` — calls `prepareInstallPrompt()` BOTH at
   module load (synchronous, so the listener is attached before
   the splash screen's useEffects run) AND in a useEffect for
   robustness. The splash screen is the very first screen the
   user sees, so attaching here is the earliest possible.

5. `pwa-install-dialog.tsx` — `handleInstall` is now async,
   and `onInstall` accepts `() => void | Promise<void>`. The
   overlay calls `await pwaUtil.install()` so the deferred
   prompt flow can complete before the dialog unmounts.

Together: the listener is now attached from the moment the
splash screen module loads, the deferred prompt is captured
whenever Chrome decides to fire the event, and the dialog's
install button can reliably `prompt()` against the cached
deferred. The full install flow now works end-to-end.
2026-06-17 12:00:24 +08:00
2026-06-05 19:09:20 +08:00
2026-06-05 19:09:20 +08:00
2026-06-15 11:37:29 +08:00
2026-06-15 14:23:31 +08:00

This is a Next.js project bootstrapped with create-next-app.

Getting Started

First, run the development server:

npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev

Open http://localhost:3000 with your browser to see the result.

You can start editing the page by modifying app/page.tsx. The page auto-updates as you edit the file.

This project uses next/font to automatically optimize and load Geist, a new font family for Vercel.

Git Hooks

项目使用 .githooks/ 目录存放仓库内的 git hooks.git/hooks/)。clone 后需手动启用

git config core.hooksPath .githooks

启用的 Hook

post-receive

触发场景git push 到本仓库时(在 bare reporeceive.denyCurrentBranch=updateInstead 的非 bare repo 上)。

行为:自动执行 pnpm run build:start,即 next build && next start

注意事项

  • 本仓库的 .githooks/post-receive 自动生效 —— 必须在每个工作副本上跑一次上面的 git config 命令
  • core.hooksPath本地 git config(写入 .git/config),随仓库提交
  • post-receive接收端触发 —— 即 push 目标机器(生产 / 测试服务器)的 hook,不是本地开发机的

Learn More

To learn more about Next.js, take a look at the following resources:

You can check out the Next.js GitHub repository - your feedback and contributions are welcome!

Deploy on Vercel

The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.

Check out our Next.js deployment documentation for more details. modify

S
Description
No description provided
Readme 47 MiB
Languages
TypeScript 90.2%
CSS 6.3%
JavaScript 1.6%
Shell 1.3%
HTML 0.4%
Other 0.1%