Refactor catalog to use coordinate-based GraphQL endpoints
All checks were successful
Build Docker Image / build (push) Successful in 3m33s

Replace entity-specific queries (GetProductsNearHub, GetOffersByHub, GetHubsForProduct, GetSuppliersForProduct) with unified coordinate-based endpoints (NearestHubs, NearestOffers, NearestSuppliers, RouteToCoordinate). This simplifies backend architecture from 18 to 8 core endpoints while maintaining identical UI/UX behavior.

All composables and pages now use coordinates + client-side grouping instead of specialized backend queries. For global product filtering, uses center point (0,0) with 20000km radius.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Ruslan Bakiev
2026-01-25 17:39:33 +07:00
parent 7403d4f063
commit 50375f2a74
6 changed files with 372 additions and 93 deletions

View File

@@ -1,8 +1,11 @@
import {
GetProductsDocument,
GetProductsBySupplierDocument,
GetProductsNearHubDocument
GetNodeDocument,
NearestOffersDocument
} from '~/composables/graphql/public/geo-generated'
import {
GetSupplierProfileDocument
} from '~/composables/graphql/public/exchange-generated'
// Shared state
const items = ref<any[]>([])
@@ -27,23 +30,89 @@ export function useCatalogProducts() {
let data
if (filterSupplierUuid.value) {
// Products from specific supplier
data = await execute(
GetProductsBySupplierDocument,
// Products from specific supplier - get supplier coordinates first
const supplierData = await execute(
GetSupplierProfileDocument,
{ supplierUuid: filterSupplierUuid.value },
'public',
'geo'
'exchange'
)
items.value = data?.productsBySupplier || []
const supplier = supplierData?.getSupplierProfile
if (!supplier?.latitude || !supplier?.longitude) {
console.warn('Supplier has no coordinates')
items.value = []
} else {
// Get offers near supplier and group by product
const offersData = await execute(
NearestOffersDocument,
{
lat: supplier.latitude,
lon: supplier.longitude,
radius: 500
},
'public',
'geo'
)
// Group offers by product
const productsMap = new Map<string, any>()
offersData?.nearestOffers?.forEach((offer: any) => {
if (offer?.productUuid) {
if (!productsMap.has(offer.productUuid)) {
productsMap.set(offer.productUuid, {
uuid: offer.productUuid,
name: offer.productName,
offersCount: 0
})
}
productsMap.get(offer.productUuid)!.offersCount++
}
})
items.value = Array.from(productsMap.values())
}
} else if (filterHubUuid.value) {
// Products near hub
data = await execute(
GetProductsNearHubDocument,
{ hubUuid: filterHubUuid.value },
// Products near hub - get hub coordinates first
const hubData = await execute(
GetNodeDocument,
{ uuid: filterHubUuid.value },
'public',
'geo'
)
items.value = data?.productsNearHub || []
const hub = hubData?.node
if (!hub?.latitude || !hub?.longitude) {
console.warn('Hub has no coordinates')
items.value = []
} else {
// Get offers near hub and group by product
const offersData = await execute(
NearestOffersDocument,
{
lat: hub.latitude,
lon: hub.longitude,
radius: 500
},
'public',
'geo'
)
// Group offers by product
const productsMap = new Map<string, any>()
offersData?.nearestOffers?.forEach((offer: any) => {
if (offer?.productUuid) {
if (!productsMap.has(offer.productUuid)) {
productsMap.set(offer.productUuid, {
uuid: offer.productUuid,
name: offer.productName,
offersCount: 0
})
}
productsMap.get(offer.productUuid)!.offersCount++
}
})
items.value = Array.from(productsMap.values())
}
} else {
// All products
data = await execute(