Use geo offers for quote results
All checks were successful
Build Docker Image / build (push) Successful in 5m9s

This commit is contained in:
Ruslan Bakiev
2026-02-06 18:25:44 +07:00
parent 0453aeae07
commit 87133ed37a
2 changed files with 110 additions and 19 deletions

View File

@@ -34,7 +34,8 @@
:quantity="offer.quantity"
:currency="offer.currency"
:unit="offer.unit"
:stages="[]"
:stages="getOfferStages(offer)"
:total-time-seconds="offer.routes?.[0]?.totalTimeSeconds ?? null"
/>
</div>
</div>
@@ -48,6 +49,7 @@ interface Offer {
productName?: string | null
productUuid?: string | null
supplierName?: string | null
supplierUuid?: string | null
quantity?: number | string | null
unit?: string | null
pricePerUnit?: number | string | null
@@ -55,6 +57,15 @@ interface Offer {
locationName?: string | null
locationCountry?: string | null
locationCountryCode?: string | null
routes?: Array<{
totalTimeSeconds?: number | null
stages?: Array<{
transportType?: string | null
distanceKm?: number | null
travelTimeSeconds?: number | null
fromName?: string | null
} | null> | null
} | null> | null
}
const emit = defineEmits<{
@@ -69,4 +80,17 @@ const props = defineProps<{
const offersWithPrice = computed(() =>
(props.offers || []).filter(o => o?.pricePerUnit != null)
)
const getOfferStages = (offer: Offer) => {
const route = offer.routes?.[0]
if (!route?.stages) return []
return route.stages
.filter((stage): stage is NonNullable<typeof stage> => stage !== null)
.map((stage) => ({
transportType: stage.transportType,
distanceKm: stage.distanceKm,
travelTimeSeconds: stage.travelTimeSeconds,
fromName: stage.fromName
}))
}
</script>

View File

@@ -83,11 +83,33 @@
</template>
<script setup lang="ts">
import { GetOffersDocument, GetOfferDocument, type GetOffersQueryVariables, type GetOffersQueryResult } from '~/composables/graphql/public/exchange-generated'
import { GetOffersDocument, GetOfferDocument, type GetOffersQueryVariables } from '~/composables/graphql/public/exchange-generated'
import { GetNodeDocument, NearestOffersDocument } from '~/composables/graphql/public/geo-generated'
import type { MapBounds } from '~/components/catalog/CatalogMap.vue'
// Offer type from search results
type OfferResult = NonNullable<NonNullable<GetOffersQueryResult['getOffers']>[number]>
type QuoteOffer = {
uuid: string
productUuid?: string | null
productName?: string | null
supplierUuid?: string | null
supplierName?: string | null
teamUuid?: string | null
quantity?: number | string | null
unit?: string | null
pricePerUnit?: number | string | null
currency?: string | null
locationName?: string | null
locationCountry?: string | null
routes?: Array<{
totalTimeSeconds?: number | null
stages?: Array<{
transportType?: string | null
distanceKm?: number | null
travelTimeSeconds?: number | null
fromName?: string | null
} | null> | null
} | null> | null
}
definePageMeta({
layout: 'topnav'
@@ -393,7 +415,7 @@ const relatedPoints = computed(() => {
})
// Offers data for quote results
const offers = ref<OfferResult[]>([])
const offers = ref<QuoteOffer[]>([])
const offersLoading = ref(false)
const showQuoteResults = ref(false)
@@ -574,24 +596,69 @@ const onSearch = async () => {
showQuoteResults.value = true
try {
const vars: GetOffersQueryVariables = {}
if (productId.value) vars.productUuid = productId.value
if (supplierId.value) vars.teamUuid = supplierId.value
if (hubId.value) vars.locationUuid = hubId.value
// Prefer geo-based offers with routes when hub + product are selected
if (hubId.value && productId.value) {
const hubData = await execute(GetNodeDocument, { uuid: hubId.value }, 'public', 'geo')
const hub = hubData?.node
if (hub?.latitude != null && hub?.longitude != null) {
const geoData = await execute(
NearestOffersDocument,
{
lat: hub.latitude,
lon: hub.longitude,
productUuid: productId.value,
hubUuid: hubId.value,
radius: 500,
limit: 12
},
'public',
'geo'
)
const data = await execute(GetOffersDocument, vars, 'public', 'exchange')
offers.value = (data?.getOffers || []).filter((o): o is OfferResult => o !== null)
let nearest = (geoData?.nearestOffers || []).filter((o): o is QuoteOffer => o !== null)
if (supplierId.value) {
nearest = nearest.filter(o => o?.supplierUuid === supplierId.value)
}
offers.value = nearest
// Update labels from response
const first = offers.value[0]
if (first) {
if (productId.value && first.productName) {
setLabel('product', productId.value, first.productName)
const first = offers.value[0]
if (first?.productName) {
setLabel('product', productId.value, first.productName)
}
} else {
offers.value = []
}
if (hubId.value && first.locationName) {
setLabel('hub', hubId.value, first.locationName)
} else {
const vars: GetOffersQueryVariables = {}
if (productId.value) vars.productUuid = productId.value
if (supplierId.value) vars.teamUuid = supplierId.value
if (hubId.value) vars.locationUuid = hubId.value
const data = await execute(GetOffersDocument, vars, 'public', 'exchange')
const exchangeOffers = (data?.getOffers || []).filter((o): o is NonNullable<typeof o> => o !== null)
offers.value = exchangeOffers.map((offer) => ({
uuid: offer.uuid,
productUuid: offer.productUuid,
productName: offer.productName,
teamUuid: offer.teamUuid,
quantity: offer.quantity,
unit: offer.unit,
pricePerUnit: offer.pricePerUnit,
currency: offer.currency,
locationName: offer.locationName,
locationCountry: offer.locationCountry
}))
// Update labels from response
const first = offers.value[0]
if (first) {
if (productId.value && first.productName) {
setLabel('product', productId.value, first.productName)
}
if (hubId.value && first.locationName) {
setLabel('hub', hubId.value, first.locationName)
}
}
// Note: teamName not included in GetOffers query, supplier label cannot be updated from offer
}
} finally {
offersLoading.value = false