feat: Show navigation panel when clicking user from list

When clicking a user from the participant list:
1. Map zooms to their location
2. Navigation panel appears with "Navigate here" option
3. Clicking "Navigate here" calculates route to that user

The selectedParticipant state is now lifted to the page level and
passed to DualMapView so both components stay in sync.

🤖 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 03:03:16 +01:00
parent 40cfea26a2
commit 908767be15
2 changed files with 16 additions and 5 deletions

View File

@ -336,9 +336,11 @@ export default function RoomPage() {
isSharing={isSharing}
onToggleSharing={handleToggleSharing}
zoomToLocation={zoomToLocation}
selectedParticipant={selectedParticipant}
onSelectedParticipantChange={setSelectedParticipant}
onParticipantClick={(p) => {
setSelectedParticipant(p);
setShowParticipants(true);
setShowParticipants(false); // Hide list to show map with navigation panel
}}
onWaypointClick={(w) => {
setSelectedWaypoint(w);

View File

@ -44,6 +44,10 @@ interface DualMapViewProps {
onToggleSharing?: () => void;
/** Location to zoom/fly to */
zoomToLocation?: { latitude: number; longitude: number } | null;
/** Selected participant (for navigation panel) */
selectedParticipant?: Participant | null;
/** Callback when selected participant changes */
onSelectedParticipantChange?: (participant: Participant | null) => void;
}
// CCC venue bounds (Hamburg Congress Center)
@ -67,10 +71,15 @@ export default function DualMapView({
isSharing = false,
onToggleSharing,
zoomToLocation,
selectedParticipant: selectedParticipantProp,
onSelectedParticipantChange,
}: DualMapViewProps) {
const [mode, setMode] = useState<MapMode>(initialMode);
const [activeView, setActiveView] = useState<'outdoor' | 'indoor'>('outdoor');
const [selectedParticipant, setSelectedParticipant] = useState<Participant | null>(null);
// Use prop if provided, otherwise manage internally
const [selectedParticipantInternal, setSelectedParticipantInternal] = useState<Participant | null>(null);
const selectedParticipant = selectedParticipantProp !== undefined ? selectedParticipantProp : selectedParticipantInternal;
const setSelectedParticipant = onSelectedParticipantChange || setSelectedParticipantInternal;
const [selectedWaypoint, setSelectedWaypoint] = useState<Waypoint | null>(null);
// Get route state from store
@ -107,20 +116,20 @@ export default function DualMapView({
setSelectedParticipant(participant);
setSelectedWaypoint(null);
onParticipantClick?.(participant);
}, [onParticipantClick]);
}, [onParticipantClick, setSelectedParticipant]);
// Handle waypoint click - show navigation panel
const handleWaypointClick = useCallback((waypoint: Waypoint) => {
setSelectedWaypoint(waypoint);
setSelectedParticipant(null);
onWaypointClick?.(waypoint);
}, [onWaypointClick]);
}, [onWaypointClick, setSelectedParticipant]);
// Close navigation panel
const closeNavigationPanel = useCallback(() => {
setSelectedParticipant(null);
setSelectedWaypoint(null);
}, []);
}, [setSelectedParticipant]);
return (
<div className="relative w-full h-full">