feat: add StopsMap and WalkingDirections components for enhanced map functionality

- Implemented StopsMap component to display bus stops on a map using MapLibre GL.
- Integrated walking directions feature in WalkingDirections component to calculate routes from user location to selected bus stop.
- Added geo utility functions for coordinate validation and distance calculation.
- Created route grouping and stop filtering logic in routeGroups module.
- Developed custom hooks for managing stop routes with React Query.
- Added tests for routing and stop functionalities to ensure reliability.
This commit is contained in:
2026-10-08 00:18:10 +03:00
parent 1492f179eb
commit 6fe039cefa
43 changed files with 1518 additions and 59 deletions

View File

@@ -182,7 +182,8 @@ test('blocked native sharing and clipboard offer a selectable manual link', asyn
test('nearby and all stops share rows, selection, typography and scrollbar styles', async ({ page, context }, info) => {
await context.grantPermissions(['geolocation']); await context.setGeolocation({ latitude: 55.49, longitude: 28.783 });
await page.goto('/stops?demo=1&city=1&stop=101');
await page.goto('/?demo=1&city=1&stop=101');
await page.getByRole('button', { name: 'Выбрать остановку', exact: true }).click();
const all = page.locator('.stopsList[aria-label="Остановки"]');
await expect(all.locator('.stopItem')).toHaveCount(5);
const styles = (element: HTMLElement) => {
@@ -191,13 +192,13 @@ test('nearby and all stops share rows, selection, typography and scrollbar style
};
const normalStyles = await all.evaluate(styles);
await page.getByRole('button', { name: 'Рядом', exact: true }).click();
const nearby = page.getByLabel('Остановки рядом', { exact: true });
const nearby = page.locator('.stopsList[aria-label="Остановки рядом"]');
await expect(nearby.locator('.stopItem')).toHaveCount(3);
await expect(nearby.locator('.activeStop')).toHaveText('Площадь Свободы120 м');
expect(await nearby.evaluate(styles)).toEqual(normalStyles);
await nearby.getByRole('button', { name: /Больница/ }).click();
await expect(nearby.locator('.activeStop')).toContainText('Больница');
await page.getByRole('button', { name: 'Все остановки', exact: true }).click();
await expect(page.locator('#board-title')).toHaveText('Больница');
await page.getByRole('button', { name: 'Выбрать остановку', exact: true }).click();
await expect(all.locator('.activeStop')).toHaveText('Больница');
await page.locator('.stopsCard').screenshot({ path: `test-results/unified-stops-${info.project.name}.png`, animations: 'disabled' });
await page.locator('.appDialog').screenshot({ path: `test-results/unified-stops-${info.project.name}.png`, animations: 'disabled' });
});