Compare commits
2 Commits
4525b0b8c3
...
c94140545c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c94140545c | ||
|
|
bb5b331b06 |
BIN
public/map/oriyo-inactive-marker.png
Normal file
BIN
public/map/oriyo-inactive-marker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@ -8,7 +8,7 @@ import {
|
||||
List,
|
||||
MapPin,
|
||||
} from 'lucide-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { Stations } from '@/app/api-utlities/@types';
|
||||
|
||||
@ -46,7 +46,6 @@ interface FilterPanelProps {
|
||||
setActiveFilterTab: (tab: string) => void;
|
||||
resetFilters: () => void;
|
||||
resetCities: () => void;
|
||||
t: (key: string) => string;
|
||||
}
|
||||
|
||||
// Пропсы для панели списка станций
|
||||
@ -58,7 +57,6 @@ interface StationListPanelProps {
|
||||
activeFilters: string[];
|
||||
activeCities: string[];
|
||||
setSelectedStation: (id: number | null) => void;
|
||||
t: (key: string) => string;
|
||||
filterToFieldMap: { [key: string]: keyof Stations[number] };
|
||||
allFilters: string[];
|
||||
resetFilters: () => void;
|
||||
@ -80,8 +78,9 @@ function FilterPanel({
|
||||
setActiveFilterTab,
|
||||
resetFilters,
|
||||
resetCities,
|
||||
t,
|
||||
}: FilterPanelProps) {
|
||||
const { t } = useTextController();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`absolute top-0 bottom-0 left-0 z-20 transform bg-white shadow-lg transition-transform duration-300 ${
|
||||
@ -207,12 +206,38 @@ function StationListPanel({
|
||||
activeFilters,
|
||||
activeCities,
|
||||
setSelectedStation,
|
||||
t,
|
||||
filterToFieldMap,
|
||||
allFilters,
|
||||
resetCities,
|
||||
resetFilters,
|
||||
}: StationListPanelProps) {
|
||||
const { t } = useTextController();
|
||||
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedStation || !scrollContainerRef.current) return;
|
||||
|
||||
const selectedStationItem = document.getElementById(
|
||||
`station_${selectedStation}`,
|
||||
);
|
||||
|
||||
if (selectedStationItem) {
|
||||
const container = scrollContainerRef.current;
|
||||
const itemRect = selectedStationItem.getBoundingClientRect();
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
|
||||
// Calculate the item's position relative to the container
|
||||
const itemTopRelativeToContainer =
|
||||
itemRect.top - containerRect.top + container.scrollTop - 10;
|
||||
|
||||
// Scroll the container to bring the item into view
|
||||
container.scrollTo({
|
||||
top: itemTopRelativeToContainer,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
}, [selectedStation]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`absolute top-0 right-0 bottom-0 z-20 transform bg-white shadow-lg transition-transform duration-300 ${
|
||||
@ -229,7 +254,11 @@ function StationListPanel({
|
||||
<Badge>{stations.length}</Badge>
|
||||
</div>
|
||||
</div>
|
||||
<div className='overflow-y-auto' style={{ height: 'calc(100% - 60px)' }}>
|
||||
<div
|
||||
className='overflow-y-auto'
|
||||
style={{ height: 'calc(100% - 60px)' }}
|
||||
ref={scrollContainerRef}
|
||||
>
|
||||
{stations.length > 0 ? (
|
||||
<div className='p-2'>
|
||||
{stations.map((station) => {
|
||||
@ -240,6 +269,7 @@ function StationListPanel({
|
||||
return (
|
||||
<div
|
||||
key={station.id}
|
||||
id={`station_${station.id}`}
|
||||
className={`mb-2 cursor-pointer rounded-lg border p-3 transition-colors ${
|
||||
selectedStation === station.id
|
||||
? 'border-blue-500 bg-blue-50'
|
||||
@ -454,7 +484,6 @@ export default function GasStationMap({ stations }: GasStationMapProps) {
|
||||
setActiveFilterTab={setActiveFilterTab}
|
||||
resetFilters={resetFilters}
|
||||
resetCities={resetCities}
|
||||
t={t}
|
||||
/>
|
||||
|
||||
{/* Station list panel */}
|
||||
@ -466,7 +495,6 @@ export default function GasStationMap({ stations }: GasStationMapProps) {
|
||||
activeFilters={activeFilters}
|
||||
activeCities={activeCities}
|
||||
setSelectedStation={setSelectedStation}
|
||||
t={t}
|
||||
filterToFieldMap={filterToFieldMap}
|
||||
allFilters={allFilters}
|
||||
resetFilters={resetFilters}
|
||||
@ -475,7 +503,11 @@ export default function GasStationMap({ stations }: GasStationMapProps) {
|
||||
|
||||
{/* Map */}
|
||||
<div className='h-full w-full'>
|
||||
<YandexMap points={points} />
|
||||
<YandexMap
|
||||
points={points}
|
||||
selectedStation={selectedStation}
|
||||
setSelectedStation={setSelectedStation}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Control buttons */}
|
||||
|
||||
@ -1,17 +1,21 @@
|
||||
'use client';
|
||||
|
||||
import { Map, Placemark, YMaps } from '@pbe/react-yandex-maps';
|
||||
import React from 'react';
|
||||
import React, { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
import { Point } from '../model';
|
||||
|
||||
type YandexMapProps = {
|
||||
points: Point[];
|
||||
selectedStation: number | null;
|
||||
setSelectedStation: Dispatch<SetStateAction<number | null>>;
|
||||
};
|
||||
|
||||
const mapCenter = [55.751574, 37.573856];
|
||||
|
||||
export const YandexMap = ({ points }: YandexMapProps) => {
|
||||
export const YandexMap = ({
|
||||
points,
|
||||
selectedStation,
|
||||
setSelectedStation,
|
||||
}: YandexMapProps) => {
|
||||
return (
|
||||
<YMaps
|
||||
query={{
|
||||
@ -22,7 +26,7 @@ export const YandexMap = ({ points }: YandexMapProps) => {
|
||||
>
|
||||
<Map
|
||||
defaultState={{
|
||||
center: points[0].coordinates || mapCenter,
|
||||
center: points[0]?.coordinates || mapCenter,
|
||||
zoom: 11,
|
||||
behaviors: ['drag', 'multiTouch', 'dblClickZoom', 'scrollZoom'],
|
||||
}}
|
||||
@ -41,10 +45,22 @@ export const YandexMap = ({ points }: YandexMapProps) => {
|
||||
geometry={point.coordinates}
|
||||
options={{
|
||||
iconLayout: 'default#image',
|
||||
iconImageHref: '/map/oriyo-marker.png',
|
||||
iconImageSize: [64, 64],
|
||||
iconImageHref:
|
||||
!selectedStation || selectedStation === point.id
|
||||
? '/map/oriyo-marker.png'
|
||||
: '/map/oriyo-inactive-marker.png',
|
||||
iconImageSize: selectedStation === point.id ? [70, 70] : [64, 64],
|
||||
iconImageOffset: [-24, -36],
|
||||
}}
|
||||
onClick={() =>
|
||||
setSelectedStation(() => {
|
||||
if (selectedStation !== null && selectedStation === point.id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return point.id;
|
||||
})
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Map>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user