181 lines
9.3 KiB
TypeScript
181 lines
9.3 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from '@/components/ui/dialog';
|
|
import { Download, Share, Plus, MoreVertical, Smartphone } from 'lucide-react';
|
|
|
|
interface BeforeInstallPromptEvent extends Event {
|
|
prompt: () => Promise<void>;
|
|
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;
|
|
}
|
|
|
|
export function InstallAppButton() {
|
|
const [showInstructions, setShowInstructions] = useState(false);
|
|
const [deferredPrompt, setDeferredPrompt] = useState<BeforeInstallPromptEvent | null>(null);
|
|
const [isIOS, setIsIOS] = useState(false);
|
|
const [isAndroid, setIsAndroid] = useState(false);
|
|
const [isStandalone, setIsStandalone] = useState(false);
|
|
|
|
useEffect(() => {
|
|
// Check if already installed as PWA
|
|
const isAppInstalled = window.matchMedia('(display-mode: standalone)').matches ||
|
|
(window.navigator as Navigator & { standalone?: boolean }).standalone === true;
|
|
setIsStandalone(isAppInstalled);
|
|
|
|
// Detect platform
|
|
const userAgent = window.navigator.userAgent.toLowerCase();
|
|
const isIOSDevice = /iphone|ipad|ipod/.test(userAgent);
|
|
const isAndroidDevice = /android/.test(userAgent);
|
|
setIsIOS(isIOSDevice);
|
|
setIsAndroid(isAndroidDevice);
|
|
|
|
// Listen for beforeinstallprompt (Android/Chrome)
|
|
const handleBeforeInstallPrompt = (e: Event) => {
|
|
e.preventDefault();
|
|
setDeferredPrompt(e as BeforeInstallPromptEvent);
|
|
};
|
|
|
|
window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
|
|
|
|
return () => {
|
|
window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt);
|
|
};
|
|
}, []);
|
|
|
|
const handleInstallClick = async () => {
|
|
if (deferredPrompt) {
|
|
// Use the native install prompt (Android/Chrome)
|
|
await deferredPrompt.prompt();
|
|
const { outcome } = await deferredPrompt.userChoice;
|
|
if (outcome === 'accepted') {
|
|
setDeferredPrompt(null);
|
|
}
|
|
} else {
|
|
// Show manual instructions
|
|
setShowInstructions(true);
|
|
}
|
|
};
|
|
|
|
// Don't show if already installed as PWA
|
|
if (isStandalone) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={handleInstallClick}
|
|
className="gap-2 border-purple-500/30 hover:bg-purple-500/10 hover:border-purple-500/50"
|
|
>
|
|
<Smartphone className="h-4 w-4 text-purple-400" />
|
|
<span className="hidden sm:inline">Add to Home Screen</span>
|
|
<span className="sm:hidden">Install</span>
|
|
</Button>
|
|
|
|
<Dialog open={showInstructions} onOpenChange={setShowInstructions}>
|
|
<DialogContent className="sm:max-w-md">
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-2">
|
|
<Download className="h-5 w-5 text-purple-400" />
|
|
Add QuitTraq to Home Screen
|
|
</DialogTitle>
|
|
<DialogDescription>
|
|
Get quick access to track your progress right from your phone's home screen.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="space-y-6 py-4">
|
|
{isIOS ? (
|
|
// iOS Instructions
|
|
<div className="space-y-4">
|
|
<p className="text-sm font-medium text-purple-400">For iPhone / iPad (Safari):</p>
|
|
<ol className="space-y-4 text-sm">
|
|
<li className="flex items-start gap-3">
|
|
<span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-purple-500/20 text-purple-400 text-xs font-bold">1</span>
|
|
<div>
|
|
<p>Tap the <strong>Share</strong> button</p>
|
|
<div className="mt-1 inline-flex items-center gap-1 rounded bg-muted px-2 py-1">
|
|
<Share className="h-4 w-4" />
|
|
</div>
|
|
</div>
|
|
</li>
|
|
<li className="flex items-start gap-3">
|
|
<span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-purple-500/20 text-purple-400 text-xs font-bold">2</span>
|
|
<div>
|
|
<p>Scroll down and tap <strong>"Add to Home Screen"</strong></p>
|
|
<div className="mt-1 inline-flex items-center gap-1 rounded bg-muted px-2 py-1">
|
|
<Plus className="h-4 w-4" /> Add to Home Screen
|
|
</div>
|
|
</div>
|
|
</li>
|
|
<li className="flex items-start gap-3">
|
|
<span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-purple-500/20 text-purple-400 text-xs font-bold">3</span>
|
|
<p>Tap <strong>"Add"</strong> to confirm</p>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
) : isAndroid ? (
|
|
// Android Instructions
|
|
<div className="space-y-4">
|
|
<p className="text-sm font-medium text-purple-400">For Android (Chrome):</p>
|
|
<ol className="space-y-4 text-sm">
|
|
<li className="flex items-start gap-3">
|
|
<span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-purple-500/20 text-purple-400 text-xs font-bold">1</span>
|
|
<div>
|
|
<p>Tap the <strong>menu</strong> button (3 dots)</p>
|
|
<div className="mt-1 inline-flex items-center gap-1 rounded bg-muted px-2 py-1">
|
|
<MoreVertical className="h-4 w-4" />
|
|
</div>
|
|
</div>
|
|
</li>
|
|
<li className="flex items-start gap-3">
|
|
<span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-purple-500/20 text-purple-400 text-xs font-bold">2</span>
|
|
<div>
|
|
<p>Tap <strong>"Add to Home screen"</strong> or <strong>"Install app"</strong></p>
|
|
</div>
|
|
</li>
|
|
<li className="flex items-start gap-3">
|
|
<span className="flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-purple-500/20 text-purple-400 text-xs font-bold">3</span>
|
|
<p>Tap <strong>"Add"</strong> or <strong>"Install"</strong> to confirm</p>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
) : (
|
|
// Desktop / Unknown
|
|
<div className="space-y-4">
|
|
<p className="text-sm font-medium text-purple-400">On mobile device:</p>
|
|
<ul className="space-y-2 text-sm text-muted-foreground">
|
|
<li>• <strong>iPhone/iPad:</strong> Use Safari, tap Share → Add to Home Screen</li>
|
|
<li>• <strong>Android:</strong> Use Chrome, tap Menu → Add to Home screen</li>
|
|
</ul>
|
|
<p className="text-xs text-muted-foreground mt-4">
|
|
Open this page on your phone to add QuitTraq to your home screen for quick access!
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
<div className="pt-2 border-t">
|
|
<p className="text-xs text-muted-foreground text-center">
|
|
📱 Once added, tap the QuitTraq icon to quickly log your usage!
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<Button onClick={() => setShowInstructions(false)} className="w-full">
|
|
Got it!
|
|
</Button>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</>
|
|
);
|
|
}
|