From a315caa3c7801d9457bac92994e7d9f6f1f66c31 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Mon, 30 Mar 2026 09:51:51 +0530 Subject: [PATCH 1/2] fix: auto-load route from URL parameters --- package-lock.json | 39 +++++- src/app.spec.tsx | 117 +++++++++++++++++- src/app.tsx | 100 +++++++++++++++ src/components/directions/directions.spec.tsx | 94 -------------- src/components/directions/directions.tsx | 36 +----- 5 files changed, 254 insertions(+), 132 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6f41675c..02f8ff2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -197,6 +197,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -616,6 +617,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -659,6 +661,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -680,6 +683,7 @@ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", "license": "MIT", + "peer": true, "dependencies": { "@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/utilities": "^3.2.2", @@ -4005,6 +4009,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.13.tgz", "integrity": "sha512-i6DY9wnghE0ghHJfDrnnFNatn4CNBzMZv4xPzKB7Lb9zMAoImAxPKoGK9gLOm79aopDa07p6ytlFFWotvwj3DQ==", "license": "MIT", + "peer": true, "dependencies": { "@tanstack/query-core": "5.90.13" }, @@ -4039,6 +4044,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.144.0.tgz", "integrity": "sha512-GmRyIGmHtGj3VLTHXepIwXAxTcHyL5W7Vw7O1CnVEtFxQQWKMVOnWgI7tPY6FhlNwMKVb3n0mPFWz9KMYyd2GA==", "license": "MIT", + "peer": true, "dependencies": { "@tanstack/history": "1.141.0", "@tanstack/react-store": "^0.8.0", @@ -4110,6 +4116,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.144.0.tgz", "integrity": "sha512-6oVERtK9XDHCP4XojgHsdHO56ZSj11YaWjF5g/zw39LhyA6Lx+/X86AEIHO4y0BUrMQaJfcjdAQMVSAs6Vjtdg==", "license": "MIT", + "peer": true, "dependencies": { "@tanstack/history": "1.141.0", "@tanstack/store": "^0.8.0", @@ -4189,6 +4196,7 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -6726,6 +6734,7 @@ "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -6734,8 +6743,7 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "devOptional": true, - "peer": true + "devOptional": true }, "node_modules/@types/react": { "version": "18.3.26", @@ -6755,6 +6763,7 @@ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -6831,6 +6840,7 @@ "integrity": "sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.50.1", "@typescript-eslint/types": "8.50.1", @@ -7576,6 +7586,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -8063,6 +8074,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001741", @@ -8459,7 +8471,8 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "devOptional": true + "devOptional": true, + "peer": true }, "node_modules/d3": { "version": "7.9.0", @@ -8802,6 +8815,7 @@ "resolved": "https://packages.atlassian.com/api/npm/npm-remote/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -9510,6 +9524,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -9570,6 +9585,7 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -9747,6 +9763,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -10848,6 +10865,7 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.3.tgz", "integrity": "sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -11539,6 +11557,7 @@ "integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@acemir/cssom": "^0.9.28", "@asamuzakjp/dom-selector": "^6.7.6", @@ -12185,6 +12204,7 @@ "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.15.0.tgz", "integrity": "sha512-pPeu/t4yPDX/+Uf9ibLUdmaKbNMlGxMAX+tBednYukol2qNk2TZXAlhdohWxjVvTO3is8crrUYv3Ok02oAaKzA==", "license": "BSD-3-Clause", + "peer": true, "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", @@ -12969,6 +12989,7 @@ "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -13105,6 +13126,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -13117,6 +13139,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -13499,6 +13522,7 @@ "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.4.2.tgz", "integrity": "sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" } @@ -13759,6 +13783,7 @@ "integrity": "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", @@ -13771,6 +13796,7 @@ "integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" } @@ -14293,6 +14319,7 @@ "resolved": "https://packages.atlassian.com/api/npm/npm-remote/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -14574,6 +14601,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14679,6 +14707,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "napi-postinstall": "^0.3.0" }, @@ -14805,6 +14834,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -14925,6 +14955,7 @@ "resolved": "https://packages.atlassian.com/api/npm/npm-remote/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -14978,6 +15009,7 @@ "integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "4.0.16", "@vitest/mocker": "4.0.16", @@ -15401,6 +15433,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/app.spec.tsx b/src/app.spec.tsx index 096f3d88..a98b954c 100644 --- a/src/app.spec.tsx +++ b/src/app.spec.tsx @@ -1,7 +1,35 @@ -import { describe, it, expect, vi } from 'vitest'; +import { beforeEach, describe, it, expect, vi } from 'vitest'; import { render, screen } from '@testing-library/react'; import { App } from './app'; +type MockSearch = { + wps?: string; +}; + +type MockWaypoint = { + id: string; + geocodeResults: Array<{ + selected?: boolean; + sourcelnglat?: [number, number]; + }>; + userInput: string; +}; + +const mockUseParams = vi.fn(() => ({ activeTab: 'directions' })); +const mockUseSearch = vi.fn<() => MockSearch>(() => ({ wps: undefined })); +const mockRefetchDirections = vi.fn().mockResolvedValue(undefined); +const mockReverseGeocode = vi.fn().mockResolvedValue([]); +let mockMapReady = true; +let mockWaypoints: MockWaypoint[] = [ + { id: '0', geocodeResults: [], userInput: '' }, + { id: '1', geocodeResults: [], userInput: '' }, +]; + +vi.mock('@tanstack/react-router', () => ({ + useParams: () => mockUseParams(), + useSearch: () => mockUseSearch(), +})); + vi.mock('react-map-gl/maplibre', () => ({ MapProvider: ({ children }: { children: React.ReactNode }) => (
{children}
@@ -32,7 +60,38 @@ vi.mock('@/components/ui/sonner', () => ({ ), })); +vi.mock('@/hooks/use-directions-queries', () => ({ + useDirectionsQuery: () => ({ + refetch: mockRefetchDirections, + }), + useReverseGeocodeDirections: () => ({ + reverseGeocode: mockReverseGeocode, + }), +})); + +vi.mock('@/stores/common-store', () => ({ + useCommonStore: (selector: (state: { mapReady: boolean }) => unknown) => + selector({ mapReady: mockMapReady }), +})); + +vi.mock('@/stores/directions-store', () => ({ + useDirectionsStore: ( + selector: (state: { waypoints: typeof mockWaypoints }) => unknown + ) => selector({ waypoints: mockWaypoints }), +})); + describe('App', () => { + beforeEach(() => { + vi.clearAllMocks(); + mockUseParams.mockReturnValue({ activeTab: 'directions' }); + mockUseSearch.mockReturnValue({ wps: undefined }); + mockMapReady = true; + mockWaypoints = [ + { id: '0', geocodeResults: [], userInput: '' }, + { id: '1', geocodeResults: [], userInput: '' }, + ]; + }); + it('should render without crashing', () => { expect(() => render()).not.toThrow(); }); @@ -73,4 +132,60 @@ describe('App', () => { expect(mapProvider).toContainElement(screen.getByTestId('settings-panel')); expect(mapProvider).toContainElement(screen.getByTestId('toaster')); }); + + it('should hydrate waypoints from URL search params on initial load', () => { + mockUseSearch.mockReturnValue({ + wps: '13.343067169189455,52.5296422146409,13.33414077758789,52.50901237642168', + }); + + render(); + + expect(mockReverseGeocode).toHaveBeenCalledTimes(2); + expect(mockReverseGeocode).toHaveBeenNthCalledWith( + 1, + 13.343067169189455, + 52.5296422146409, + 0, + { isPermalink: true } + ); + expect(mockReverseGeocode).toHaveBeenNthCalledWith( + 2, + 13.33414077758789, + 52.50901237642168, + 1, + { isPermalink: true } + ); + }); + + it('should auto-render directions when URL waypoints already exist in state', () => { + mockUseSearch.mockReturnValue({ + wps: '13.343067169189455,52.5296422146409,13.33414077758789,52.50901237642168', + }); + mockWaypoints = [ + { + id: '0', + geocodeResults: [ + { + selected: true, + sourcelnglat: [13.343067169189455, 52.5296422146409], + }, + ], + userInput: 'Waypoint 1', + }, + { + id: '1', + geocodeResults: [ + { + selected: true, + sourcelnglat: [13.33414077758789, 52.50901237642168], + }, + ], + userInput: 'Waypoint 2', + }, + ]; + + render(); + + expect(mockRefetchDirections).toHaveBeenCalledTimes(1); + }); }); diff --git a/src/app.tsx b/src/app.tsx index 9fd9be84..cf96918a 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,10 +1,110 @@ +import { useEffect, useMemo, useRef } from 'react'; +import { useParams, useSearch } from '@tanstack/react-router'; import { MapProvider } from 'react-map-gl/maplibre'; import { MapComponent } from './components/map'; import { RoutePlanner } from './components/route-planner'; import { SettingsPanel } from './components/settings-panel/settings-panel'; import { Toaster } from '@/components/ui/sonner'; +import { + useDirectionsQuery, + useReverseGeocodeDirections, +} from '@/hooks/use-directions-queries'; +import { useCommonStore } from '@/stores/common-store'; +import { useDirectionsStore } from '@/stores/directions-store'; +import { isValidCoordinates } from '@/utils/geom'; export const App = () => { + const { activeTab } = useParams({ from: '/$activeTab' }); + const { wps } = useSearch({ from: '/$activeTab' }); + const { refetch: refetchDirections } = useDirectionsQuery(); + const { reverseGeocode } = useReverseGeocodeDirections(); + const mapReady = useCommonStore((state) => state.mapReady); + const waypoints = useDirectionsStore((state) => state.waypoints); + const initialWpsRef = useRef(wps); + const urlWaypointsLoadedRef = useRef(false); + const urlRouteRenderedRef = useRef(false); + + const activeWaypointCount = useMemo( + () => + waypoints.filter((wp) => + wp.geocodeResults.some((result) => result.selected) + ).length, + [waypoints] + ); + + useEffect(() => { + const initialWps = initialWpsRef.current; + + if ( + activeTab !== 'directions' || + !initialWps || + urlWaypointsLoadedRef.current + ) { + return; + } + + urlWaypointsLoadedRef.current = true; + console.info('[App] Hydrating directions from URL search params', { + wps: initialWps, + }); + + const coordinates = initialWps.split(',').map(Number); + let hasValidWaypoint = false; + + for (let i = 0; i < coordinates.length; i += 2) { + const lng = coordinates[i]; + const lat = coordinates[i + 1]; + + if ( + lng === undefined || + lat === undefined || + Number.isNaN(lng) || + Number.isNaN(lat) || + !isValidCoordinates(lat, lng) + ) { + continue; + } + + hasValidWaypoint = true; + + void reverseGeocode(lng, lat, i / 2, { isPermalink: true }).catch( + (error) => { + console.error('[App] Failed to hydrate waypoint from URL', error); + } + ); + } + + if (!hasValidWaypoint) { + console.debug( + '[App] No valid route coordinates found in URL search params' + ); + } + }, [activeTab, reverseGeocode]); + + useEffect(() => { + const initialWps = initialWpsRef.current; + + if ( + activeTab !== 'directions' || + !initialWps || + !mapReady || + urlRouteRenderedRef.current || + activeWaypointCount < 2 + ) { + return; + } + + urlRouteRenderedRef.current = true; + console.info('[App] Auto-rendering route from URL search params', { + activeWaypointCount, + }); + + void refetchDirections().catch((error) => { + console.error('[App] Failed to auto-render route from URL', error); + urlRouteRenderedRef.current = false; + }); + }, [activeTab, activeWaypointCount, mapReady, refetchDirections]); + return ( diff --git a/src/components/directions/directions.spec.tsx b/src/components/directions/directions.spec.tsx index b888329c..2dbeb410 100644 --- a/src/components/directions/directions.spec.tsx +++ b/src/components/directions/directions.spec.tsx @@ -5,7 +5,6 @@ import { DirectionsControl } from './directions'; const mockNavigate = vi.fn(); const mockRefetchDirections = vi.fn(); -const mockReverseGeocode = vi.fn().mockResolvedValue([]); const mockAddEmptyWaypointToEnd = vi.fn(); const mockClearWaypoints = vi.fn(); const mockClearRoutes = vi.fn(); @@ -15,10 +14,6 @@ vi.mock('@tanstack/react-router', () => ({ useNavigate: vi.fn(() => mockNavigate), })); -vi.mock('@/utils/parse-url-params', () => ({ - parseUrlParams: vi.fn(() => ({})), -})); - const mockWaypoints = [ { id: '0', geocodeResults: [], userInput: '' }, { id: '1', geocodeResults: [], userInput: '' }, @@ -63,9 +58,6 @@ vi.mock('@/hooks/use-directions-queries', () => ({ useDirectionsQuery: vi.fn(() => ({ refetch: mockRefetchDirections, })), - useReverseGeocodeDirections: vi.fn(() => ({ - reverseGeocode: mockReverseGeocode, - })), })); vi.mock('@/hooks/use-optimized-route-query', () => ({ @@ -292,89 +284,3 @@ describe('DirectionsControl', () => { expect(result.wps).toBe('13.4,52.5,10,48'); }); }); - -describe('DirectionsControl URL parsing', () => { - beforeEach(() => { - vi.clearAllMocks(); - mockResults.data = null; - mockWaypoints.length = 0; - mockWaypoints.push( - { id: '0', geocodeResults: [], userInput: '' }, - { id: '1', geocodeResults: [], userInput: '' } - ); - }); - - it('should process URL params with valid coordinates (Berlin)', async () => { - const parseUrlParams = await import('@/utils/parse-url-params'); - vi.mocked(parseUrlParams.parseUrlParams).mockReturnValue({ - wps: '13.365016850476763,52.483706198952575,13.422421655040836,52.49336042169804', - }); - - render(); - - expect(mockReverseGeocode).toHaveBeenCalledTimes(2); - expect(mockReverseGeocode).toHaveBeenCalledWith( - 13.365016850476763, - 52.483706198952575, - 0, - { isPermalink: true } - ); - expect(mockReverseGeocode).toHaveBeenCalledWith( - 13.422421655040836, - 52.49336042169804, - 1, - { isPermalink: true } - ); - }); - - it('should process URL params with valid coordinates where lng > 90 (Singapore)', async () => { - const parseUrlParams = await import('@/utils/parse-url-params'); - vi.mocked(parseUrlParams.parseUrlParams).mockReturnValue({ - wps: '103.66492937866911,1.4827280571964963,103.66421854954496,1.4840285187178779', - }); - - render(); - - expect(mockReverseGeocode).toHaveBeenCalledTimes(2); - expect(mockReverseGeocode).toHaveBeenCalledWith( - 103.66492937866911, - 1.4827280571964963, - 0, - { isPermalink: true } - ); - expect(mockReverseGeocode).toHaveBeenCalledWith( - 103.66421854954496, - 1.4840285187178779, - 1, - { isPermalink: true } - ); - }); - - it('should skip truly invalid coordinates from URL', async () => { - const parseUrlParams = await import('@/utils/parse-url-params'); - vi.mocked(parseUrlParams.parseUrlParams).mockReturnValue({ - wps: '999,999', - }); - - render(); - - expect(mockReverseGeocode).not.toHaveBeenCalled(); - }); - - it('should handle coordinates near edge of valid range', async () => { - const parseUrlParams = await import('@/utils/parse-url-params'); - vi.mocked(parseUrlParams.parseUrlParams).mockReturnValue({ - wps: '179.9,89,-179.9,-89', - }); - - render(); - - expect(mockReverseGeocode).toHaveBeenCalledTimes(2); - expect(mockReverseGeocode).toHaveBeenCalledWith(179.9, 89, 0, { - isPermalink: true, - }); - expect(mockReverseGeocode).toHaveBeenCalledWith(-179.9, -89, 1, { - isPermalink: true, - }); - }); -}); diff --git a/src/components/directions/directions.tsx b/src/components/directions/directions.tsx index 3147dd54..d5344c12 100644 --- a/src/components/directions/directions.tsx +++ b/src/components/directions/directions.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef } from 'react'; +import { useCallback, useEffect } from 'react'; import { Waypoints } from './waypoints/waypoint-list'; @@ -11,14 +11,9 @@ import type { ParsedDirectionsGeometry } from '@/components/types'; import { Button } from '@/components/ui/button'; import { MapPinPlus, MapPinXInside } from 'lucide-react'; import { RouteCard } from './route-card'; -import { parseUrlParams } from '@/utils/parse-url-params'; -import { isValidCoordinates } from '@/utils/geom'; import { useNavigate } from '@tanstack/react-router'; import { useDirectionsStore } from '@/stores/directions-store'; -import { - useDirectionsQuery, - useReverseGeocodeDirections, -} from '@/hooks/use-directions-queries'; +import { useDirectionsQuery } from '@/hooks/use-directions-queries'; import { useOptimizedRouteQuery } from '@/hooks/use-optimized-route-query'; import { Sparkles } from 'lucide-react'; import { @@ -35,13 +30,10 @@ export const DirectionsControl = () => { ); const clearWaypoints = useDirectionsStore((state) => state.clearWaypoints); const clearRoutes = useDirectionsStore((state) => state.clearRoutes); - const initialUrlParams = useRef(parseUrlParams()); - const urlParamsProcessed = useRef(false); const navigate = useNavigate({ from: '/$activeTab' }); const updateDateTime = useCommonStore((state) => state.updateDateTime); const dateTime = useCommonStore((state) => state.dateTime); const { refetch: refetchDirections } = useDirectionsQuery(); - const { reverseGeocode } = useReverseGeocodeDirections(); const { optimizeRoute, isPending: isOptimizing } = useOptimizedRouteQuery(); const isOptimized = useDirectionsStore((state) => state.isOptimized); const activeRouteIndex = useDirectionsStore( @@ -51,30 +43,6 @@ export const DirectionsControl = () => { (state) => state.setActiveRouteIndex ); - useEffect(() => { - if (urlParamsProcessed.current) return; - - const wpsParam = initialUrlParams.current.wps; - - if (wpsParam) { - const coordinates = wpsParam.split(',').map(Number); - - for (let i = 0; i < coordinates.length; i += 2) { - const lng = coordinates[i]!; - const lat = coordinates[i + 1]!; - - if (!isValidCoordinates(lat, lng) || isNaN(lng) || isNaN(lat)) continue; - - const index = i / 2; - reverseGeocode(lng, lat, index, { isPermalink: true }); - } - refetchDirections(); - } - - urlParamsProcessed.current = true; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - useEffect(() => { const wps: number[] = []; From 7c24ccd06e49dc7ea459999c27edc483c2c7c3f9 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Fri, 3 Apr 2026 00:13:51 +0530 Subject: [PATCH 2/2] chore: remove unintended lockfile changes --- package-lock.json | 39 +++------------------------------------ 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/package-lock.json b/package-lock.json index 02f8ff2b..6f41675c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -197,7 +197,6 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -617,7 +616,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -661,7 +659,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -683,7 +680,6 @@ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", "license": "MIT", - "peer": true, "dependencies": { "@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/utilities": "^3.2.2", @@ -4009,7 +4005,6 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.13.tgz", "integrity": "sha512-i6DY9wnghE0ghHJfDrnnFNatn4CNBzMZv4xPzKB7Lb9zMAoImAxPKoGK9gLOm79aopDa07p6ytlFFWotvwj3DQ==", "license": "MIT", - "peer": true, "dependencies": { "@tanstack/query-core": "5.90.13" }, @@ -4044,7 +4039,6 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.144.0.tgz", "integrity": "sha512-GmRyIGmHtGj3VLTHXepIwXAxTcHyL5W7Vw7O1CnVEtFxQQWKMVOnWgI7tPY6FhlNwMKVb3n0mPFWz9KMYyd2GA==", "license": "MIT", - "peer": true, "dependencies": { "@tanstack/history": "1.141.0", "@tanstack/react-store": "^0.8.0", @@ -4116,7 +4110,6 @@ "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.144.0.tgz", "integrity": "sha512-6oVERtK9XDHCP4XojgHsdHO56ZSj11YaWjF5g/zw39LhyA6Lx+/X86AEIHO4y0BUrMQaJfcjdAQMVSAs6Vjtdg==", "license": "MIT", - "peer": true, "dependencies": { "@tanstack/history": "1.141.0", "@tanstack/store": "^0.8.0", @@ -4196,7 +4189,6 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -6734,7 +6726,6 @@ "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -6743,7 +6734,8 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "devOptional": true + "devOptional": true, + "peer": true }, "node_modules/@types/react": { "version": "18.3.26", @@ -6763,7 +6755,6 @@ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -6840,7 +6831,6 @@ "integrity": "sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.50.1", "@typescript-eslint/types": "8.50.1", @@ -7586,7 +7576,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -8074,7 +8063,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001741", @@ -8471,8 +8459,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "devOptional": true, - "peer": true + "devOptional": true }, "node_modules/d3": { "version": "7.9.0", @@ -8815,7 +8802,6 @@ "resolved": "https://packages.atlassian.com/api/npm/npm-remote/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -9524,7 +9510,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -9585,7 +9570,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -9763,7 +9747,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -10865,7 +10848,6 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.3.tgz", "integrity": "sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -11557,7 +11539,6 @@ "integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@acemir/cssom": "^0.9.28", "@asamuzakjp/dom-selector": "^6.7.6", @@ -12204,7 +12185,6 @@ "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.15.0.tgz", "integrity": "sha512-pPeu/t4yPDX/+Uf9ibLUdmaKbNMlGxMAX+tBednYukol2qNk2TZXAlhdohWxjVvTO3is8crrUYv3Ok02oAaKzA==", "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", @@ -12989,7 +12969,6 @@ "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -13126,7 +13105,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -13139,7 +13117,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -13522,7 +13499,6 @@ "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.4.2.tgz", "integrity": "sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" } @@ -13783,7 +13759,6 @@ "integrity": "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", @@ -13796,7 +13771,6 @@ "integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" } @@ -14319,7 +14293,6 @@ "resolved": "https://packages.atlassian.com/api/npm/npm-remote/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -14601,7 +14574,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14707,7 +14679,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "napi-postinstall": "^0.3.0" }, @@ -14834,7 +14805,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -14955,7 +14925,6 @@ "resolved": "https://packages.atlassian.com/api/npm/npm-remote/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -15009,7 +14978,6 @@ "integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/expect": "4.0.16", "@vitest/mocker": "4.0.16", @@ -15433,7 +15401,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" }