feat(chat): port chat widget components from Dart to React
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
"use client";
|
||||
/**
|
||||
* PwaInstallOverlay PWA 安装提示触发器
|
||||
*
|
||||
* 原始 Dart: lib/ui/chat/widgets/pwa_install_overlay.dart(76 行)
|
||||
*
|
||||
* 行为:
|
||||
* - 检查 PWA 支持
|
||||
* - 检查每日是否已显示(使用 AppStorage 持久化)
|
||||
* - 延迟 3.5s 后弹出 PwaInstallDialog
|
||||
* - 生产环境有效;开发环境 1s 后立即弹出(测试用)
|
||||
*
|
||||
* 注意:PWA install prompt API(`beforeinstallprompt`)在浏览器差异较大,
|
||||
* 本轮仅实现"显示时机"逻辑,具体 install prompt 调用由 Dialog 内部处理。
|
||||
*/
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { SpAsyncUtil } from "@/utils/storage";
|
||||
|
||||
import { PwaInstallDialog } from "./pwa-install-dialog";
|
||||
import styles from "./pwa-install-overlay.module.css";
|
||||
|
||||
const PWA_DIALOG_KEY = "cozsweet:lastPwaDialogShown";
|
||||
|
||||
export function PwaInstallOverlay() {
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
|
||||
const init = async () => {
|
||||
// 检查每日是否已显示
|
||||
const lastResult = await SpAsyncUtil.getString(PWA_DIALOG_KEY);
|
||||
if (!lastResult.success) return;
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
if (lastResult.data === today) return; // 今天已显示过
|
||||
|
||||
// 检查 PWA 支持
|
||||
if (typeof window === "undefined") return;
|
||||
if (!("serviceWorker" in navigator)) return;
|
||||
|
||||
// 延迟 3.5s 后显示
|
||||
setTimeout(() => {
|
||||
if (!mounted) return;
|
||||
showPwaDialog();
|
||||
}, 3500);
|
||||
};
|
||||
|
||||
void init();
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return <div className={styles.hidden} aria-hidden="true" />;
|
||||
}
|
||||
|
||||
function showPwaDialog() {
|
||||
if (typeof document === "undefined") return;
|
||||
// 记录显示时间
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
void SpAsyncUtil.setString(PWA_DIALOG_KEY, today);
|
||||
|
||||
// 创建挂载点
|
||||
const root = document.createElement("div");
|
||||
document.body.appendChild(root);
|
||||
// 用 React DOM 渲染(通过 import)
|
||||
import("react-dom/client").then(({ createRoot }) => {
|
||||
const reactRoot = createRoot(root);
|
||||
reactRoot.render(<PwaInstallDialogMount rootEl={root} reactRoot={reactRoot} />);
|
||||
});
|
||||
}
|
||||
|
||||
function PwaInstallDialogMount({
|
||||
rootEl,
|
||||
reactRoot,
|
||||
}: {
|
||||
rootEl: HTMLElement;
|
||||
reactRoot: { unmount: () => void };
|
||||
}) {
|
||||
return (
|
||||
<PwaInstallDialog
|
||||
onClose={() => {
|
||||
reactRoot.unmount();
|
||||
rootEl.remove();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user