Fix: Mapbox preview not updating on search#223
Conversation
The Mapbox preview was not updating when a user searched for a location. This was because the `flyTo` animation was being interrupted and not correctly restarting. This commit fixes the issue by: - Stopping any existing rotation before starting a new `flyTo` animation. - Ensuring the map rotation restarts after the `flyTo` animation is complete. - Using a `finally` block to ensure the `isUpdatingPositionRef` is always reset. - Fixing a few linting warnings.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
|
WalkthroughRotation now resumes unconditionally after moves and is explicitly stopped before programmatic target moves; MapData-driven position updates validate coordinates and halt rotation; long-press drawing disabled in RealTimeMode; provider composition changed (MapDataProvider now wraps AI); Chat reads map data via hook and syncs drawnFeatures to server; extensive debug logging added across map-query, geospatial tool, and actions. Changes
Sequence Diagram(s)sequenceDiagram
participant MapDataContext
participant MapboxComponent
participant Mapbox
participant Rotation
MapDataContext-->>MapboxComponent: emits targetPosition [lng, lat]
MapboxComponent->>Rotation: stopRotation()
MapboxComponent->>MapboxComponent: validate lng/lat (numbers)
alt valid
MapboxComponent->>Mapbox: updateMapPosition(lat,lng)
Mapbox-->>MapboxComponent: move complete
MapboxComponent->>Rotation: startRotation() (unconditional)
else invalid
MapboxComponent->>MapboxComponent: clear targetPosition/mapFeature
end
sequenceDiagram
participant App
participant MapDataProvider
participant AI
participant Chat
App->>MapDataProvider: mount (outer)
MapDataProvider->>AI: provide AI (inner)
AI->>Chat: render Chat
Chat->>MapDataProvider: useMapData() (direct hook access)
Chat->>Server: updateDrawingContext(id, drawnFeatures) [when present]
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
PR Code Suggestions ✨No code suggestions found for the PR. |
PR Code Suggestions ✨Explore these optional code suggestions:
|
||||||||||||
This commit fixes an issue where the Mapbox preview would not update when a user searched for a location. The root cause of the issue was the placement of the `MapDataProvider`. It was not correctly wrapping all the components that needed access to the map data. This meant that the `MapQueryHandler` and the `Mapbox` component were not sharing the same context, so the map would not update when the context was changed. This commit fixes the issue by moving the `MapDataProvider` to wrap the `AI` provider in `app/search/[id]/page.tsx`. This ensures that all components have access to the same map data context. This commit also includes a previous fix that makes the map update logic in `mapbox-map.tsx` more robust.
There was a problem hiding this comment.
Actionable comments posted: 0
🔭 Outside diff range comments (3)
components/map/mapbox-map.tsx (3)
500-504: Fix falsy checks for zero coordinates (0 latitude/longitude)
0is a valid coordinate but falsy; the current check skips updates at the equator/prime meridian.- if (map.current && position?.latitude && position?.longitude && mapType === MapToggleEnum.RealTimeMode) { - updateMapPosition(position.latitude, position.longitude) - } + if ( + map.current && + position && + Number.isFinite(position.latitude) && + Number.isFinite(position.longitude) && + mapType === MapToggleEnum.RealTimeMode + ) { + updateMapPosition(position.latitude, position.longitude) + }
487-497: Map initialization effect tears down/rebuilds on dependency changesBecause the effect returns a cleanup unconditionally, any dependency change triggers full teardown (
map.remove()) and re-init on the next pass. This causes flicker, lost map state, and unnecessary work.Make the initialization effect run once on mount/unmount.
- }, [ - handleUserInteraction, - startRotation, - stopRotation, - mapType, - updateMeasurementLabels, - setupGeolocationWatcher, - captureMapCenter, - setupDrawingTools, - setIsMapLoaded // Added missing dependency - ]) + }, [])Note: map type changes and draw control setup are already handled in the dedicated
mapTypeeffect.
552-601: Cleanup-only effect currently tears down the map on any dependency changeThis effect returns only a cleanup function yet depends on many values. On each dependency change, it removes the map, draw controls, labels, etc. This fights the rest of the component lifecycle.
Either remove this effect (preferred) and rely on the initialization effect’s cleanup, or make it run only on unmount with an empty dependency array.
Option A (remove the effect entirely):
- useEffect(() => { - // ... existing useEffect logic ... - return () => { - // ... existing cleanup logic ... - if (longPressTimerRef.current) { // Cleanup timer on component unmount - clearTimeout(longPressTimerRef.current); - longPressTimerRef.current = null; - } - // ... existing cleanup logic for map and geolocation ... - if (map.current) { - map.current.off('moveend', captureMapCenter) - - if (drawRef.current) { - try { - map.current.off('draw.create', updateMeasurementLabels) - map.current.off('draw.delete', updateMeasurementLabels) - map.current.off('draw.update', updateMeasurementLabels) - map.current.removeControl(drawRef.current) - } catch (e) { - console.log('Draw control already removed') - } - } - - Object.values(polygonLabelsRef.current).forEach(marker => marker.remove()) - Object.values(lineLabelsRef.current).forEach(marker => marker.remove()) - - stopRotation() - setIsMapLoaded(false) - map.current.remove() - map.current = null - } - - if (geolocationWatchIdRef.current !== null) { - navigator.geolocation.clearWatch(geolocationWatchIdRef.current) - geolocationWatchIdRef.current = null - } - }; - }, [ - handleUserInteraction, - startRotation, - stopRotation, - mapType, // mapType is already here, good. - updateMeasurementLabels, - setupGeolocationWatcher, - captureMapCenter, - setupDrawingTools, - setIsMapLoaded - ]); + // (Effect removed — cleanup is handled in the map initialization effect)Option B (if you want to keep it): change the dependency array to
[]so it only runs on unmount.
🧹 Nitpick comments (5)
components/map/mapbox-map.tsx (5)
221-224: Restart rotation only when appropriate; also avoid double-resetting the update flagStarting rotation unconditionally after flyTo can re-enable rotation in RealTimeMode, which earlier logic avoided. Also,
isUpdatingPositionRef.currentis reset here and in thefinallyblock—keep a single source of truth.
- Gate rotation restart by mode (if intended).
- Rely on the
finallyblock to resetisUpdatingPositionRef.If you want rotation to remain disabled in RealTimeMode after a search, apply:
- setTimeout(() => { - startRotation() - isUpdatingPositionRef.current = false - }, 500) + setTimeout(() => { + if (mapType !== MapToggleEnum.RealTimeMode) { + startRotation() + } + }, 500)And update the hook deps to include
mapType:- }, [startRotation, stopRotation]) + }, [startRotation, stopRotation, mapType])
227-229: Good: always resetisUpdatingPositionRefvia finallySolid reliability improvement. With this in place, you can remove the flag reset inside the
setTimeoutto avoid redundant writes.
209-220: Add a timeout fallback in casemoveenddoesn’t fireIf
flyToresults in no effective movement (or gets interrupted),moveendmight not fire, leaving the promise pending and the UI stuck. A small fallback avoids this.- await new Promise<void>((resolve) => { - map.current?.flyTo({ - center: [longitude, latitude], - zoom: 12, - essential: true, - speed: 0.5, - curve: 1, - }) - map.current?.once('moveend', () => { - resolve() - }) - }) + await new Promise<void>((resolve) => { + const timeoutId = setTimeout(() => resolve(), 3000) // Fallback if no 'moveend' + map.current?.once('moveend', () => { + clearTimeout(timeoutId) + resolve() + }) + map.current?.flyTo({ + center: [longitude, latitude], + zoom: 12, + essential: true, + speed: 0.5, + curve: 1, + }) + })
231-231: Confirm removal ofmapTypefromupdateMapPositiondepsIf you intend to restart rotation regardless of mode, this is fine. If you gate rotation by
mapType(as suggested), add it back to the deps.
37-37: PreferReturnType<typeof setTimeout>for timer ref in browser context
NodeJS.Timeoutcan be incorrect under DOM typings.ReturnType<typeof setTimeout>is robust across environments.- const longPressTimerRef = useRef<NodeJS.Timeout | null>(null); + const longPressTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
components/map/mapbox-map.tsx(3 hunks)
🔇 Additional comments (1)
components/map/mapbox-map.tsx (1)
508-516: Stopping rotation before context-driven flyTo looks goodHalting rotation before a programmatic move removes the interference that was breaking the preview update. This aligns with the PR objective.
There was a problem hiding this comment.
Actionable comments posted: 1
🔭 Outside diff range comments (1)
components/chat.tsx (1)
66-72: Handle server action errors and support clearing on empty features; avoid noisy logsThe effect fires on every drawnFeatures change but:
- It ignores the “clear” case (length === 0), leaving stale server state.
- It doesn’t handle rejections, which can produce unhandled promise rejections.
- It logs feature payloads to console on the client.
Apply:
- useEffect(() => { - if (id && mapData.drawnFeatures && mapData.drawnFeatures.length > 0) { - console.log('Chat.tsx: drawnFeatures changed, calling updateDrawingContext', mapData.drawnFeatures); - updateDrawingContext(id, mapData.drawnFeatures); - } - }, [id, mapData.drawnFeatures]); + useEffect(() => { + if (!id) return; + const features = mapData.drawnFeatures ?? []; + // Optional: enable for local debugging only + // if (process.env.NODE_ENV !== 'production') { + // console.debug('drawnFeatures changed; updating drawing context', features); + // } + void updateDrawingContext(id, features).catch((err) => { + console.error('Failed to update drawing context', err); + }); + }, [id, mapData.drawnFeatures]);Optionally consider debouncing/batching if drawnFeatures changes rapidly during drawing interactions.
🧹 Nitpick comments (3)
app/search/[id]/page.tsx (2)
12-18: Type params per Next.js conventions; drop Promise/await for paramsNext.js app router provides params synchronously. Typing params as Promise and awaiting it works at runtime but is misleading and can confuse tooling. Recommend using the standard shape.
Apply:
-export interface SearchPageProps { - params: Promise<{ id: string }>; // Keep as is for now -} +export interface SearchPageProps { + params: { id: string }; +} export async function generateMetadata({ params }: SearchPageProps) { - const { id } = await params; // Keep as is for now + const { id } = params; // TODO: Metadata generation might need authenticated user if chats are private // For now, assuming getChat can be called or it handles anon access for metadata appropriately const userId = await getCurrentUserIdOnServer(); // Attempt to get user for metadata const chat = await getChat(id, userId || 'anonymous'); // Pass userId or 'anonymous' if none return { title: chat?.title?.toString().slice(0, 50) || 'Search', }; } export default async function SearchPage({ params }: SearchPageProps) { - const { id } = await params; // Keep as is for now + const { id } = params; const userId = await getCurrentUserIdOnServer();Also applies to: 27-29
44-60: Avoid unsafe role cast; validate or narrow roles during mappingCasting dbMsg.role to AIMessage['role'] can mask unexpected roles at runtime. Prefer narrowing with a type guard or fallback to a safe role to prevent corrupted state.
Example adjustment:
const allowedRoles = new Set<AIMessage['role']>(['system','user','assistant','tool']); const role = allowedRoles.has(dbMsg.role as any) ? (dbMsg.role as AIMessage['role']) : 'assistant'; return { id: dbMsg.id, role, content: dbMsg.content, createdAt: dbMsg.createdAt ? new Date(dbMsg.createdAt) : undefined, };components/chat.tsx (1)
111-116: Use Tailwind utilities instead of inline style; prefer top offset over margin on fixed elementFor a fixed element, using top-[0.5in] is clearer than combining top-0 with mt-[0.5in]. Also replace inline zIndex with Tailwind’s z-10 for consistency.
- <div - className="w-1/2 p-4 fixed h-[calc(100vh-0.5in)] top-0 right-0 mt-[0.5in]" - style={{ zIndex: 10 }} // Added z-index - > + <div + className="w-1/2 p-4 fixed h-[calc(100vh-0.5in)] right-0 top-[0.5in] z-10" + > {activeView ? <SettingsView /> : <Mapbox />} </div>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
app/search/[id]/page.tsx(1 hunks)components/chat.tsx(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
app/search/[id]/page.tsx (6)
components/map/map-data-context.tsx (1)
MapDataProvider(26-34)components/chat.tsx (1)
Chat(20-119)lib/actions/chat-db.ts (1)
Chat(9-9)lib/types/index.ts (1)
Chat(47-55)app/page.tsx (1)
Page(9-18)lib/actions/chat.ts (1)
msg(119-127)
🔇 Additional comments (2)
components/chat.tsx (2)
77-99: Mobile layout changes look goodClean separation of mobile sections and consistent use of components. No issues spotted.
13-15: No action required — Chat is already wrapped by MapDataProviderVerified Chat mounts are wrapped by MapDataProvider and components/chat.tsx correctly consumes useMapData, so no runtime context error expected.
- app/page.tsx — MapDataProvider wraps (around lines 12–15).
- app/search/[id]/page.tsx — MapDataProvider wraps (around lines 63–74).
- components/chat.tsx — consumes useMapData(); the hook throws if used outside MapDataProvider (components/map/map-data-context.tsx).
| <MapDataProvider> | ||
| <AI | ||
| initialAIState={{ | ||
| chatId: chat.id, | ||
| messages: initialMessages, // Use the transformed messages from the database | ||
| // isSharePage: true, // This was in PR#533, but share functionality is removed. | ||
| // If needed for styling or other logic, it can be set. | ||
| }} | ||
| > | ||
| <Chat id={id} /> | ||
| </MapDataProvider> | ||
| </AI> | ||
| </AI> | ||
| </MapDataProvider> | ||
| ); |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify and align provider order across routes (MapDataProvider ↔ AI) to avoid inconsistent context lifecycles
Here, MapDataProvider wraps AI. In app/page.tsx (home), AI wraps MapDataProvider. Different provider hierarchies can change when mapData resets across page transitions (e.g., navigating between home and search), potentially leading to surprising state persistence/reset behavior. If this is intentional, ignore; otherwise, consider standardizing the order across routes.
Run this script to list occurrences and surrounding context so you can quickly verify composition order:
🏁 Script executed:
#!/bin/bash
# Show occurrences of AI, MapDataProvider, and Chat together to inspect hierarchy
rg -n -C3 -P '(?s)<AI\b|<MapDataProvider\b|<Chat\b' app/**/*.tsxLength of output: 121
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Searching repository for AI, MapDataProvider, Chat usages..."
rg -n -S -C3 -P '(?s)<(AI|MapDataProvider|Chat)\b' || true
echo
echo "Listing any page.tsx files found..."
find . -type f -name 'page.tsx' -print || trueLength of output: 2064
Align provider order (MapDataProvider ↔ AI) across routes
Verified: app/page.tsx uses AI > MapDataProvider, while app/search/[id]/page.tsx uses MapDataProvider > AI. This mismatch can change context lifecycles and cause surprising state resets across navigation. Standardize the order.
Files to update:
- app/page.tsx — AI wraps MapDataProvider (current; lines ~12–16)
- app/search/[id]/page.tsx — MapDataProvider wraps AI (current; lines ~63–74) — change to match chosen order
Suggested change (make app/search/[id]/page.tsx match app/page.tsx by moving AI outermost):
Before
< MapDataProvider>
After
< AI initialAIState={...}>
🤖 Prompt for AI Agents
In app/search/[id]/page.tsx around lines 63 to 75, the provider order is
MapDataProvider wrapping AI which differs from app/page.tsx and can cause
context lifecycle mismatches; change the nesting so AI is the outer provider and
MapDataProvider is inside it, preserving the existing initialAIState prop on AI
and passing Chat id as before (i.e., wrap MapDataProvider and Chat with AI as
the parent) so the component tree matches app/page.tsx.
This commit adds extensive logging to the application to help diagnose an issue where the Mapbox preview is not updating when a user searches for a location. Logging has been added to the following files: - `lib/agents/tools/geospatial.tsx` - `app/actions.tsx` - `components/map/map-query-handler.tsx` - `components/map/mapbox-map.tsx` This logging will trace the data flow from the initial search query all the way to the map component, allowing us to pinpoint exactly where the process is failing.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (5)
lib/agents/tools/geospatial.tsx (2)
154-155: Gate verbose logs behind a debug flag to avoid noisy/PII-ish logs in productionThese logs are great for diagnosing issues but can be noisy and potentially include sensitive inputs/results. Recommend guarding them by environment.
Apply this diff to gate the logs in development only:
@@ - console.log('[GeospatialTool] Execute called with:', JSON.stringify(params, null, 2)); + if (process.env.NODE_ENV !== 'production') { + console.log('[GeospatialTool] Execute called with:', JSON.stringify(params, null, 2)); + } @@ - console.log('[GeospatialTool] Calling tool:', toolName, 'with args:', JSON.stringify(toolArgs, null, 2)); + if (process.env.NODE_ENV !== 'production') { + console.log('[GeospatialTool] Calling tool:', toolName, 'with args:', JSON.stringify(toolArgs, null, 2)); + } @@ - console.log('[GeospatialTool] Raw MCP Response:', JSON.stringify(toolCallResult, null, 2)); + if (process.env.NODE_ENV !== 'production') { + console.log('[GeospatialTool] Raw MCP Response:', JSON.stringify(toolCallResult, null, 2)); + } @@ - console.log('[GeospatialTool] Parsed MCP Response Content:', JSON.stringify(content, null, 2)); + if (process.env.NODE_ENV !== 'production') { + console.log('[GeospatialTool] Parsed MCP Response Content:', JSON.stringify(content, null, 2)); + } - } catch { - console.warn('[GeospatialTool] Content is not JSON, using as string:', content); + } catch { + if (process.env.NODE_ENV !== 'production') { + console.warn('[GeospatialTool] Content is not JSON, using as string:', content); + } } @@ - console.log('[GeospatialTool] Returning result:', JSON.stringify(result, null, 2)); + if (process.env.NODE_ENV !== 'production') { + console.log('[GeospatialTool] Returning result:', JSON.stringify(result, null, 2)); + }Also applies to: 208-208, 228-228, 240-245, 274-276
231-236: Content parsing fallback: consider a softer fallback before erroring on non-JSON contentRight now, if the content isn’t JSON (and can’t be parsed), we end up throwing “Unexpected response format.” If MCP tools sometimes return plain text (e.g., map links or coordinates in text), you might salvage minimal data (like a map URL) without failing.
If plain text payloads are expected from any tool, consider extracting lat/lng via a regex or isolating a URL before throwing, and include a bounded content snippet (e.g., first 200 chars) in the error for diagnostics.
Also applies to: 247-259
components/map/map-query-handler.tsx (2)
39-41: Validate coordinate ranges, not just typesType checks pass for NaN/Infinity and out-of-bounds values. Add range/finite guards to prevent invalid targetPosition updates.
- if (typeof latitude === 'number' && typeof longitude === 'number') { + if ( + Number.isFinite(latitude) && + Number.isFinite(longitude) && + latitude >= -90 && latitude <= 90 && + longitude >= -180 && longitude <= 180 + ) {
34-35: Gate console logging in this effect under a debug flagThese logs are helpful during development, but should be quiet in production to avoid noise and leaking user queries/locations to logs.
- console.log('[MapQueryHandler] useEffect triggered. toolOutput:', JSON.stringify(toolOutput, null, 2)); + if (process.env.NODE_ENV !== 'production') { + console.log('[MapQueryHandler] useEffect triggered. toolOutput:', JSON.stringify(toolOutput, null, 2)); + } @@ - console.log('[MapQueryHandler] Calling setMapData with:', JSON.stringify(newMapData, null, 2)); + if (process.env.NODE_ENV !== 'production') { + console.log('[MapQueryHandler] Calling setMapData with:', JSON.stringify(newMapData, null, 2)); + } @@ - console.warn('[MapQueryHandler] Invalid latitude/longitude in toolOutput.mcp_response:', toolOutput.mcp_response.location); + if (process.env.NODE_ENV !== 'production') { + console.warn('[MapQueryHandler] Invalid latitude/longitude in toolOutput.mcp_response:', toolOutput.mcp_response.location); + } @@ - if (toolOutput) { - console.warn('[MapQueryHandler] toolOutput provided, but mcp_response or location data is missing.', toolOutput); - } else { - console.log('[MapQueryHandler] toolOutput is null or undefined.'); - } + if (process.env.NODE_ENV !== 'production') { + if (toolOutput) { + console.warn('[MapQueryHandler] toolOutput provided, but mcp_response or location data is missing.', toolOutput); + } else { + console.log('[MapQueryHandler] toolOutput is null or undefined.'); + } + }Also applies to: 47-47, 53-53, 61-65
components/map/mapbox-map.tsx (1)
221-229: Avoid double-resetting isUpdatingPositionRef; rely on finally for resetYou reset isUpdatingPositionRef both in the timeout and in finally, which is redundant. It also weakens the “no rotation during update” guard if reset happens before the 500ms delay.
- setTimeout(() => { - startRotation() - isUpdatingPositionRef.current = false - }, 500) + setTimeout(() => { + startRotation() + }, 500) } catch (error) { console.error('Error updating map position:', error) } finally { isUpdatingPositionRef.current = false }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
app/actions.tsx(1 hunks)components/map/map-query-handler.tsx(1 hunks)components/map/mapbox-map.tsx(2 hunks)lib/agents/tools/geospatial.tsx(7 hunks)
✅ Files skipped from review due to trivial changes (1)
- app/actions.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
lib/agents/tools/geospatial.tsx (3)
components/message.tsx (1)
BotMessage(11-29)mapbox_mcp/index.ts (1)
testMCPConnection(14-89)mapbox_mcp/hooks.ts (1)
query(91-156)
🔇 Additional comments (4)
lib/agents/tools/geospatial.tsx (1)
164-174: Good fail-fast path and user feedback when MCP is unavailableEarly return with a user-facing message, structured result, and logs is solid. This prevents downstream null dereferences and keeps UI responsive.
components/map/map-query-handler.tsx (1)
40-47: Correct ordering to [lng, lat] and mapFeature propagation looks goodSetting targetPosition as [longitude, latitude] matches Mapbox expectations and cleanly threads place_name/mapUrl. This aligns with the consumer in mapbox-map.tsx.
Also applies to: 48-51
components/map/mapbox-map.tsx (2)
221-229: Rotation resumes unconditionally after flyTo—confirm RealTimeMode expectationsThis change restarts rotation even in RealTimeMode after programmatic moves (e.g., geolocation updates), which may be undesirable if RealTimeMode is meant to keep a steady tracked view.
If RealTimeMode should never rotate, consider passing a “resumeRotation: boolean” to updateMapPosition based on mapType, or check mapType inside. Happy to sketch that change if needed.
508-520: Stopping rotation before applying mapData targetPosition is the right fixHalting rotation before flyTo and then resuming resolves the “preview not updating” issue due to interrupted animations.
User description
The Mapbox preview was not updating when a user searched for a location. This was because the
flyToanimation was being interrupted and not correctly restarting.This commit fixes the issue by:
flyToanimation.flyToanimation is complete.finallyblock to ensure theisUpdatingPositionRefis always reset.PR Type
Bug fix
Description
Fix Mapbox preview not updating on search
Stop existing rotation before flyTo animation
Ensure rotation restarts after animation completes
Add proper error handling with finally block
Diagram Walkthrough
File Walkthrough
mapbox-map.tsx
Fix map animation and rotation handlingcomponents/map/mapbox-map.tsx
Summary by CodeRabbit
Bug Fixes
New Features