feat: Zoom to location instead of opening Google Maps

Replace all Google Maps navigation links with in-app zoom functionality.
When clicking on a participant or waypoint to navigate, the map now
smoothly flies to their location at zoom level 17 instead of opening
an external Google Maps link.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2025-12-29 02:53:16 +01:00
parent 1dddf16c6a
commit 40cfea26a2
3 changed files with 29 additions and 9 deletions

View File

@ -37,6 +37,7 @@ export default function RoomPage() {
const [selectedParticipant, setSelectedParticipant] = useState<Participant | null>(null); const [selectedParticipant, setSelectedParticipant] = useState<Participant | null>(null);
const [selectedWaypoint, setSelectedWaypoint] = useState<Waypoint | null>(null); const [selectedWaypoint, setSelectedWaypoint] = useState<Waypoint | null>(null);
const [shouldAutoStartSharing, setShouldAutoStartSharing] = useState(false); const [shouldAutoStartSharing, setShouldAutoStartSharing] = useState(false);
const [zoomToLocation, setZoomToLocation] = useState<{ latitude: number; longitude: number } | null>(null);
// Load user and sharing preference from localStorage // Load user and sharing preference from localStorage
useEffect(() => { useEffect(() => {
@ -263,17 +264,16 @@ export default function RoomPage() {
}; };
}, [leave]); }, [leave]);
// Navigate to participant - opens Google Maps navigation // Navigate to participant - zoom to their location on the map
const handleNavigateTo = (participant: Participant) => { const handleNavigateTo = (participant: Participant) => {
if (!participant.location) { if (!participant.location) {
console.log('No location for participant:', participant.name); console.log('No location for participant:', participant.name);
return; return;
} }
const { latitude, longitude } = participant.location; const { latitude, longitude } = participant.location;
window.open( setZoomToLocation({ latitude, longitude });
`https://www.google.com/maps/dir/?api=1&destination=${latitude},${longitude}`, setSelectedParticipant(participant);
'_blank' setShowParticipants(false); // Close participant list to show map
);
}; };
// Loading state // Loading state
@ -335,6 +335,7 @@ export default function RoomPage() {
eventId="39c3" eventId="39c3"
isSharing={isSharing} isSharing={isSharing}
onToggleSharing={handleToggleSharing} onToggleSharing={handleToggleSharing}
zoomToLocation={zoomToLocation}
onParticipantClick={(p) => { onParticipantClick={(p) => {
setSelectedParticipant(p); setSelectedParticipant(p);
setShowParticipants(true); setShowParticipants(true);
@ -397,10 +398,7 @@ export default function RoomPage() {
}} }}
onNavigate={() => { onNavigate={() => {
const { latitude, longitude } = selectedWaypoint.location; const { latitude, longitude } = selectedWaypoint.location;
window.open( setZoomToLocation({ latitude, longitude });
`https://www.google.com/maps/dir/?api=1&destination=${latitude},${longitude}`,
'_blank'
);
setSelectedWaypoint(null); setSelectedWaypoint(null);
}} }}
/> />

View File

@ -42,6 +42,8 @@ interface DualMapViewProps {
isSharing?: boolean; isSharing?: boolean;
/** Callback to toggle location sharing */ /** Callback to toggle location sharing */
onToggleSharing?: () => void; onToggleSharing?: () => void;
/** Location to zoom/fly to */
zoomToLocation?: { latitude: number; longitude: number } | null;
} }
// CCC venue bounds (Hamburg Congress Center) // CCC venue bounds (Hamburg Congress Center)
@ -64,6 +66,7 @@ export default function DualMapView({
onIndoorPositionSet, onIndoorPositionSet,
isSharing = false, isSharing = false,
onToggleSharing, onToggleSharing,
zoomToLocation,
}: DualMapViewProps) { }: DualMapViewProps) {
const [mode, setMode] = useState<MapMode>(initialMode); const [mode, setMode] = useState<MapMode>(initialMode);
const [activeView, setActiveView] = useState<'outdoor' | 'indoor'>('outdoor'); const [activeView, setActiveView] = useState<'outdoor' | 'indoor'>('outdoor');
@ -129,6 +132,7 @@ export default function DualMapView({
currentUserId={currentUserId} currentUserId={currentUserId}
onParticipantClick={handleParticipantClick} onParticipantClick={handleParticipantClick}
onWaypointClick={handleWaypointClick} onWaypointClick={handleWaypointClick}
zoomToLocation={zoomToLocation}
routeSegments={activeRoute?.segments} routeSegments={activeRoute?.segments}
routeLoading={activeRoute?.isLoading} routeLoading={activeRoute?.isLoading}
routeError={activeRoute?.error} routeError={activeRoute?.error}

View File

@ -17,6 +17,8 @@ interface MapViewProps {
onMapClick?: (lngLat: { lng: number; lat: number }) => void; onMapClick?: (lngLat: { lng: number; lat: number }) => void;
/** Auto-center on current user's location when first available */ /** Auto-center on current user's location when first available */
autoCenterOnUser?: boolean; autoCenterOnUser?: boolean;
/** Location to zoom/fly to */
zoomToLocation?: { latitude: number; longitude: number } | null;
/** Active route segments to display */ /** Active route segments to display */
routeSegments?: RouteSegment[]; routeSegments?: RouteSegment[];
/** Route loading state */ /** Route loading state */
@ -64,6 +66,7 @@ export default function MapView({
onWaypointClick, onWaypointClick,
onMapClick, onMapClick,
autoCenterOnUser = true, autoCenterOnUser = true,
zoomToLocation,
routeSegments = [], routeSegments = [],
routeLoading = false, routeLoading = false,
routeError, routeError,
@ -233,6 +236,21 @@ export default function MapView({
} }
}, [participants, mapLoaded, currentUserId, onParticipantClick, autoCenterOnUser]); }, [participants, mapLoaded, currentUserId, onParticipantClick, autoCenterOnUser]);
// Fly to location when zoomToLocation changes
useEffect(() => {
if (!map.current || !mapLoaded || !zoomToLocation) return;
const { latitude, longitude } = zoomToLocation;
if (isValidCoordinate(latitude, longitude)) {
console.log('Flying to location:', latitude, longitude);
map.current.flyTo({
center: [longitude, latitude],
zoom: 17,
duration: 1500,
});
}
}, [zoomToLocation, mapLoaded]);
// Update waypoint markers // Update waypoint markers
useEffect(() => { useEffect(() => {
if (!map.current || !mapLoaded) return; if (!map.current || !mapLoaded) return;