feat(chat): trigger pwa prompt after message threshold

This commit is contained in:
2026-07-03 17:50:35 +08:00
parent 36636ad77b
commit 7e559ac098
2 changed files with 21 additions and 7 deletions
+3 -2
View File
@@ -67,6 +67,7 @@ export function ChatScreen() {
historyLoaded: state.historyLoaded, historyLoaded: state.historyLoaded,
loginStatus: authState.loginStatus, loginStatus: authState.loginStatus,
}); });
const shouldShowPwaInstall = state.historyLoaded && state.messages.length >= 10;
const externalBrowserPromptShownRef = useRef(false); const externalBrowserPromptShownRef = useRef(false);
@@ -181,8 +182,8 @@ export function ChatScreen() {
{/* 浏览器提示(应用内浏览器检测) */} {/* 浏览器提示(应用内浏览器检测) */}
<BrowserHintOverlay forceShow={isChatDevelopmentEnvironment()} /> <BrowserHintOverlay forceShow={isChatDevelopmentEnvironment()} />
{/* PWA 安装提示触发器(无可见 UI3.5s 后弹 dialog */} {/* PWA 安装提示触发器(聊天消息数量达到阈值后才允许弹出 */}
<PwaInstallOverlay /> <PwaInstallOverlay enabled={shouldShowPwaInstall} />
<ExternalBrowserDialog <ExternalBrowserDialog
open={showExternalBrowserDialog} open={showExternalBrowserDialog}
@@ -3,6 +3,7 @@
* PwaInstallOverlay PWA 安装提示触发器 * PwaInstallOverlay PWA 安装提示触发器
* *
* 行为: * 行为:
* - 等聊天消息数量达到触发阈值后才开始检查
* - 检查 PWA 支持(pwaUtil.isSupported * - 检查 PWA 支持(pwaUtil.isSupported
* - 检查 PWA 是否已安装(pwaUtil.isInstalled)—— 已安装则不弹 * - 检查 PWA 是否已安装(pwaUtil.isInstalled)—— 已安装则不弹
* - 检查每日是否已显示(使用 AppStorage 持久化) * - 检查每日是否已显示(使用 AppStorage 持久化)
@@ -20,10 +21,19 @@ import { PwaInstallDialog } from "./pwa-install-dialog";
import styles from "./pwa-install-overlay.module.css"; import styles from "./pwa-install-overlay.module.css";
const PWA_DIALOG_KEY = "cozsweet:lastPwaDialogShown"; const PWA_DIALOG_KEY = "cozsweet:lastPwaDialogShown";
const DEVELOPMENT_DIALOG_DELAY_MS = 1000;
const PRODUCTION_DIALOG_DELAY_MS = 1500;
export function PwaInstallOverlay() { export interface PwaInstallOverlayProps {
enabled: boolean;
}
export function PwaInstallOverlay({ enabled }: PwaInstallOverlayProps) {
useEffect(() => { useEffect(() => {
if (!enabled) return;
let mounted = true; let mounted = true;
let timer: number | undefined;
const init = async () => { const init = async () => {
// const isDev = AppEnvUtil.isDevelopment(); // const isDev = AppEnvUtil.isDevelopment();
@@ -34,9 +44,11 @@ export function PwaInstallOverlay() {
// 提前挂 beforeinstallprompt 监听,避免用户点 OK 时事件已在更早时机丢失。 // 提前挂 beforeinstallprompt 监听,避免用户点 OK 时事件已在更早时机丢失。
pwaUtil.prepareInstallPrompt(); pwaUtil.prepareInstallPrompt();
// 开发环境 1s 后弹(快);生产环境 3.5s 后弹(让用户先看到聊天内容) // 达到聊天数量阈值后稍作停顿,避免弹窗与消息刷新挤在同一瞬间。
const delay = isDev ? 1000 : 3500; const delay = isDev
setTimeout(() => { ? DEVELOPMENT_DIALOG_DELAY_MS
: PRODUCTION_DIALOG_DELAY_MS;
timer = window.setTimeout(() => {
if (!mounted) return; if (!mounted) return;
showPwaDialog(); showPwaDialog();
}, delay); }, delay);
@@ -45,8 +57,9 @@ export function PwaInstallOverlay() {
void init(); void init();
return () => { return () => {
mounted = false; mounted = false;
if (timer !== undefined) window.clearTimeout(timer);
}; };
}, []); }, [enabled]);
return <div className={styles.hidden} aria-hidden="true" />; return <div className={styles.hidden} aria-hidden="true" />;
} }