Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions e2e/map.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,40 @@ test.describe('Map interactions with left context menu', () => {
);
expect(clipboardContent).toBe('13.393707,52.518310');
});

test('should show routing warning toast when API returns warnings', async ({
page,
}) => {
await setupNominatimMock(page);

const mockResponse = JSON.parse(JSON.stringify(customRouteResponse));
mockResponse.warnings = [{ code: 1, description: 'Test routing warning' }];

await setupRouteMock(page, mockResponse);

// Add "from" waypoint
await page
.getByRole('region', { name: 'Map' })
.click({ button: 'right', position: { x: 800, y: 100 }, force: true });

await page.getByRole('button', { name: 'Directions from here' }).click();

await expect(
page.getByLabel('Map marker 1').getByRole('img')
).toBeVisible();

// Add "to" waypoint
await page
.getByRole('region', { name: 'Map' })
.click({ button: 'right', position: { x: 800, y: 300 }, force: true });

await page.getByRole('button', { name: 'Directions to here' }).click();

await expect(page.getByText('Test routing warning')).toBeVisible();

// Reset page state so other tests are not affected
await page.reload();
});
});

test.describe('Map interactions with URL parameters', () => {
Expand Down
8 changes: 8 additions & 0 deletions src/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,14 +213,21 @@ export interface Address {
country_code: string;
}

export interface ValhallaWarning {
code: number;
description: string;
}

export interface ValhallaRouteResponse {
id: 'valhalla_directions';
trip: Trip;
alternates?: ValhallaRouteResponse[];
warnings?: ValhallaWarning[];
}

export interface ValhallaIsochroneResponse extends GeoJSON.FeatureCollection {
id: string;
warnings?: ValhallaWarning[];
}

export interface FetchGeocodeObject {
Expand All @@ -241,4 +248,5 @@ export interface OptimizedLocation {
export interface ValhallaOptimizedRouteResponse {
trip: Trip;
id?: string;
warnings?: ValhallaWarning[];
}
4 changes: 4 additions & 0 deletions src/hooks/use-directions-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { getDirectionsLanguage } from '@/utils/directions-language';
import { useCommonStore } from '@/stores/common-store';
import { useDirectionsStore, type Waypoint } from '@/stores/directions-store';
import { router } from '@/routes';
import { handleValhallaWarnings } from '@/utils/handle-valhalla-warnings';

const getActiveWaypoints = (waypoints: Waypoint[]): ActiveWaypoint[] =>
waypoints.flatMap((wp) => wp.geocodeResults.filter((r) => r.selected));
Expand Down Expand Up @@ -56,6 +57,9 @@ async function fetchDirections() {
}
);

// Display routing warnings if present
handleValhallaWarnings(data.warnings);

// Parse geometry for main route
(data as ParsedDirectionsGeometry).decodedGeometry =
parseDirectionsGeometry(data);
Expand Down
4 changes: 4 additions & 0 deletions src/hooks/use-isochrones-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { calcArea } from '@/utils/geom';
import { useCommonStore } from '@/stores/common-store';
import { useIsochronesStore } from '@/stores/isochrones-store';
import { router } from '@/routes';
import { handleValhallaWarnings } from '@/utils/handle-valhalla-warnings';

async function fetchIsochrones() {
const { geocodeResults, maxRange, interval, denoise, generalize } =
Expand Down Expand Up @@ -51,6 +52,9 @@ async function fetchIsochrones() {
}
);

// Display routing warnings if present
handleValhallaWarnings(data.warnings);

// Calculate area for each feature
data.features.forEach((feature) => {
if (feature.properties) {
Expand Down
4 changes: 4 additions & 0 deletions src/hooks/use-optimized-route-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { router } from '@/routes';
import type { ValhallaOptimizedRouteResponse } from '@/components/types';
import type { Waypoint } from '@/stores/directions-store';
import { getDirectionsLanguage } from '@/utils/directions-language';
import { handleValhallaWarnings } from '@/utils/handle-valhalla-warnings';

export function useOptimizedRouteQuery() {
const waypoints = useDirectionsStore((state) => state.waypoints);
Expand Down Expand Up @@ -55,6 +56,9 @@ export function useOptimizedRouteQuery() {
{ params: { json: JSON.stringify(request.json) } }
);

// Display routing warnings if present
handleValhallaWarnings(data.warnings);

const processedData = {
...data,
id: data.id ?? 'valhalla_optimized_route',
Expand Down
38 changes: 38 additions & 0 deletions src/utils/handle-valhalla-warnings.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { toast } from 'sonner';
import { handleValhallaWarnings } from './handle-valhalla-warnings';

vi.mock('sonner', () => ({
toast: {
warning: vi.fn(),
},
}));

describe('handleValhallaWarnings', () => {
beforeEach(() => {
vi.clearAllMocks();
});

it('should display toast for each warning', () => {
const warnings = [
{ code: 1, description: 'Warning one' },
{ code: 2, description: 'Warning two' },
];

handleValhallaWarnings(warnings);

expect(toast.warning).toHaveBeenCalledTimes(2);
});

it('should not display toast when warnings are empty', () => {
handleValhallaWarnings([]);

expect(toast.warning).not.toHaveBeenCalled();
});

it('should not display toast when warnings are undefined', () => {
handleValhallaWarnings(undefined);

expect(toast.warning).not.toHaveBeenCalled();
});
});
26 changes: 26 additions & 0 deletions src/utils/handle-valhalla-warnings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { toast } from 'sonner';
import type { ValhallaWarning } from '@/components/types';
import type { ExternalToast } from 'sonner';

/**
* Displays toast notifications for warnings returned by the Valhalla API
* @param warnings - Optional warnings array from Valhalla API response
* warning object structure: { code: number, description: string }
*/

const TOAST_CONFIG: ExternalToast = {
position: 'bottom-center',
duration: 5000,
closeButton: true,
};

export const handleValhallaWarnings = (warnings?: ValhallaWarning[]): void => {
if (!warnings?.length) return;

warnings?.forEach((warning) => {
toast.warning('Routing warning', {
description: warning.description,
...TOAST_CONFIG,
});
});
};
Loading