Skip to content

Commit 1954576

Browse files
authored
Convert popup buttons to labels and remove locate points (#359)
1 parent a6a6975 commit 1954576

File tree

5 files changed

+43
-151
lines changed

5 files changed

+43
-151
lines changed

e2e/map.spec.ts

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { test, expect } from '@playwright/test';
22
import {
33
BERLIN_COORDINATES,
44
setupHeightMock,
5-
setupLocateMock,
65
setupNominatimMock,
76
setupRouteMock,
87
setupSearchMock,
@@ -481,6 +480,9 @@ test.describe('Map interactions with left context menu', () => {
481480
button: 'left',
482481
});
483482

483+
// Wait for popup to appear (has 200ms delay)
484+
await expect(page.getByTestId('map-info-popup')).toBeVisible();
485+
484486
await expect(page.getByTestId('dd-button')).toContainText(
485487
'13.393707, 52.518310'
486488
);
@@ -496,14 +498,9 @@ test.describe('Map interactions with left context menu', () => {
496498
);
497499
await expect(page.getByTestId('dms-copy-button')).toBeVisible();
498500

499-
await expect(
500-
page.getByRole('button', { name: 'Locate Point' })
501-
).toBeVisible();
502-
await expect(page.getByTestId('locate-point-copy-button')).toBeVisible();
503-
504-
await expect(
505-
page.getByRole('button', { name: 'Valhalla Location JSON' })
506-
).toBeVisible();
501+
await expect(page.getByTestId('location-json-button')).toContainText(
502+
'Valhalla Location JSON'
503+
);
507504
await expect(page.getByTestId('location-json-copy-button')).toBeVisible();
508505

509506
await expect(page.getByTestId('elevation-button')).toContainText('34 m');
@@ -516,35 +513,10 @@ test.describe('Map interactions with left context menu', () => {
516513
button: 'left',
517514
});
518515

519-
await expect(page.getByTestId('elevation-button')).toContainText('34 m');
520-
});
521-
522-
test('should call locate', async ({ page }) => {
523-
await setupHeightMock(page);
524-
const locateRequests = await setupLocateMock(page);
516+
// Wait for popup to appear (has 200ms delay)
517+
await expect(page.getByTestId('map-info-popup')).toBeVisible();
525518

526-
await page.getByRole('region', { name: 'Map' }).click({
527-
button: 'left',
528-
});
529-
530-
await expect(
531-
page.getByRole('button', { name: 'Locate Point' })
532-
).toBeVisible();
533-
534-
await page.getByRole('button', { name: 'Locate Point' }).click();
535-
536-
expect(locateRequests.length).toBeGreaterThan(0);
537-
538-
const locateRequest = locateRequests[0] as RouteApiRequest;
539-
expect(locateRequest.method).toBe('POST');
540-
expect(locateRequest.url).toMatch(
541-
/https:\/\/valhalla1\.openstreetmap\.de\/locate/
542-
);
543-
expect(locateRequest.body).toBeDefined();
544-
expect(locateRequest.body?.costing).toBe('bicycle');
545-
expect(locateRequest.body?.locations).toStrictEqual([
546-
{ lat: 52.51830999999976, lon: 13.393706999999239 },
547-
]);
519+
await expect(page.getByTestId('elevation-button')).toContainText('34 m');
548520
});
549521

550522
test('should copy text to clipboard', async ({ page }) => {
@@ -554,6 +526,9 @@ test.describe('Map interactions with left context menu', () => {
554526
button: 'left',
555527
});
556528

529+
// Wait for popup to appear (has 200ms delay)
530+
await expect(page.getByTestId('map-info-popup')).toBeVisible();
531+
557532
await page.getByTestId('dd-copy-button').click();
558533

559534
const clipboardContent = await page.evaluate(() =>

src/components/map/index.tsx

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@ import 'maplibre-gl/dist/maplibre-gl.css';
1616

1717
import axios from 'axios';
1818
import { throttle } from 'throttle-debounce';
19-
import {
20-
getValhallaUrl,
21-
buildHeightRequest,
22-
buildLocateRequest,
23-
} from '@/utils/valhalla';
19+
import { getValhallaUrl, buildHeightRequest } from '@/utils/valhalla';
2420
import { buildHeightgraphData } from '@/utils/heightgraph';
2521
import HeightGraph from '@/components/heightgraph';
2622
import { DrawControl } from './draw-control';
@@ -89,12 +85,10 @@ export const MapComponent = () => {
8985
);
9086
const updateSettings = useCommonStore((state) => state.updateSettings);
9187
const setMapReady = useCommonStore((state) => state.setMapReady);
92-
const { profile, style } = useSearch({ from: '/$activeTab' });
88+
const { style } = useSearch({ from: '/$activeTab' });
9389
const [showInfoPopup, setShowInfoPopup] = useState(false);
9490
const [showContextPopup, setShowContextPopup] = useState(false);
95-
const [isLocateLoading, setIsLocateLoading] = useState(false);
9691
const [isHeightLoading, setIsHeightLoading] = useState(false);
97-
const [locate, setLocate] = useState([]);
9892
const [popupLngLat, setPopupLngLat] = useState<{
9993
lng: number;
10094
lat: number;
@@ -292,32 +286,6 @@ export const MapComponent = () => {
292286
});
293287
}, []);
294288

295-
const getLocate = useCallback(
296-
(lng: number, lat: number) => {
297-
setIsLocateLoading(true);
298-
axios
299-
.post(
300-
getValhallaUrl() + '/locate',
301-
buildLocateRequest({ lng, lat }, profile || 'bicycle'),
302-
{
303-
headers: {
304-
'Content-Type': 'application/json',
305-
},
306-
}
307-
)
308-
.then(({ data }) => {
309-
setLocate(data);
310-
})
311-
.catch(({ response }) => {
312-
console.log(response);
313-
})
314-
.finally(() => {
315-
setIsLocateLoading(false);
316-
});
317-
},
318-
[profile]
319-
);
320-
321289
const handleAddWaypoint = useCallback(
322290
(index: number) => {
323291
if (!popupLngLat) return;
@@ -876,12 +844,8 @@ export const MapComponent = () => {
876844
popupLngLat={popupLngLat}
877845
elevation={elevation}
878846
isHeightLoading={isHeightLoading}
879-
isLocateLoading={isLocateLoading}
880-
locate={locate}
881-
onLocate={getLocate}
882847
onClose={() => {
883848
setShowInfoPopup(false);
884-
setLocate([]);
885849
}}
886850
/>
887851
</Popup>

src/components/map/parts/map-info-popup.spec.tsx

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ const defaultProps = {
1111
popupLngLat: { lng: 10.123456, lat: 50.654321 },
1212
elevation: '250 m',
1313
isHeightLoading: false,
14-
isLocateLoading: false,
15-
locate: [],
16-
onLocate: vi.fn(),
1714
onClose: vi.fn(),
1815
};
1916

@@ -68,40 +65,14 @@ describe('MapInfoPopup', () => {
6865
expect(screen.getByTestId('elevation-button')).toHaveTextContent('500 m');
6966
});
7067

71-
it('should display Locate Point button', () => {
72-
render(<MapInfoPopup {...defaultProps} />);
73-
74-
expect(screen.getByTestId('locate-point-button')).toHaveTextContent(
75-
'Locate Point'
76-
);
77-
});
78-
79-
it('should display Valhalla Location JSON button', () => {
68+
it('should display Valhalla Location JSON label', () => {
8069
render(<MapInfoPopup {...defaultProps} />);
8170

8271
expect(screen.getByTestId('location-json-button')).toHaveTextContent(
8372
'Valhalla Location JSON'
8473
);
8574
});
8675

87-
it('should call onLocate when Locate Point is clicked', async () => {
88-
const user = userEvent.setup();
89-
const onLocate = vi.fn();
90-
const popupLngLat = { lng: 10.5, lat: 50.5 };
91-
92-
render(
93-
<MapInfoPopup
94-
{...defaultProps}
95-
onLocate={onLocate}
96-
popupLngLat={popupLngLat}
97-
/>
98-
);
99-
100-
await user.click(screen.getByTestId('locate-point-button'));
101-
102-
expect(onLocate).toHaveBeenCalledWith(10.5, 50.5);
103-
});
104-
10576
it('should format coordinates to 6 decimal places', () => {
10677
render(
10778
<MapInfoPopup
@@ -115,12 +86,20 @@ describe('MapInfoPopup', () => {
11586
);
11687
});
11788

118-
it('should have copy buttons for coordinate rows', () => {
89+
it('should have copy buttons for coordinate rows with copyable values', () => {
11990
render(<MapInfoPopup {...defaultProps} />);
12091

12192
expect(screen.getByTestId('dd-copy-button')).toBeInTheDocument();
12293
expect(screen.getByTestId('latlng-copy-button')).toBeInTheDocument();
12394
expect(screen.getByTestId('dms-copy-button')).toBeInTheDocument();
12495
expect(screen.getByTestId('location-json-copy-button')).toBeInTheDocument();
12596
});
97+
98+
it('should not have copy button for elevation (non-copyable value)', () => {
99+
render(<MapInfoPopup {...defaultProps} />);
100+
101+
expect(
102+
screen.queryByTestId('elevation-copy-button')
103+
).not.toBeInTheDocument();
104+
});
126105
});

src/components/map/parts/map-info-popup.tsx

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,19 @@
11
import { Button } from '@/components/ui/button';
22
import { CoordinateRow } from '@/components/ui/coordinate-row';
3-
import {
4-
X,
5-
Locate,
6-
Globe,
7-
Compass,
8-
Cog,
9-
MapPin,
10-
ArrowUpDown,
11-
} from 'lucide-react';
3+
import { X, Locate, Globe, Compass, MapPin, ArrowUpDown } from 'lucide-react';
124
import { convertDDToDMS } from '../utils';
135

146
interface MapInfoPopupProps {
157
popupLngLat: { lng: number; lat: number };
168
elevation: string;
179
isHeightLoading: boolean;
18-
isLocateLoading: boolean;
19-
locate: unknown[];
20-
onLocate: (lng: number, lat: number) => void;
2110
onClose: () => void;
2211
}
2312

2413
export function MapInfoPopup({
2514
popupLngLat,
2615
elevation,
2716
isHeightLoading,
28-
isLocateLoading,
29-
locate,
30-
onLocate,
3117
onClose,
3218
}: MapInfoPopupProps) {
3319
const lngLatStr = `${popupLngLat.lng.toFixed(6)}, ${popupLngLat.lat.toFixed(6)}`;
@@ -43,12 +29,13 @@ export function MapInfoPopup({
4329
);
4430

4531
return (
46-
<div className="flex flex-col gap-2 p-2">
32+
<div className="flex flex-col gap-2 px-4 py-6" data-testid="map-info-popup">
4733
<Button
4834
variant="ghost"
4935
size="icon-xs"
5036
onClick={onClose}
5137
className="absolute right-1 top-1"
38+
aria-label="Close"
5239
>
5340
<X className="size-4" />
5441
</Button>
@@ -78,18 +65,7 @@ export function MapInfoPopup({
7865
/>
7966

8067
<CoordinateRow
81-
label="Calls Valhalla's Locate API"
82-
value="Locate Point"
83-
copyText={JSON.stringify(locate)}
84-
icon={<Cog className="size-3.5" />}
85-
onClick={() => onLocate(popupLngLat.lng, popupLngLat.lat)}
86-
isLoading={isLocateLoading}
87-
copyDisabled={locate.length === 0}
88-
testId="locate-point"
89-
/>
90-
91-
<CoordinateRow
92-
label="Copies a Valhalla location object to clipboard for API requests"
68+
label="Valhalla location object for API requests"
9369
value="Valhalla Location JSON"
9470
copyText={valhallaJson}
9571
icon={<MapPin className="size-3.5" />}

src/components/ui/coordinate-row.tsx

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
11
import { type ReactNode } from 'react';
22
import { Loader2 } from 'lucide-react';
3-
import { Button } from '@/components/ui/button';
4-
import { ButtonGroup } from '@/components/ui/button-group';
53
import { CopyButton } from '@/components/ui/copy-button';
64
import {
75
Tooltip,
86
TooltipContent,
97
TooltipTrigger,
108
} from '@/components/ui/tooltip';
9+
import { cn } from '@/lib/utils';
1110

1211
interface CoordinateRowProps {
13-
/** Tooltip content describing the button */
12+
/** Tooltip content describing the label */
1413
label: string;
15-
/** Display value/label shown in the button */
14+
/** Display value/label shown */
1615
value: string;
1716
/** Text to copy to clipboard. If omitted, no copy button is shown */
1817
copyText?: string;
1918
/** Optional icon to show before the value */
2019
icon?: ReactNode;
21-
/** Click handler for the main button */
22-
onClick?: () => void;
23-
/** Shows loading spinner and disables button */
20+
/** Shows loading spinner */
2421
isLoading?: boolean;
2522
/** Disables the copy button */
2623
copyDisabled?: boolean;
@@ -33,37 +30,38 @@ function CoordinateRow({
3330
value,
3431
copyText,
3532
icon,
36-
onClick,
3733
isLoading,
3834
copyDisabled,
3935
testId,
4036
}: CoordinateRowProps) {
4137
return (
42-
<ButtonGroup>
38+
<div
39+
className={cn(
40+
'flex items-center border rounded-lg gap-1.5',
41+
copyText ? 'justify-between' : 'self-start'
42+
)}
43+
>
4344
<Tooltip>
4445
<TooltipTrigger asChild>
45-
<Button
46-
variant="outline"
47-
size="sm"
48-
onClick={onClick}
49-
disabled={isLoading}
50-
className="gap-1.5"
46+
<div
47+
className="flex items-center gap-1.5 px-2 py-1"
5148
data-testid={testId ? `${testId}-button` : undefined}
5249
>
5350
{isLoading ? <Loader2 className="size-3.5 animate-spin" /> : icon}
5451
{value}
55-
</Button>
52+
</div>
5653
</TooltipTrigger>
5754
<TooltipContent side="top">{label}</TooltipContent>
5855
</Tooltip>
5956
{copyText && (
6057
<CopyButton
58+
variant="ghost"
6159
value={copyText}
6260
disabled={copyDisabled}
6361
data-testid={testId ? `${testId}-copy-button` : undefined}
6462
/>
6563
)}
66-
</ButtonGroup>
64+
</div>
6765
);
6866
}
6967

0 commit comments

Comments
 (0)