Use offer result cards in catalog and compute routes for supplier offers
All checks were successful
Build Docker Image / build (push) Successful in 5m50s

This commit is contained in:
Ruslan Bakiev
2026-02-05 19:02:26 +07:00
parent f1eb7bc746
commit beb02bd3fc
5 changed files with 61 additions and 43 deletions

View File

@@ -37,13 +37,14 @@
<!-- Offers Tab -->
<template v-if="activeTab === 'offers'">
<OfferCard
<OfferResultCard
v-for="(offer, index) in offers"
:key="offer.uuid ?? index"
:offer="offer"
selectable
compact
:is-selected="selectedId === offer.uuid"
:location-name="offer.locationName"
:product-name="offer.title || undefined"
:stages="[]"
:start-name="offer.locationName || undefined"
:end-name="undefined"
@select="selectOffer(offer)"
/>
<Text v-if="offers.length === 0" tone="muted" size="sm" class="text-center py-4">

View File

@@ -13,10 +13,12 @@
</Stack>
<Grid :cols="1" :md="2" :lg="3" :gap="4">
<OfferCard
<OfferResultCard
v-for="(offer, index) in offers"
:key="offer.uuid ?? index"
:offer="offer"
:location-name="offer.locationName"
:product-name="offer.title || undefined"
:stages="[]"
/>
</Grid>

View File

@@ -141,12 +141,15 @@
{{ $t('catalog.empty.noOffers') }}
</div>
<div v-else-if="!loadingOffers" class="flex flex-col gap-2">
<OfferCard
<OfferResultCard
v-for="(offer, index) in relatedOffers"
:key="offer.uuid ?? index"
:offer="offer"
compact
selectable
:location-name="offer.locationName || offer.locationCountry || offer.locationName"
:product-name="offer.productName"
:price-per-unit="offer.pricePerUnit ? Number(offer.pricePerUnit) : null"
:currency="offer.currency"
:unit="offer.unit"
:stages="getOfferStages(offer)"
@select="onOfferSelect(offer)"
/>
</div>
@@ -217,6 +220,7 @@ import type {
InfoSupplierItem,
InfoOfferItem
} from '~/composables/useCatalogInfo'
import type { RouteStageType } from '~/composables/graphql/public/geo-generated'
const props = defineProps<{
entityType: InfoEntityType
@@ -344,4 +348,15 @@ const onSupplierSelect = (supplier: InfoSupplierItem) => {
emit('open-info', 'supplier', supplier.uuid)
}
}
const getOfferStages = (offer: InfoOfferItem) => {
const route = offer.routes?.[0]
if (!route?.stages) return []
return route.stages
.filter((stage): stage is NonNullable<RouteStageType> => stage !== null)
.map(stage => ({
transportType: stage.transportType,
distanceKm: stage.distanceKm
}))
}
</script>

View File

@@ -26,7 +26,14 @@
class="cursor-pointer"
@click="emit('select-offer', offer)"
>
<OfferCard :offer="offer" compact selectable />
<OfferResultCard
:location-name="offer.locationName || offer.locationCountry"
:product-name="offer.productName"
:price-per-unit="offer.pricePerUnit ? Number(offer.pricePerUnit) : null"
:currency="offer.currency"
:unit="offer.unit"
:stages="[]"
/>
</div>
</div>
</div>

View File

@@ -431,6 +431,29 @@ export function useCatalogInfo() {
isLoadingHubs.value = true
try {
let hubUuid: string | null = relatedHubs.value?.[0]?.uuid ?? null
if (!hubUuid && supplier.uuid) {
const hubsData = await execute(
NearestHubsDocument,
{
lat: supplier.latitude,
lon: supplier.longitude,
radius: 1000,
sourceUuid: supplier.uuid,
limit: 1
},
'public',
'geo'
)
const hub = (hubsData?.nearestHubs || []).find((h): h is HubItem => h !== null)
if (hub?.uuid) {
hubUuid = hub.uuid
if (!relatedHubs.value.length) {
relatedHubs.value = [hub]
}
}
}
// Find offers near supplier for this product
const offersData = await execute(
NearestOffersDocument,
@@ -438,6 +461,7 @@ export function useCatalogInfo() {
lat: supplier.latitude,
lon: supplier.longitude,
productUuid,
...(hubUuid ? { hubUuid } : {}),
radius: 500,
limit: 12
},
@@ -447,37 +471,6 @@ export function useCatalogInfo() {
relatedOffers.value = (offersData?.nearestOffers || []).filter((o): o is OfferItem => o !== null)
isLoadingOffers.value = false
// Load hubs near each offer and aggregate (limit to 12)
const allHubs = new Map<string, HubItem>()
for (const offer of relatedOffers.value.slice(0, 3)) {
// Check first 3 offers
if (!offer.latitude || !offer.longitude) continue
try {
const hubsData = await execute(
NearestHubsDocument,
{
lat: offer.latitude,
lon: offer.longitude,
radius: 1000,
limit: 5
},
'public',
'geo'
)
hubsData?.nearestHubs?.forEach(hub => {
if (hub && hub.uuid && !allHubs.has(hub.uuid)) {
allHubs.set(hub.uuid, hub)
}
})
} catch (e) {
console.warn('Error loading hubs for offer:', offer.uuid, e)
}
if (allHubs.size >= 12) break
}
relatedHubs.value = Array.from(allHubs.values()).slice(0, 12)
} finally {
isLoadingOffers.value = false
isLoadingHubs.value = false