diff --git a/src/app/[slug]/page.tsx b/src/app/[slug]/page.tsx index 4f7a822..28c60ba 100644 --- a/src/app/[slug]/page.tsx +++ b/src/app/[slug]/page.tsx @@ -11,6 +11,7 @@ import RoomHeader from '@/components/room/RoomHeader'; import ShareModal from '@/components/room/ShareModal'; import MeetingPointModal from '@/components/room/MeetingPointModal'; import WaypointModal from '@/components/room/WaypointModal'; +import InstallBanner from '@/components/room/InstallBanner'; import type { Participant, ParticipantLocation, Waypoint } from '@/types'; // Dynamic import for map to avoid SSR issues with MapLibre @@ -242,11 +243,17 @@ export default function RoomPage() { }; }, [leave]); - // Navigate to participant + // Navigate to participant - opens Google Maps navigation const handleNavigateTo = (participant: Participant) => { - setSelectedParticipant(participant); - // TODO: Implement navigation route display - console.log('Navigate to:', participant.name); + if (!participant.location) { + console.log('No location for participant:', participant.name); + return; + } + const { latitude, longitude } = participant.location; + window.open( + `https://www.google.com/maps/dir/?api=1&destination=${latitude},${longitude}`, + '_blank' + ); }; // Loading state @@ -283,6 +290,9 @@ export default function RoomPage() { return (
+ {/* PWA Install Banner */} + + {/* Header */} { + setDismissed(true); + sessionStorage.setItem('rmaps_install_dismissed', 'true'); + }; + + const handleInstall = async () => { + if (isIOS) { + setShowIOSInstructions(true); + } else { + const success = await promptInstall(); + if (success) { + handleDismiss(); + } + } + }; + + return ( + <> +
+
+ 📲 + Install rMaps for the best experience +
+
+ + +
+
+ + {/* iOS Instructions Modal */} + {showIOSInstructions && ( +
+
setShowIOSInstructions(false)} /> +
+

Install on iOS

+
    +
  1. + 1. + Tap the Share button in Safari +
  2. +
  3. + 2. + Scroll down and tap "Add to Home Screen" +
  4. +
  5. + 3. + Tap "Add" in the top right +
  6. +
+ +
+
+ )} + + ); +} diff --git a/src/hooks/usePWAInstall.ts b/src/hooks/usePWAInstall.ts new file mode 100644 index 0000000..a65b483 --- /dev/null +++ b/src/hooks/usePWAInstall.ts @@ -0,0 +1,78 @@ +'use client'; + +import { useState, useEffect, useCallback } from 'react'; + +interface BeforeInstallPromptEvent extends Event { + prompt(): Promise; + userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>; +} + +export function usePWAInstall() { + const [installPrompt, setInstallPrompt] = useState(null); + const [isInstallable, setIsInstallable] = useState(false); + const [isInstalled, setIsInstalled] = useState(false); + + useEffect(() => { + // Check if already installed (standalone mode) + if (window.matchMedia('(display-mode: standalone)').matches) { + setIsInstalled(true); + return; + } + + // Check iOS standalone + if ((navigator as any).standalone === true) { + setIsInstalled(true); + return; + } + + const handleBeforeInstall = (e: Event) => { + e.preventDefault(); + setInstallPrompt(e as BeforeInstallPromptEvent); + setIsInstallable(true); + }; + + const handleAppInstalled = () => { + setIsInstalled(true); + setIsInstallable(false); + setInstallPrompt(null); + }; + + window.addEventListener('beforeinstallprompt', handleBeforeInstall); + window.addEventListener('appinstalled', handleAppInstalled); + + return () => { + window.removeEventListener('beforeinstallprompt', handleBeforeInstall); + window.removeEventListener('appinstalled', handleAppInstalled); + }; + }, []); + + const promptInstall = useCallback(async () => { + if (!installPrompt) return false; + + try { + await installPrompt.prompt(); + const result = await installPrompt.userChoice; + + if (result.outcome === 'accepted') { + setIsInstalled(true); + setIsInstallable(false); + setInstallPrompt(null); + return true; + } + } catch (error) { + console.error('Install prompt error:', error); + } + return false; + }, [installPrompt]); + + const isIOS = typeof navigator !== 'undefined' && + /iPad|iPhone|iPod/.test(navigator.userAgent) && + !(window as any).MSStream; + + return { + isInstallable, + isInstalled, + isIOS, + promptInstall, + }; +}