diff --git a/src/features/map/ui/gas-station-map.tsx b/src/features/map/ui/gas-station-map.tsx index 0f2d763..7621105 100644 --- a/src/features/map/ui/gas-station-map.tsx +++ b/src/features/map/ui/gas-station-map.tsx @@ -1,10 +1,231 @@ 'use client'; -import { MapPin } from 'lucide-react'; -import { useEffect, useRef } from 'react'; +import { + Check, + ChevronLeft, + ChevronRight, + Filter, + List, + MapPin, +} from 'lucide-react'; +import { useEffect, useRef, useState } from 'react'; + +import { useLanguage } from '@/shared/language'; +import { Badge } from '@/shared/shadcn-ui/badge'; +import { Button } from '@/shared/shadcn-ui/button'; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from '@/shared/shadcn-ui/tabs'; + +// Sample data for gas stations +const stations = [ + { + id: 1, + name: 'АЗС Душанбе-Центр', + address: 'ул. Рудаки 150, Душанбе', + city: 'Душанбе', + coordinates: { x: 0.2, y: 0.3 }, + services: ['ДТ', 'АИ-92', 'АИ-95', 'Z-100 Power', 'Минимаркет', 'Туалет'], + }, + { + id: 2, + name: 'АЗС Худжанд', + address: 'ул. Ленина 45, Худжанд', + city: 'Худжанд', + coordinates: { x: 0.5, y: 0.2 }, + services: [ + 'ДТ', + 'АИ-92', + 'АИ-95', + 'Пропан', + 'Минимаркет', + 'Автомойка', + 'Туалет', + ], + }, + { + id: 3, + name: 'АЗС Куляб', + address: 'ул. Сомони 78, Куляб', + city: 'Куляб', + coordinates: { x: 0.7, y: 0.4 }, + services: ['ДТ', 'АИ-92', 'Пропан', 'Туалет'], + }, + { + id: 4, + name: 'АЗС Бохтар', + address: 'ул. Айни 23, Бохтар', + city: 'Бохтар', + coordinates: { x: 0.3, y: 0.6 }, + services: [ + 'ДТ', + 'АИ-92', + 'АИ-95', + 'Z-100 Power', + 'Минимаркет', + 'Зарядная станция', + 'Туалет', + ], + }, + { + id: 5, + name: 'АЗС Хорог', + address: 'ул. Горная 12, Хорог', + city: 'Хорог', + coordinates: { x: 0.6, y: 0.7 }, + services: ['ДТ', 'АИ-92', 'Автомойка', 'Туалет'], + }, + { + id: 6, + name: 'АЗС Истаравшан', + address: 'ул. Исмоили Сомони 34, Истаравшан', + city: 'Истаравшан', + coordinates: { x: 0.8, y: 0.8 }, + services: ['ДТ', 'АИ-92', 'АИ-95', 'Минимаркет', 'Туалет'], + }, + { + id: 7, + name: 'АЗС Пенджикент', + address: 'ул. Рудаки 56, Пенджикент', + city: 'Пенджикент', + coordinates: { x: 0.1, y: 0.9 }, + services: ['ДТ', 'АИ-92', 'АИ-95', 'Пропан', 'Минимаркет', 'Туалет'], + }, + { + id: 8, + name: 'АЗС Душанбе-Запад', + address: 'ул. Джами 23, Душанбе', + city: 'Душанбе', + coordinates: { x: 0.25, y: 0.35 }, + services: [ + 'ДТ', + 'АИ-92', + 'АИ-95', + 'Z-100 Power', + 'Пропан', + 'Минимаркет', + 'Автомойка', + 'Туалет', + ], + }, + { + id: 9, + name: 'АЗС Душанбе-Восток', + address: 'ул. Айни 78, Душанбе', + city: 'Душанбе', + coordinates: { x: 0.15, y: 0.25 }, + services: [ + 'ДТ', + 'АИ-92', + 'АИ-95', + 'Зарядная станция', + 'Минимаркет', + 'Туалет', + ], + }, + { + id: 10, + name: 'АЗС Гиссар', + address: 'ул. Центральная 12, Гиссар', + city: 'Гиссар', + coordinates: { x: 0.4, y: 0.4 }, + services: ['ДТ', 'АИ-92', 'Пропан', 'Туалет'], + }, + { + id: 11, + name: 'АЗС Вахдат', + address: 'ул. Сомони 45, Вахдат', + city: 'Вахдат', + coordinates: { x: 0.55, y: 0.45 }, + services: ['ДТ', 'АИ-92', 'АИ-95', 'Минимаркет', 'Туалет'], + }, + { + id: 12, + name: 'АЗС Турсунзаде', + address: 'ул. Ленина 34, Турсунзаде', + city: 'Турсунзаде', + coordinates: { x: 0.65, y: 0.55 }, + services: ['ДТ', 'АИ-92', 'АИ-95', 'Z-100 Power', 'Автомойка', 'Туалет'], + }, +]; + +// All available filters +const allFilters = [ + 'ДТ', + 'АИ-92', + 'АИ-95', + 'Z-100 Power', + 'Пропан', + 'Зарядная станция', + 'Минимаркет', + 'Автомойка', + 'Туалет', +]; + +// Extract unique cities from stations +const allCities = [...new Set(stations.map((station) => station.city))].sort(); export default function GasStationMap() { + const { t } = useLanguage(); const mapRef = useRef(null); + const [activeFilters, setActiveFilters] = useState([]); + const [activeCities, setActiveCities] = useState([]); + const [filteredStations, setFilteredStations] = useState(stations); + const [selectedStation, setSelectedStation] = useState(null); + const [isFilterOpen, setIsFilterOpen] = useState(false); + const [isStationListOpen, setIsStationListOpen] = useState(false); + const [activeFilterTab, setActiveFilterTab] = useState('cities'); + + // Toggle service filter + const toggleFilter = (filter: string) => { + if (activeFilters.includes(filter)) { + setActiveFilters(activeFilters.filter((f) => f !== filter)); + } else { + setActiveFilters([...activeFilters, filter]); + } + }; + + // Toggle city filter + const toggleCity = (city: string) => { + if (activeCities.includes(city)) { + setActiveCities(activeCities.filter((c) => c !== city)); + } else { + setActiveCities([...activeCities, city]); + } + }; + + // Select all cities + const selectAllCities = () => { + if (activeCities.length === allCities.length) { + setActiveCities([]); + } else { + setActiveCities([...allCities]); + } + }; + + // Filter stations based on active filters and cities + useEffect(() => { + let filtered = stations; + + // Filter by services + if (activeFilters.length > 0) { + filtered = filtered.filter((station) => + activeFilters.every((filter) => station.services.includes(filter)), + ); + } + + // Filter by cities + if (activeCities.length > 0) { + filtered = filtered.filter((station) => + activeCities.includes(station.city), + ); + } + + setFilteredStations(filtered); + }, [activeFilters, activeCities]); useEffect(() => { // This is a placeholder for a real map implementation @@ -42,24 +263,15 @@ export default function GasStationMap() { } // Draw gas station markers - const stations = [ - { x: 0.2, y: 0.3 }, - { x: 0.5, y: 0.2 }, - { x: 0.7, y: 0.4 }, - { x: 0.3, y: 0.6 }, - { x: 0.6, y: 0.7 }, - { x: 0.8, y: 0.8 }, - { x: 0.1, y: 0.9 }, - ]; - - stations.forEach((station) => { + filteredStations.forEach((station) => { + const isSelected = selectedStation === station.id; // Draw marker - ctx.fillStyle = '#ef4444'; + ctx.fillStyle = isSelected ? '#3b82f6' : '#ef4444'; ctx.beginPath(); ctx.arc( - station.x * canvas.width, - station.y * canvas.height, - 10, + station.coordinates.x * canvas.width, + station.coordinates.y * canvas.height, + isSelected ? 12 : 10, 0, 2 * Math.PI, ); @@ -70,9 +282,9 @@ export default function GasStationMap() { ctx.lineWidth = 2; ctx.beginPath(); ctx.arc( - station.x * canvas.width, - station.y * canvas.height, - 10, + station.coordinates.x * canvas.width, + station.coordinates.y * canvas.height, + isSelected ? 12 : 10, 0, 2 * Math.PI, ); @@ -99,17 +311,257 @@ export default function GasStationMap() { } } }; - }, []); + }, [filteredStations, selectedStation]); return (
-
-
+ {/* Filter panel - slides from left */} +
+
+
+ + {t('map.filters')} +
+ +
+ +
+ + + {t('map.cities')} + {t('map.services')} + + + + + +
+ {allCities.map((city) => ( + + ))} +
+ + {activeCities.length > 0 && ( + + )} +
+ + +
+ {allFilters.map((filter) => ( + + ))} +
+ {activeFilters.length > 0 && ( + + )} +
+
+
+
+ + {/* Station list panel - slides from right */} +
+
+ +
+ {t('map.stationsList')} + {filteredStations.length} +
+
+
+ {filteredStations.length > 0 ? ( +
+ {filteredStations.map((station) => ( +
setSelectedStation(station.id)} + > +
+

{station.name}

+ +
+

+ {station.address} +

+
+ + {station.city} + + {station.services.map((service) => ( + + {service} + + ))} +
+
+ ))} +
+ ) : ( +
+

{t('map.noStations')}

+
+ {activeFilters.length > 0 && ( + + )} + {activeCities.length > 0 && ( + + )} +
+
+ )} +
+
+ + {/* Map */} +
+
+
+ + {/* Control buttons */} +
+ +
+ +
+ +
+ +
- Наши заправки + {t('map.ourStations')}
-

Всего станций: 25

+

+ {t('map.totalStations')}: {stations.length} +

); diff --git a/src/shared/shadcn-ui/badge.tsx b/src/shared/shadcn-ui/badge.tsx new file mode 100644 index 0000000..9c5f1c3 --- /dev/null +++ b/src/shared/shadcn-ui/badge.tsx @@ -0,0 +1,36 @@ +import { cva, type VariantProps } from 'class-variance-authority'; +import * as React from 'react'; + +import { cn } from '@/shared/lib/utils'; + +const badgeVariants = cva( + 'focus:ring-ring inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:ring-2 focus:ring-offset-2 focus:outline-none', + { + variants: { + variant: { + default: + 'bg-primary text-primary-foreground hover:bg-primary/80 border-transparent', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-secondary/80 border-transparent', + destructive: + 'bg-destructive text-destructive-foreground hover:bg-destructive/80 border-transparent', + outline: 'text-foreground', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +); + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( +
+ ); +} + +export { Badge, badgeVariants }; diff --git a/src/widgets/map-section.tsx b/src/widgets/map-section.tsx index ff87613..5e64426 100644 --- a/src/widgets/map-section.tsx +++ b/src/widgets/map-section.tsx @@ -1,11 +1,10 @@ 'use client'; -import { ChevronRight, MapPin } from 'lucide-react'; +import { MapPin } from 'lucide-react'; import { GasStationMap } from '@/features/map'; import { useLanguage } from '@/shared/language'; -import { Button } from '@/shared/shadcn-ui/button'; export const MapSection = () => { const { t } = useLanguage(); @@ -30,12 +29,6 @@ export const MapSection = () => { >
-
- -
);