|
@@ -13,6 +13,7 @@ export default function MapView() {
|
|
|
const mapRef = useRef<MapProvider | null>(null)
|
|
const mapRef = useRef<MapProvider | null>(null)
|
|
|
const { user, isLoading } = useAuth()
|
|
const { user, isLoading } = useAuth()
|
|
|
const [places, setPlaces] = useState<Place[]>([])
|
|
const [places, setPlaces] = useState<Place[]>([])
|
|
|
|
|
+ const [selectedPlace, setSelectedPlace] = useState<Place | null>(null)
|
|
|
const [mapError, setMapError] = useState(false)
|
|
const [mapError, setMapError] = useState(false)
|
|
|
|
|
|
|
|
const fetchPlaces = useCallback(async (bounds?: MapBounds) => {
|
|
const fetchPlaces = useCallback(async (bounds?: MapBounds) => {
|
|
@@ -63,17 +64,19 @@ export default function MapView() {
|
|
|
const provider = mapRef.current
|
|
const provider = mapRef.current
|
|
|
if (!provider || !provider.isReady()) return
|
|
if (!provider || !provider.isReady()) return
|
|
|
|
|
|
|
|
|
|
+ const isGuest = !user
|
|
|
places.forEach((place) => {
|
|
places.forEach((place) => {
|
|
|
provider.addMarker(place.id, place.lat, place.lng, {
|
|
provider.addMarker(place.id, place.lat, place.lng, {
|
|
|
- type: place.type as 'place' | 'studio',
|
|
|
|
|
- ghost: true,
|
|
|
|
|
|
|
+ title: isGuest ? undefined : place.title,
|
|
|
|
|
+ onClick: isGuest ? undefined : () => setSelectedPlace(place),
|
|
|
|
|
+ ghost: isGuest,
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
return () => {
|
|
return () => {
|
|
|
places.forEach((place) => provider.removeMarker(place.id))
|
|
places.forEach((place) => provider.removeMarker(place.id))
|
|
|
}
|
|
}
|
|
|
- }, [places])
|
|
|
|
|
|
|
+ }, [places, user])
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<div className="relative h-full w-full">
|
|
<div className="relative h-full w-full">
|
|
@@ -93,8 +96,33 @@ export default function MapView() {
|
|
|
<p className="text-sm">Зарегистрируйтесь, чтобы исследовать места для фотосъёмок</p>
|
|
<p className="text-sm">Зарегистрируйтесь, чтобы исследовать места для фотосъёмок</p>
|
|
|
</div>
|
|
</div>
|
|
|
)}
|
|
)}
|
|
|
|
|
+
|
|
|
|
|
+ {selectedPlace && (
|
|
|
|
|
+ <PlaceCardModal
|
|
|
|
|
+ place={selectedPlace}
|
|
|
|
|
+ onClose={() => setSelectedPlace(null)}
|
|
|
|
|
+ />
|
|
|
|
|
+ )}
|
|
|
</div>
|
|
</div>
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
|
|
+function PlaceCardModal({ place, onClose }: { place: Place; onClose: () => void }) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div className="absolute bottom-0 left-0 right-0 z-20 max-h-[60vh] overflow-y-auto rounded-t-2xl bg-[#1e293b] p-6 shadow-xl">
|
|
|
|
|
+ <button onClick={onClose} className="mb-4 text-white/60 hover:text-white">✕</button>
|
|
|
|
|
+ <h2 className="mb-2 text-xl font-bold text-white">{place.title}</h2>
|
|
|
|
|
+ {place.address && <p className="mb-2 text-sm text-white/60">{place.address}</p>}
|
|
|
|
|
+ {place.description && <p className="mb-4 text-sm text-white/80">{place.description}</p>}
|
|
|
|
|
+ <div className="mb-4 flex flex-wrap gap-2">
|
|
|
|
|
+ {place.tags?.map((tag) => (
|
|
|
|
|
+ <span key={tag.id} className="rounded-full bg-white/10 px-3 py-1 text-xs text-white/80">{tag.name}</span>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div className="flex items-center gap-4 text-sm text-white/60">
|
|
|
|
|
+ <span>★ {place.rating?.toFixed(1) || 'Нет оценок'}</span>
|
|
|
|
|
+ {place.type === 'studio' && place.hourly_rate && <span>{place.hourly_rate} ₽/час</span>}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|