diff --git a/index.html b/index.html index c784b70..89ae8da 100644 --- a/index.html +++ b/index.html @@ -15,6 +15,10 @@ /> + + + + Agro Control — Smart Farm Platform diff --git a/public/Logo-192.png b/public/Logo-192.png new file mode 100644 index 0000000..f677a2e Binary files /dev/null and b/public/Logo-192.png differ diff --git a/public/Logo-512.png b/public/Logo-512.png new file mode 100644 index 0000000..4e5869d Binary files /dev/null and b/public/Logo-512.png differ diff --git a/src/App.tsx b/src/App.tsx index 8e5cc25..4c19e38 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,7 +1,13 @@ import { AppRouter } from './routes/AppRouter'; +import { PWAInstallBanner } from './components/pwa/PWAInstallBanner'; function App() { - return ; + return ( + <> + + + + ); } export default App; diff --git a/src/components/pwa/PWAInstallBanner.tsx b/src/components/pwa/PWAInstallBanner.tsx new file mode 100644 index 0000000..835ecb7 --- /dev/null +++ b/src/components/pwa/PWAInstallBanner.tsx @@ -0,0 +1,158 @@ +import { useEffect, useState } from 'react'; +import { usePWAInstall } from '../../hooks/usePWAInstall'; + +/** + * PWAInstallBanner + * + * Banner premium de instalación de la PWA. + * Se muestra como un banner flotante en la parte inferior de la pantalla, + * con animación de entrada/salida, glassmorphism, y lógica inteligente + * para no ser invasivo (cooldown de 7 días tras descartar). + * + * Compatible con desktop (Chrome, Edge) y móvil (Android Chrome, Samsung Internet). + * En iOS Safari no se soporta `beforeinstallprompt` — el banner no se mostrará. + */ +export function PWAInstallBanner() { + const { canInstall, isInstalled, promptInstall, dismiss } = usePWAInstall(); + const [visible, setVisible] = useState(false); + const [exiting, setExiting] = useState(false); + + // Mostrar con un delay de 2 segundos para no interrumpir la carga inicial + useEffect(() => { + if (!canInstall || isInstalled) { + setVisible(false); + return; + } + + const timer = setTimeout(() => setVisible(true), 2000); + return () => clearTimeout(timer); + }, [canInstall, isInstalled]); + + const handleDismiss = () => { + setExiting(true); + setTimeout(() => { + setVisible(false); + setExiting(false); + dismiss(); + }, 300); + }; + + const handleInstall = async () => { + await promptInstall(); + setExiting(true); + setTimeout(() => { + setVisible(false); + setExiting(false); + }, 300); + }; + + if (!visible) return null; + + return ( + <> + {/* Backdrop sutil — solo en móvil para dar enfoque */} +