Files
buzz-sheet/components/site-install-button.tsx
T

77 lines
3.6 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { DownloadIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
type InstallEvent = Event & {
prompt: () => Promise<void>;
userChoice: Promise<{ outcome: string }>;
};
export function SiteInstallButton() {
const [open, setOpen] = useState(false);
const [installed, setInstalled] = useState(false);
const [installEvent, setInstallEvent] = useState<InstallEvent | null>(null);
const [busy, setBusy] = useState(false);
const [error, setError] = useState("");
useEffect(() => {
const displayMode = window.matchMedia("(display-mode: standalone)");
const frame = requestAnimationFrame(() => setInstalled(displayMode.matches ||
(navigator as Navigator & { standalone?: boolean }).standalone === true));
const beforeInstall = (event: Event) => {
event.preventDefault();
setInstallEvent(event as InstallEvent);
};
const onInstalled = () => { setInstalled(true); setOpen(false); setInstallEvent(null); };
window.addEventListener("beforeinstallprompt", beforeInstall);
window.addEventListener("appinstalled", onInstalled);
return () => {
cancelAnimationFrame(frame);
window.removeEventListener("beforeinstallprompt", beforeInstall);
window.removeEventListener("appinstalled", onInstalled);
};
}, []);
async function install() {
if (!installEvent || busy) return;
setBusy(true);
setError("");
try {
await installEvent.prompt();
const result = await installEvent.userChoice;
setInstallEvent(null);
if (result.outcome === "accepted") setOpen(false);
} catch { setError("ติดตั้งไม่สำเร็จ กรุณาลองจากเมนูของเบราว์เซอร์"); }
finally { setBusy(false); }
}
if (installed) return null;
return <>
<Button variant="ghost" size="sm" onClick={() => setOpen(true)} aria-label="ติดตั้ง Buzz Guide">
<DownloadIcon data-icon="inline-start" />ติดตั้งแอป
</Button>
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>ติดตั้ง Buzz Guide</DialogTitle>
<DialogDescription>เพิ่มไกด์ลงหน้าจอหลักเพื่อเปิดอ่านได้สะดวก</DialogDescription>
</DialogHeader>
{!installEvent && <div className="flex flex-col gap-3 text-sm text-muted-foreground">
<p>บน iPhone/iPad เปิดใน Safari แตะปุ่มแชร์ แล้วเลือก “เพิ่มไปยังหน้าจอโฮม”</p>
<p>บน Android หรือคอมพิวเตอร์ เปิดเมนูของเบราว์เซอร์ แล้วเลือก “ติดตั้งแอป” หรือ “เพิ่มไปยังหน้าจอหลัก” หากมีตัวเลือกนี้</p>
</div>}
{error && <p role="alert" className="text-sm text-destructive">{error}</p>}
<DialogFooter>
<Button variant="outline" onClick={() => setOpen(false)}>ปิด</Button>
{installEvent && <Button disabled={busy} onClick={() => void install()}>{busy ? "กำลังติดตั้ง…" : "ติดตั้งแอป"}</Button>}
</DialogFooter>
</DialogContent>
</Dialog>
</>;
}