'use client' import * as React from 'react' import { Download, Smartphone, Monitor, CheckCircle, XCircle, AlertCircle, Loader2 } from 'lucide-react' import { Button } from '@/components/ui/button' import { Card, CardContent } from '@/components/ui/card' export function InstallButton({ variant = 'ghost', size = 'icon', className = '', ...props }: { variant?: 'default' | 'ghost' | 'outline'; size?: 'sm' | 'icon'; className?: string }) { const [showInstructions, setShowInstructions] = React.useState(false) const [platform, setPlatform] = React.useState<'android' | 'ios' | 'desktop' | 'unknown'>('unknown') const [swDiagnostic, setSwDiagnostic] = React.useState<{ controlling: boolean swVersion?: string error?: string } | null>(null) const [checkingSW, setCheckingSW] = React.useState(false) React.useEffect(() => { const ua = navigator.userAgent const isStandalone = window.matchMedia('(display-mode: standalone)').matches const isInWebAppiOS = (window.navigator as any).standalone === true if (isStandalone || isInWebAppiOS) return if (/iPad|iPhone|iPod/.test(ua)) setPlatform('ios') else if (/Android/.test(ua)) setPlatform('android') else setPlatform('desktop') }, []) const checkSW = async () => { setCheckingSW(true) try { if (!('serviceWorker' in navigator)) { setSwDiagnostic({ controlling: false, error: 'Service Workers not supported' }) return } // First, unregister all old SWs to force fresh registration const regs = await navigator.serviceWorker.getRegistrations() for (const reg of regs) { if (reg.active?.scriptURL.includes('sw.js') && !reg.active.scriptURL.includes('v=3')) { await reg.unregister() console.log('Unregistered old SW:', reg.scope) } } // Register fresh const reg = await navigator.serviceWorker.register('/sw.js?v=3', { updateViaCache: 'none' }) await reg.update() const controlling = !!navigator.serviceWorker.controller let swVersion = 'unknown' try { const res = await fetch('/sw.js?v=3') const text = await res.text() const match = text.match(/version\s+(\d+)/i) || text.match(/v(\d+)/i) if (match) swVersion = match[1] } catch {} setSwDiagnostic({ controlling, swVersion }) } catch (err) { setSwDiagnostic({ controlling: false, error: String(err) }) } finally { setCheckingSW(false) } } React.useEffect(() => { checkSW() }, []) const handleClick = () => setShowInstructions(true) const isInstalled = window.matchMedia('(display-mode: standalone)').matches || (window.navigator as any).standalone === true if (isInstalled) { return ( ) } return (
{/* SW Status Indicator */}
{/* Diagnostic Tooltip */} {swDiagnostic && (

SW Diagnostic

Service Worker: Registered
{swDiagnostic.controlling ? : } Controlling page: {swDiagnostic.controlling ? 'YES ✓' : 'NO ✗'}
{swDiagnostic.swVersion && (
Version: {swDiagnostic.swVersion}
)} {swDiagnostic.error && (
Error: {swDiagnostic.error}
)} {!swDiagnostic.controlling && (
If controlling=NO: refresh page, or check Brave Shields (lion icon → OFF)
)}
)} {showInstructions && (
setShowInstructions(false)} />

Install OfflineAcademy

{platform === 'android' && (

On Android (Chrome/Brave/Edge), use the browser menu:

Chrome / Edge

Menu (⋮ top-right) → "Install app" or "Add to Home screen"

Brave Browser

Menu (⋮ bottom-right) → "Install app"
If missing: Shields OFF (lion icon) → reload

)} {platform === 'ios' && (

On iOS (Safari), use the Share button:

  1. Tap Share button (square with arrow up) at bottom
  2. Scroll down, tap "Add to Home Screen"
  3. Tap "Add" top-right
)} {platform === 'desktop' && (

On Desktop (Chrome/Edge):

Chrome

Menu (⋮ top-right) → "Install OfflineAcademy" or "Install app"

Edge

Menu (⋮ top-right) → "Apps""Install this site as an app"

Creates Start Menu shortcut (Windows) / Applications folder (Mac)
)} {platform === 'unknown' && (

Open in Chrome/Edge/Safari/Brave for install options

)}
)}
) }