diff --git a/app/pages/catalog/index.vue b/app/pages/catalog/index.vue index 78deab5..2cd346c 100644 --- a/app/pages/catalog/index.vue +++ b/app/pages/catalog/index.vue @@ -9,7 +9,7 @@ panel-width="w-[32rem]" map-id="unified-catalog-map" :point-color="mapPointColor" - :items="currentSelectionItems" + :items="mapItems" :hovered-id="hoveredItemId ?? undefined" :show-panel="showPanel && !kycSheetUuid" :filter-by-bounds="filterByBounds" @@ -475,7 +475,7 @@ watch(searchTrigger, () => { }) // Loading state -const isLoading = computed(() => offersLoading.value || selectionLoading.value) +const isLoading = computed(() => offersLoading.value || selectionLoading.value || exploreOffersLoading.value) // Info loading state for map fitBounds (true while any info data is still loading) const isInfoLoading = computed(() => @@ -501,9 +501,73 @@ const clusterSupplierUuid = computed(() => supplierId.value || undefined) // to avoid mismatch between graph-filtered list and clustered map results. const useServerClustering = computed(() => { if (productId.value && (mapViewMode.value === 'hubs' || mapViewMode.value === 'suppliers')) return false + if (hubId.value && mapViewMode.value === 'offers') return false return true }) +// Offers for Explore map when hub filter is active (graph-based) +const exploreOffers = ref([]) +const exploreOffersLoading = ref(false) + +const shouldLoadExploreOffers = computed(() => + catalogMode.value === 'explore' && mapViewMode.value === 'offers' && !!hubId.value +) + +const loadExploreOffers = async () => { + if (!hubId.value) return + exploreOffersLoading.value = true + try { + const hubData = await execute(GetNodeDocument, { uuid: hubId.value }, 'public', 'geo') + const hub = hubData?.node + if (!hub?.latitude || !hub?.longitude) { + exploreOffers.value = [] + return + } + const geoData = await execute( + NearestOffersDocument, + { + lat: hub.latitude, + lon: hub.longitude, + hubUuid: hubId.value, + productUuid: productId.value || null, + limit: 500 + }, + 'public', + 'geo' + ) + exploreOffers.value = (geoData?.nearestOffers || []).filter((o): o is QuoteOffer => o !== null) + } finally { + exploreOffersLoading.value = false + } +} + +watch([shouldLoadExploreOffers, hubId, productId], ([enabled]) => { + if (!enabled) { + exploreOffers.value = [] + exploreOffersLoading.value = false + return + } + loadExploreOffers() +}, { immediate: true }) + +const mapItems = computed((): MapItemWithCoords[] => { + if (!useServerClustering.value) { + if (mapViewMode.value === 'offers') { + return exploreOffers.value + .filter((offer) => offer.uuid && offer.latitude != null && offer.longitude != null) + .map((offer) => ({ + uuid: offer.uuid, + name: offer.productName || '', + latitude: Number(offer.latitude), + longitude: Number(offer.longitude) + })) + } + if (mapViewMode.value === 'hubs') return toMapItems(filteredHubs.value) + if (mapViewMode.value === 'suppliers') return toMapItems(filteredSuppliers.value) + } + return currentSelectionItems.value +}) + // Show panel when selecting OR when showing info OR when showing quote results const showPanel = computed(() => { return selectMode.value !== null || infoId.value !== null || showQuoteResults.value