Fix InfoPanel map: hide toggle, show current entity, auto-center
All checks were successful
Build Docker Image / build (push) Successful in 4m18s

- Hide view mode toggle (offers/hubs/suppliers) when in InfoPanel mode
- Add current entity to relatedPoints so it's visible on the map
- Auto-fit map bounds to show all points (current + related) in InfoPanel mode
This commit is contained in:
Ruslan Bakiev
2026-01-27 11:25:57 +07:00
parent 80474acc0f
commit ff34c564e1
3 changed files with 53 additions and 21 deletions

View File

@@ -693,13 +693,26 @@ watch(() => props.hoveredItem, () => {
} }
}, { deep: true }) }, { deep: true })
// Update related points layer when relatedPoints changes // Update related points layer when relatedPoints changes + fit bounds
watch(() => props.relatedPoints, () => { watch(() => props.relatedPoints, (points) => {
if (!mapRef.value || !mapInitialized.value) return if (!mapRef.value || !mapInitialized.value) return
// Update the source data
const source = mapRef.value.getSource(relatedSourceId.value) as mapboxgl.GeoJSONSource | undefined const source = mapRef.value.getSource(relatedSourceId.value) as mapboxgl.GeoJSONSource | undefined
if (source) { if (source) {
source.setData(relatedPointsGeoJson.value) source.setData(relatedPointsGeoJson.value)
} }
// Fit bounds to show all related points (Info mode)
if (points && points.length > 0) {
const bounds = new LngLatBounds()
points.forEach(p => {
bounds.extend([p.longitude, p.latitude])
})
if (!bounds.isEmpty()) {
mapRef.value.fitBounds(bounds, { padding: 80, maxZoom: 12 })
}
}
}, { deep: true }) }, { deep: true })
// Watch for pointColor or entityType changes - update colors and icons // Watch for pointColor or entityType changes - update colors and icons

View File

@@ -64,8 +64,8 @@
</label> </label>
<!-- View toggle (top RIGHT overlay, below header) --> <!-- View toggle (top RIGHT overlay, below header) - hide in info mode -->
<div class="absolute top-[116px] right-4 z-20 hidden lg:flex items-center gap-2"> <div v-if="!isInfoMode" class="absolute top-[116px] right-4 z-20 hidden lg:flex items-center gap-2">
<!-- View mode toggle --> <!-- View mode toggle -->
<div class="flex gap-1 bg-black/30 backdrop-blur-md rounded-lg p-1 border border-white/10"> <div class="flex gap-1 bg-black/30 backdrop-blur-md rounded-lg p-1 border border-white/10">
<button <button
@@ -126,8 +126,8 @@
<span>{{ $t('catalog.list') }}</span> <span>{{ $t('catalog.list') }}</span>
</button> </button>
<!-- Mobile view toggle --> <!-- Mobile view toggle - hide in info mode -->
<div class="flex gap-1 bg-black/30 backdrop-blur-md rounded-lg p-1 border border-white/10"> <div v-if="!isInfoMode" class="flex gap-1 bg-black/30 backdrop-blur-md rounded-lg p-1 border border-white/10">
<button <button
class="flex items-center justify-center w-8 h-8 rounded-md transition-colors" class="flex items-center justify-center w-8 h-8 rounded-md transition-colors"
:class="mapViewMode === 'offers' ? 'bg-white/20' : 'hover:bg-white/10'" :class="mapViewMode === 'offers' ? 'bg-white/20' : 'hover:bg-white/10'"

View File

@@ -67,9 +67,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { GetOffersDocument, GetOfferDocument } from '~/composables/graphql/public/exchange-generated' import { GetOffersDocument, GetOfferDocument, type GetOffersQueryVariables, type GetOffersQueryResult } from '~/composables/graphql/public/exchange-generated'
import type { MapBounds } from '~/components/catalog/CatalogMap.vue' import type { MapBounds } from '~/components/catalog/CatalogMap.vue'
// Offer type from search results
type OfferResult = NonNullable<NonNullable<GetOffersQueryResult['getOffers']>[number]>
definePageMeta({ definePageMeta({
layout: 'topnav' layout: 'topnav'
}) })
@@ -282,7 +285,7 @@ watch(infoProduct, async (productUuid) => {
} }
}) })
// Related points for Info mode (shown on map) - show all related entities // Related points for Info mode (shown on map) - show current entity + all related entities
const relatedPoints = computed(() => { const relatedPoints = computed(() => {
if (!infoId.value) return [] if (!infoId.value) return []
@@ -294,7 +297,18 @@ const relatedPoints = computed(() => {
type: 'hub' | 'supplier' | 'offer' type: 'hub' | 'supplier' | 'offer'
}> = [] }> = []
// Add all hubs // Add current entity first (the one we're viewing in InfoPanel)
if (entity.value?.latitude && entity.value?.longitude) {
points.push({
uuid: infoId.value.uuid,
name: entity.value.name || '',
latitude: Number(entity.value.latitude),
longitude: Number(entity.value.longitude),
type: infoId.value.type
})
}
// Add all related hubs
relatedHubs.value.forEach(hub => { relatedHubs.value.forEach(hub => {
if (hub.uuid && hub.latitude && hub.longitude) { if (hub.uuid && hub.latitude && hub.longitude) {
points.push({ points.push({
@@ -307,7 +321,7 @@ const relatedPoints = computed(() => {
} }
}) })
// Add all suppliers // Add all related suppliers
relatedSuppliers.value.forEach(supplier => { relatedSuppliers.value.forEach(supplier => {
if (supplier.uuid && supplier.latitude && supplier.longitude) { if (supplier.uuid && supplier.latitude && supplier.longitude) {
points.push({ points.push({
@@ -324,7 +338,7 @@ const relatedPoints = computed(() => {
}) })
// Offers data for quote results // Offers data for quote results
const offers = ref<any[]>([]) const offers = ref<OfferResult[]>([])
const offersLoading = ref(false) const offersLoading = ref(false)
const showQuoteResults = ref(false) const showQuoteResults = ref(false)
@@ -360,8 +374,15 @@ const mapPointColor = computed(() => {
return entityColors.offer return entityColors.offer
}) })
// Map item type from CatalogMap
interface MapSelectItem {
uuid?: string | null
id?: string
name?: string | null
}
// Handle map item selection // Handle map item selection
const onMapSelect = async (item: any) => { const onMapSelect = async (item: MapSelectItem) => {
// Get uuid from item - clusters use 'id', regular items use 'uuid' // Get uuid from item - clusters use 'id', regular items use 'uuid'
const itemId = item.uuid || item.id const itemId = item.uuid || item.id
if (!itemId || itemId.startsWith('cluster-')) return if (!itemId || itemId.startsWith('cluster-')) return
@@ -411,7 +432,7 @@ const onMapSelect = async (item: any) => {
} }
// Handle selection from SelectionPanel - add to filter (show badge in search) // Handle selection from SelectionPanel - add to filter (show badge in search)
const onSelectItem = (type: string, item: any) => { const onSelectItem = (type: string, item: { uuid?: string | null; name?: string | null }) => {
if (item.uuid && item.name) { if (item.uuid && item.name) {
selectItem(type, item.uuid, item.name) selectItem(type, item.uuid, item.name)
} }
@@ -470,26 +491,24 @@ const onSearch = async () => {
showQuoteResults.value = true showQuoteResults.value = true
try { try {
const vars: any = {} const vars: GetOffersQueryVariables = {}
if (productId.value) vars.productUuid = productId.value if (productId.value) vars.productUuid = productId.value
if (supplierId.value) vars.teamUuid = supplierId.value if (supplierId.value) vars.teamUuid = supplierId.value
if (hubId.value) vars.locationUuid = hubId.value if (hubId.value) vars.locationUuid = hubId.value
const data = await execute(GetOffersDocument, vars, 'public', 'exchange') const data = await execute(GetOffersDocument, vars, 'public', 'exchange')
offers.value = data?.getOffers || [] offers.value = (data?.getOffers || []).filter((o): o is OfferResult => o !== null)
// Update labels from response // Update labels from response
if (offers.value.length > 0) {
const first = offers.value[0] const first = offers.value[0]
if (first) {
if (productId.value && first.productName) { if (productId.value && first.productName) {
setLabel('product', productId.value, first.productName) setLabel('product', productId.value, first.productName)
} }
if (hubId.value && first.locationName) { if (hubId.value && first.locationName) {
setLabel('hub', hubId.value, first.locationName) setLabel('hub', hubId.value, first.locationName)
} }
if (supplierId.value && first.teamName) { // Note: teamName not included in GetOffers query, supplier label cannot be updated from offer
setLabel('supplier', supplierId.value, first.teamName)
}
} }
} finally { } finally {
offersLoading.value = false offersLoading.value = false
@@ -497,7 +516,7 @@ const onSearch = async () => {
} }
// Select offer - navigate to detail page // Select offer - navigate to detail page
const onSelectOffer = (offer: any) => { const onSelectOffer = (offer: { uuid: string; productUuid?: string | null }) => {
if (offer.uuid && offer.productUuid) { if (offer.uuid && offer.productUuid) {
router.push(localePath(`/catalog/offers/${offer.productUuid}?offer=${offer.uuid}`)) router.push(localePath(`/catalog/offers/${offer.productUuid}?offer=${offer.uuid}`))
} }