Render map points by entity type
Some checks failed
Build Docker Image / build (push) Has been cancelled
Some checks failed
Build Docker Image / build (push) Has been cancelled
This commit is contained in:
@@ -44,11 +44,13 @@ const props = withDefaults(defineProps<{
|
||||
mapId: string
|
||||
items?: MapItem[]
|
||||
clusteredPoints?: ClusterPointType[]
|
||||
clusteredPointsByType?: Partial<Record<'offer' | 'hub' | 'supplier', ClusterPointType[]>>
|
||||
useServerClustering?: boolean
|
||||
hoveredItemId?: string | null
|
||||
hoveredItem?: HoveredItem | null
|
||||
pointColor?: string
|
||||
entityType?: 'offer' | 'hub' | 'supplier'
|
||||
visibleTypes?: Array<'offer' | 'hub' | 'supplier'>
|
||||
initialCenter?: [number, number]
|
||||
initialZoom?: number
|
||||
infoLoading?: boolean
|
||||
@@ -68,6 +70,8 @@ const props = withDefaults(defineProps<{
|
||||
infoLoading: false,
|
||||
items: () => [],
|
||||
clusteredPoints: () => [],
|
||||
clusteredPointsByType: undefined,
|
||||
visibleTypes: undefined,
|
||||
relatedPoints: () => []
|
||||
})
|
||||
|
||||
@@ -81,6 +85,11 @@ const { flyThroughSpace } = useMapboxFlyAnimation()
|
||||
const didFitBounds = ref(false)
|
||||
const mapInitialized = ref(false)
|
||||
|
||||
const usesTypedClusters = computed(() => {
|
||||
const typed = props.clusteredPointsByType
|
||||
return !!typed && Object.keys(typed).length > 0
|
||||
})
|
||||
|
||||
// Entity type icons - SVG data URLs with specific colors
|
||||
const createEntityIcon = (type: 'offer' | 'hub' | 'supplier', color: string) => {
|
||||
const icons = {
|
||||
@@ -137,6 +146,8 @@ const ENTITY_COLORS = {
|
||||
offer: '#f97316' // orange
|
||||
} as const
|
||||
|
||||
const CLUSTER_TYPES: Array<'offer' | 'hub' | 'supplier'> = ['offer', 'hub', 'supplier']
|
||||
|
||||
// Load all icons for related points (each type with its standard color)
|
||||
const loadRelatedPointIcons = async (map: MapboxMapType) => {
|
||||
const types: Array<'hub' | 'supplier' | 'offer'> = ['hub', 'supplier', 'offer']
|
||||
@@ -216,6 +227,33 @@ const serverClusteredGeoJson = computed(() => ({
|
||||
}))
|
||||
}))
|
||||
|
||||
const serverClusteredGeoJsonByType = computed(() => {
|
||||
const build = (points: ClusterPointType[] | undefined, type: 'offer' | 'hub' | 'supplier') => ({
|
||||
type: 'FeatureCollection' as const,
|
||||
features: (points || []).filter(Boolean).map(point => ({
|
||||
type: 'Feature' as const,
|
||||
properties: {
|
||||
id: point!.id,
|
||||
name: point!.name,
|
||||
count: point!.count ?? 1,
|
||||
expansionZoom: point!.expansionZoom,
|
||||
isCluster: (point!.count ?? 1) > 1,
|
||||
type
|
||||
},
|
||||
geometry: {
|
||||
type: 'Point' as const,
|
||||
coordinates: [point!.longitude ?? 0, point!.latitude ?? 0]
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
return {
|
||||
offer: build(props.clusteredPointsByType?.offer, 'offer'),
|
||||
hub: build(props.clusteredPointsByType?.hub, 'hub'),
|
||||
supplier: build(props.clusteredPointsByType?.supplier, 'supplier')
|
||||
}
|
||||
})
|
||||
|
||||
// Hovered point GeoJSON (separate layer on top)
|
||||
const hoveredPointGeoJson = computed(() => ({
|
||||
type: 'FeatureCollection' as const,
|
||||
@@ -256,6 +294,17 @@ const sourceId = computed(() => `${props.mapId}-points`)
|
||||
const hoveredSourceId = computed(() => `${props.mapId}-hovered`)
|
||||
const relatedSourceId = computed(() => `${props.mapId}-related`)
|
||||
|
||||
const getServerSourceId = (type: 'offer' | 'hub' | 'supplier') => `${props.mapId}-server-${type}`
|
||||
const getServerClusterLayerId = (type: 'offer' | 'hub' | 'supplier') => `${props.mapId}-server-${type}-clusters`
|
||||
const getServerClusterCountLayerId = (type: 'offer' | 'hub' | 'supplier') => `${props.mapId}-server-${type}-cluster-count`
|
||||
const getServerPointLayerId = (type: 'offer' | 'hub' | 'supplier') => `${props.mapId}-server-${type}-points`
|
||||
const getServerPointLabelLayerId = (type: 'offer' | 'hub' | 'supplier') => `${props.mapId}-server-${type}-point-labels`
|
||||
|
||||
const isTypeVisible = (type: 'offer' | 'hub' | 'supplier') => {
|
||||
if (!props.visibleTypes || props.visibleTypes.length === 0) return true
|
||||
return props.visibleTypes.includes(type)
|
||||
}
|
||||
|
||||
const emitBoundsChange = (map: MapboxMapType) => {
|
||||
const bounds = map.getBounds()
|
||||
if (!bounds) return
|
||||
@@ -279,7 +328,11 @@ const onMapCreated = (map: MapboxMapType) => {
|
||||
})
|
||||
|
||||
if (props.useServerClustering) {
|
||||
await initServerClusteringLayers(map)
|
||||
if (usesTypedClusters.value) {
|
||||
await initServerClusteringLayersByType(map)
|
||||
} else {
|
||||
await initServerClusteringLayers(map)
|
||||
}
|
||||
} else {
|
||||
await initClientClusteringLayers(map)
|
||||
}
|
||||
@@ -677,15 +730,218 @@ const initServerClusteringLayers = async (map: MapboxMapType) => {
|
||||
})
|
||||
}
|
||||
|
||||
const initServerClusteringLayersByType = async (map: MapboxMapType) => {
|
||||
for (const type of CLUSTER_TYPES) {
|
||||
await loadEntityIcon(map, type, ENTITY_COLORS[type])
|
||||
|
||||
const sourceIdByType = getServerSourceId(type)
|
||||
map.addSource(sourceIdByType, {
|
||||
type: 'geojson',
|
||||
data: serverClusteredGeoJsonByType.value[type]
|
||||
})
|
||||
|
||||
const clusterLayerId = getServerClusterLayerId(type)
|
||||
const clusterCountLayerId = getServerClusterCountLayerId(type)
|
||||
const pointLayerId = getServerPointLayerId(type)
|
||||
const pointLabelLayerId = getServerPointLabelLayerId(type)
|
||||
|
||||
map.addLayer({
|
||||
id: clusterLayerId,
|
||||
type: 'circle',
|
||||
source: sourceIdByType,
|
||||
filter: ['>', ['get', 'count'], 1],
|
||||
paint: {
|
||||
'circle-color': ENTITY_COLORS[type],
|
||||
'circle-radius': ['step', ['get', 'count'], 20, 10, 30, 50, 40],
|
||||
'circle-opacity': 0.8,
|
||||
'circle-stroke-width': 2,
|
||||
'circle-stroke-color': '#ffffff'
|
||||
},
|
||||
layout: {
|
||||
visibility: isTypeVisible(type) ? 'visible' : 'none'
|
||||
}
|
||||
})
|
||||
|
||||
map.addLayer({
|
||||
id: clusterCountLayerId,
|
||||
type: 'symbol',
|
||||
source: sourceIdByType,
|
||||
filter: ['>', ['get', 'count'], 1],
|
||||
layout: {
|
||||
'text-field': ['get', 'count'],
|
||||
'text-size': 14,
|
||||
visibility: isTypeVisible(type) ? 'visible' : 'none'
|
||||
},
|
||||
paint: { 'text-color': '#ffffff' }
|
||||
})
|
||||
|
||||
map.addLayer({
|
||||
id: pointLayerId,
|
||||
type: 'symbol',
|
||||
source: sourceIdByType,
|
||||
filter: ['==', ['get', 'count'], 1],
|
||||
layout: {
|
||||
'icon-image': `entity-icon-${type}`,
|
||||
'icon-size': 1,
|
||||
'icon-allow-overlap': true,
|
||||
visibility: isTypeVisible(type) ? 'visible' : 'none'
|
||||
}
|
||||
})
|
||||
|
||||
map.addLayer({
|
||||
id: pointLabelLayerId,
|
||||
type: 'symbol',
|
||||
source: sourceIdByType,
|
||||
filter: ['==', ['get', 'count'], 1],
|
||||
layout: {
|
||||
'text-field': ['get', 'name'],
|
||||
'text-offset': [0, 1.8],
|
||||
'text-size': 12,
|
||||
'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
|
||||
visibility: isTypeVisible(type) ? 'visible' : 'none'
|
||||
},
|
||||
paint: {
|
||||
'text-color': '#ffffff',
|
||||
'text-halo-color': '#000000',
|
||||
'text-halo-width': 1.5
|
||||
}
|
||||
})
|
||||
|
||||
map.on('click', clusterLayerId, (e) => {
|
||||
const features = map.queryRenderedFeatures(e.point, { layers: [clusterLayerId] })
|
||||
const feature = features[0]
|
||||
if (!feature) return
|
||||
const clusterId = feature.properties?.cluster_id
|
||||
const source = map.getSource(sourceIdByType) as mapboxgl.GeoJSONSource
|
||||
source.getClusterExpansionZoom(clusterId, (err, zoom) => {
|
||||
if (err) return
|
||||
const geometry = feature.geometry as GeoJSON.Point
|
||||
map.easeTo({ center: geometry.coordinates as [number, number], zoom: zoom || 4 })
|
||||
})
|
||||
})
|
||||
|
||||
map.on('click', pointLayerId, (e) => {
|
||||
const features = map.queryRenderedFeatures(e.point, { layers: [pointLayerId] })
|
||||
const feature = features[0]
|
||||
if (!feature) return
|
||||
const props_data = feature.properties as Record<string, any> | undefined
|
||||
emit('select-item', props_data?.id, props_data)
|
||||
})
|
||||
|
||||
map.on('mouseenter', clusterLayerId, () => { map.getCanvas().style.cursor = 'pointer' })
|
||||
map.on('mouseleave', clusterLayerId, () => { map.getCanvas().style.cursor = '' })
|
||||
map.on('mouseenter', pointLayerId, () => { map.getCanvas().style.cursor = 'pointer' })
|
||||
map.on('mouseleave', pointLayerId, () => { map.getCanvas().style.cursor = '' })
|
||||
}
|
||||
|
||||
// Hovered point layer (on top of everything)
|
||||
map.addSource(hoveredSourceId.value, {
|
||||
type: 'geojson',
|
||||
data: hoveredPointGeoJson.value
|
||||
})
|
||||
map.addLayer({
|
||||
id: 'hovered-point-ring',
|
||||
type: 'circle',
|
||||
source: hoveredSourceId.value,
|
||||
paint: {
|
||||
'circle-radius': 20,
|
||||
'circle-color': 'transparent',
|
||||
'circle-stroke-width': 3,
|
||||
'circle-stroke-color': '#ffffff'
|
||||
}
|
||||
})
|
||||
map.addLayer({
|
||||
id: 'hovered-point-layer',
|
||||
type: 'circle',
|
||||
source: hoveredSourceId.value,
|
||||
paint: {
|
||||
'circle-radius': 14,
|
||||
'circle-color': props.pointColor,
|
||||
'circle-stroke-width': 3,
|
||||
'circle-stroke-color': '#ffffff'
|
||||
}
|
||||
})
|
||||
|
||||
// Related points layer
|
||||
await loadRelatedPointIcons(map)
|
||||
|
||||
map.addSource(relatedSourceId.value, {
|
||||
type: 'geojson',
|
||||
data: relatedPointsGeoJson.value
|
||||
})
|
||||
map.addLayer({
|
||||
id: `${props.mapId}-related-points`,
|
||||
type: 'symbol',
|
||||
source: relatedSourceId.value,
|
||||
layout: {
|
||||
'icon-image': [
|
||||
'match',
|
||||
['get', 'type'],
|
||||
'hub', 'related-icon-hub',
|
||||
'supplier', 'related-icon-supplier',
|
||||
'offer', 'related-icon-offer',
|
||||
'related-icon-offer'
|
||||
],
|
||||
'icon-size': 1,
|
||||
'icon-allow-overlap': true
|
||||
}
|
||||
})
|
||||
map.addLayer({
|
||||
id: `${props.mapId}-related-labels`,
|
||||
type: 'symbol',
|
||||
source: relatedSourceId.value,
|
||||
layout: {
|
||||
'text-field': ['get', 'name'],
|
||||
'text-size': 11,
|
||||
'text-anchor': 'top',
|
||||
'text-offset': [0, 1.5]
|
||||
},
|
||||
paint: {
|
||||
'text-color': '#ffffff',
|
||||
'text-halo-color': '#000000',
|
||||
'text-halo-width': 1
|
||||
}
|
||||
})
|
||||
|
||||
map.on('click', `${props.mapId}-related-points`, (e) => {
|
||||
const features = map.queryRenderedFeatures(e.point, { layers: [`${props.mapId}-related-points`] })
|
||||
const feature = features[0]
|
||||
if (!feature) return
|
||||
const props_data = feature.properties as Record<string, any> | undefined
|
||||
emit('select-item', props_data?.uuid, props_data)
|
||||
})
|
||||
|
||||
map.on('mouseenter', `${props.mapId}-related-points`, () => {
|
||||
map.getCanvas().style.cursor = 'pointer'
|
||||
})
|
||||
|
||||
map.on('mouseleave', `${props.mapId}-related-points`, () => {
|
||||
map.getCanvas().style.cursor = ''
|
||||
})
|
||||
}
|
||||
|
||||
// Update map data when items or clusteredPoints change
|
||||
watch(() => props.useServerClustering ? serverClusteredGeoJson.value : geoJsonData.value, (newData) => {
|
||||
if (!mapRef.value || !mapInitialized.value) return
|
||||
if (usesTypedClusters.value) return
|
||||
const source = mapRef.value.getSource(sourceId.value) as mapboxgl.GeoJSONSource | undefined
|
||||
if (source) {
|
||||
source.setData(newData)
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
watch(() => serverClusteredGeoJsonByType.value, (newData) => {
|
||||
if (!mapRef.value || !mapInitialized.value) return
|
||||
if (!usesTypedClusters.value) return
|
||||
for (const type of CLUSTER_TYPES) {
|
||||
const sourceIdByType = getServerSourceId(type)
|
||||
const source = mapRef.value.getSource(sourceIdByType) as mapboxgl.GeoJSONSource | undefined
|
||||
if (source) {
|
||||
source.setData(newData[type])
|
||||
}
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
// Update hovered point layer when hoveredItem changes
|
||||
watch(() => props.hoveredItem, () => {
|
||||
if (!mapRef.value || !mapInitialized.value) return
|
||||
@@ -706,6 +962,25 @@ watch(() => props.relatedPoints, () => {
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
watch(() => props.visibleTypes, () => {
|
||||
if (!mapRef.value || !mapInitialized.value) return
|
||||
if (!usesTypedClusters.value) return
|
||||
for (const type of CLUSTER_TYPES) {
|
||||
const visibility = isTypeVisible(type) ? 'visible' : 'none'
|
||||
const layers = [
|
||||
getServerClusterLayerId(type),
|
||||
getServerClusterCountLayerId(type),
|
||||
getServerPointLayerId(type),
|
||||
getServerPointLabelLayerId(type)
|
||||
]
|
||||
layers.forEach((layerId) => {
|
||||
if (mapRef.value?.getLayer(layerId)) {
|
||||
mapRef.value.setLayoutProperty(layerId, 'visibility', visibility)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
// Fit bounds when info loading finishes (all related data loaded)
|
||||
watch(() => props.infoLoading, (loading, wasLoading) => {
|
||||
// Only fit bounds when loading changes from true to false (data finished loading)
|
||||
@@ -731,10 +1006,12 @@ watch([() => props.pointColor, () => props.entityType], async ([newColor, newTyp
|
||||
|
||||
// Update cluster circle colors
|
||||
if (props.useServerClustering) {
|
||||
if (usesTypedClusters.value) {
|
||||
return
|
||||
}
|
||||
if (map.getLayer('server-clusters')) {
|
||||
map.setPaintProperty('server-clusters', 'circle-color', newColor)
|
||||
}
|
||||
// Update icon reference for points
|
||||
if (map.getLayer('server-points')) {
|
||||
map.setLayoutProperty('server-points', 'icon-image', `entity-icon-${newType}`)
|
||||
}
|
||||
@@ -755,6 +1032,7 @@ watch([() => props.pointColor, () => props.entityType], async ([newColor, newTyp
|
||||
|
||||
// fitBounds for server clustering when first data arrives
|
||||
watch(() => props.clusteredPoints, (points) => {
|
||||
if (usesTypedClusters.value) return
|
||||
if (!mapRef.value || !mapInitialized.value) return
|
||||
if (!didFitBounds.value && points && points.length > 0) {
|
||||
const bounds = new LngLatBounds()
|
||||
@@ -770,6 +1048,26 @@ watch(() => props.clusteredPoints, (points) => {
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
watch([() => props.clusteredPointsByType, () => props.visibleTypes], () => {
|
||||
if (!usesTypedClusters.value) return
|
||||
if (!mapRef.value || !mapInitialized.value) return
|
||||
if (didFitBounds.value) return
|
||||
|
||||
const bounds = new LngLatBounds()
|
||||
const visible = props.visibleTypes && props.visibleTypes.length > 0 ? props.visibleTypes : CLUSTER_TYPES
|
||||
visible.forEach(type => {
|
||||
const points = serverClusteredGeoJsonByType.value[type]?.features ?? []
|
||||
points.forEach((p) => {
|
||||
const coords = (p.geometry as GeoJSON.Point).coordinates as [number, number]
|
||||
bounds.extend(coords)
|
||||
})
|
||||
})
|
||||
if (!bounds.isEmpty()) {
|
||||
mapRef.value.fitBounds(bounds, { padding: 50, maxZoom: 6 })
|
||||
didFitBounds.value = true
|
||||
}
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
// Expose flyTo method for external use (with space fly animation)
|
||||
const flyTo = async (lat: number, lng: number, zoom = 8) => {
|
||||
if (!mapRef.value) return
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
ref="mapRef"
|
||||
:map-id="mapId"
|
||||
:items="isInfoMode ? [] : (useServerClustering ? [] : itemsWithCoords)"
|
||||
:clustered-points="isInfoMode ? [] : (useServerClustering ? clusteredNodes : [])"
|
||||
:clustered-points="isInfoMode ? [] : (useServerClustering && !useTypedClusters ? clusteredNodes : [])"
|
||||
:clustered-points-by-type="isInfoMode ? undefined : (useServerClustering && useTypedClusters ? clusteredPointsByType : undefined)"
|
||||
:visible-types="useServerClustering && useTypedClusters ? visibleTypes : undefined"
|
||||
:use-server-clustering="useServerClustering && !isInfoMode"
|
||||
:point-color="activePointColor"
|
||||
:entity-type="activeEntityType"
|
||||
@@ -246,6 +248,7 @@ const props = withDefaults(defineProps<{
|
||||
loading?: boolean
|
||||
useServerClustering?: boolean
|
||||
clusterNodeType?: string
|
||||
useTypedClusters?: boolean
|
||||
mapId?: string
|
||||
pointColor?: string
|
||||
hoveredId?: string
|
||||
@@ -266,6 +269,7 @@ const props = withDefaults(defineProps<{
|
||||
loading: false,
|
||||
useServerClustering: true,
|
||||
clusterNodeType: 'offer',
|
||||
useTypedClusters: false,
|
||||
mapId: 'catalog-map',
|
||||
pointColor: '#f97316',
|
||||
items: () => [],
|
||||
@@ -284,11 +288,59 @@ const emit = defineEmits<{
|
||||
'update:filter-by-bounds': [value: boolean]
|
||||
}>()
|
||||
|
||||
// Server-side clustering - use computed node type based on view mode
|
||||
const { clusteredNodes, fetchClusters, loading: clusterLoading, clearNodes } = useClusteredNodes(undefined, activeClusterNodeType)
|
||||
const useTypedClusters = computed(() => props.useTypedClusters && props.useServerClustering)
|
||||
|
||||
// Server-side clustering (single-type mode)
|
||||
const { clusteredNodes, fetchClusters, loading: singleClusterLoading, clearNodes } = useClusteredNodes(undefined, activeClusterNodeType)
|
||||
|
||||
// Server-side clustering (typed mode)
|
||||
const offerClusters = useClusteredNodes(undefined, ref('offer'))
|
||||
const hubClusters = useClusteredNodes(undefined, ref('logistics'))
|
||||
const supplierClusters = useClusteredNodes(undefined, ref('supplier'))
|
||||
|
||||
const clusteredPointsByType = computed(() => ({
|
||||
offer: offerClusters.clusteredNodes.value,
|
||||
hub: hubClusters.clusteredNodes.value,
|
||||
supplier: supplierClusters.clusteredNodes.value
|
||||
}))
|
||||
|
||||
const activeClusterType = computed<'offer' | 'hub' | 'supplier'>(() => {
|
||||
if (mapViewMode.value === 'hubs') return 'hub'
|
||||
if (mapViewMode.value === 'suppliers') return 'supplier'
|
||||
return 'offer'
|
||||
})
|
||||
|
||||
const visibleTypes = computed(() => [activeClusterType.value])
|
||||
|
||||
const clusterLoading = computed(() => {
|
||||
if (!useTypedClusters.value) return singleClusterLoading.value
|
||||
if (activeClusterType.value === 'hub') return hubClusters.loading.value
|
||||
if (activeClusterType.value === 'supplier') return supplierClusters.loading.value
|
||||
return offerClusters.loading.value
|
||||
})
|
||||
|
||||
const fetchActiveClusters = async () => {
|
||||
if (!currentBounds.value) return
|
||||
if (activeClusterType.value === 'hub') {
|
||||
await hubClusters.fetchClusters(currentBounds.value)
|
||||
return
|
||||
}
|
||||
if (activeClusterType.value === 'supplier') {
|
||||
await supplierClusters.fetchClusters(currentBounds.value)
|
||||
return
|
||||
}
|
||||
await offerClusters.fetchClusters(currentBounds.value)
|
||||
}
|
||||
|
||||
// Refetch clusters when view mode changes
|
||||
watch(mapViewMode, async () => {
|
||||
if (!props.useServerClustering) return
|
||||
if (useTypedClusters.value) {
|
||||
if (currentBounds.value) {
|
||||
await fetchActiveClusters()
|
||||
}
|
||||
return
|
||||
}
|
||||
// Clear old data first
|
||||
clearNodes()
|
||||
// Refetch with current bounds if available
|
||||
@@ -338,7 +390,11 @@ const onBoundsChange = (bounds: MapBounds) => {
|
||||
emit('bounds-change', bounds)
|
||||
// Don't fetch clusters when in info mode
|
||||
if (props.useServerClustering && !isInfoMode.value) {
|
||||
fetchClusters(bounds)
|
||||
if (useTypedClusters.value) {
|
||||
fetchActiveClusters()
|
||||
} else {
|
||||
fetchClusters(bounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
ref="catalogPageRef"
|
||||
:loading="isLoading"
|
||||
:use-server-clustering="true"
|
||||
:use-typed-clusters="true"
|
||||
:cluster-node-type="clusterNodeType"
|
||||
map-id="unified-catalog-map"
|
||||
:point-color="mapPointColor"
|
||||
@@ -410,10 +411,12 @@ const onMapSelect = async (item: MapSelectItem) => {
|
||||
|
||||
const itemName = item.name || itemId.slice(0, 8) + '...'
|
||||
|
||||
const itemType = (item as MapSelectItem & { type?: 'hub' | 'supplier' | 'offer' }).type
|
||||
|
||||
// If in selection mode, use map click to fill the selector
|
||||
if (selectMode.value) {
|
||||
// For hubs selection - click on hub fills hub selector
|
||||
if (selectMode.value === 'hub' && mapViewMode.value === 'hubs') {
|
||||
if (selectMode.value === 'hub' && (itemType === 'hub' || mapViewMode.value === 'hubs')) {
|
||||
selectItem('hub', itemId, itemName)
|
||||
showQuoteResults.value = false
|
||||
offers.value = []
|
||||
@@ -421,7 +424,7 @@ const onMapSelect = async (item: MapSelectItem) => {
|
||||
}
|
||||
|
||||
// For supplier selection - click on supplier fills supplier selector
|
||||
if (selectMode.value === 'supplier' && mapViewMode.value === 'suppliers') {
|
||||
if (selectMode.value === 'supplier' && (itemType === 'supplier' || mapViewMode.value === 'suppliers')) {
|
||||
selectItem('supplier', itemId, itemName)
|
||||
showQuoteResults.value = false
|
||||
offers.value = []
|
||||
@@ -429,7 +432,7 @@ const onMapSelect = async (item: MapSelectItem) => {
|
||||
}
|
||||
|
||||
// For product selection viewing offers - fetch offer to get productUuid
|
||||
if (selectMode.value === 'product' && mapViewMode.value === 'offers') {
|
||||
if (selectMode.value === 'product' && (itemType === 'offer' || mapViewMode.value === 'offers')) {
|
||||
// Fetch offer details to get productUuid (not available in cluster data)
|
||||
const data = await execute(GetOfferDocument, { uuid: itemId }, 'public', 'exchange')
|
||||
const offer = data?.getOffer
|
||||
@@ -444,8 +447,8 @@ const onMapSelect = async (item: MapSelectItem) => {
|
||||
|
||||
// NEW: Default behavior - open Info directly
|
||||
let infoType: 'hub' | 'supplier' | 'offer'
|
||||
if (mapViewMode.value === 'hubs') infoType = 'hub'
|
||||
else if (mapViewMode.value === 'suppliers') infoType = 'supplier'
|
||||
if (itemType === 'hub' || mapViewMode.value === 'hubs') infoType = 'hub'
|
||||
else if (itemType === 'supplier' || mapViewMode.value === 'suppliers') infoType = 'supplier'
|
||||
else infoType = 'offer'
|
||||
|
||||
openInfo(infoType, itemId)
|
||||
|
||||
Reference in New Issue
Block a user