"use client"; /** * PwaInstallOverlay PWA 安装提示触发器 * * 行为: * - 调用方达到消息阈值后启用检查 * - 仅在浏览器可安装、尚未安装且未展示过时继续 * - 延迟 1.5 秒显示 PwaInstallDialog * - 用户确认后调用浏览器安装提示 */ import { useEffect } from "react"; import { canShowPwaInstallPromptOnce, recordPwaInstallPromptShown, } from "@/lib/chat/pwa_install_prompt"; import { pwaUtil } from "@/utils/pwa"; import { PwaInstallDialog } from "./pwa-install-dialog"; const DIALOG_DELAY_MS = 1500; export interface PwaInstallOverlayProps { enabled: boolean; } export function PwaInstallOverlay({ enabled }: PwaInstallOverlayProps) { useEffect(() => { if (!enabled) return; let mounted = true; let timer: number | undefined; let unsubscribe: (() => void) | undefined; const init = async () => { // 提前挂 beforeinstallprompt 监听,避免用户点 OK 时事件已在更早时机丢失。 pwaUtil.prepareInstallPrompt(); const tryScheduleDialog = async () => { const shouldShowDialog = await shouldShowPwaInstallDialog(); if (!mounted || !shouldShowDialog || timer !== undefined) return; // 达到聊天数量阈值后稍作停顿,避免弹窗与消息刷新挤在同一瞬间。 timer = window.setTimeout(() => { if (!mounted) return; showPwaDialog(); }, DIALOG_DELAY_MS); }; await tryScheduleDialog(); unsubscribe = pwaUtil.subscribe(() => { void tryScheduleDialog(); }); }; void init(); return () => { mounted = false; unsubscribe?.(); if (timer !== undefined) window.clearTimeout(timer); }; }, [enabled]); return null; } async function shouldShowPwaInstallDialog() { if (!pwaUtil.canShowInstallEntry()) return false; return canShowPwaInstallPromptOnce(); } function showPwaDialog() { if (typeof document === "undefined") return; // Persist before rendering so remounts cannot schedule a second dialog. void recordPwaInstallPromptShown(); const root = document.createElement("div"); document.body.appendChild(root); import("react-dom/client").then(({ createRoot }) => { const reactRoot = createRoot(root); reactRoot.render(); }); } function PwaInstallDialogMount({ rootEl, reactRoot, }: { rootEl: HTMLElement; reactRoot: { unmount: () => void }; }) { return ( { reactRoot.unmount(); rootEl.remove(); }} onInstall={async () => { // The utility owns deferred-prompt lookup and browser prompting. await pwaUtil.install(); }} /> ); }