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

@@ -64,7 +64,7 @@
</template>
<script setup lang="ts">
import { GetOffersByHubDocument } from '~/composables/graphql/public/geo-generated'
import { GetNodeDocument, NearestOffersDocument, RouteToCoordinateDocument } from '~/composables/graphql/public/geo-generated'
import type { RouteStageItem } from '~/components/RouteStagesList.vue'
import { GetOfferDocument, GetSupplierProfileByTeamDocument } from '~/composables/graphql/public/exchange-generated'
@@ -106,17 +106,68 @@ type ProductRouteOption = {
const fetchOffersByHub = async () => {
if (!productUuid.value || !destinationUuid.value) return null
const { client } = useApolloClient('publicGeo')
const { data } = await client.query({
query: GetOffersByHubDocument,
variables: {
hubUuid: destinationUuid.value,
// 1. Get hub node to get coordinates
const hubData = await execute(GetNodeDocument, { uuid: destinationUuid.value }, 'public', 'geo')
const hub = hubData?.node
if (!hub?.latitude || !hub?.longitude) {
console.warn('Hub has no coordinates')
return null
}
// 2. Find offers near hub for this product
const offersData = await execute(
NearestOffersDocument,
{
lat: hub.latitude,
lon: hub.longitude,
productUuid: productUuid.value,
radius: 500,
limit: 5
}
})
return data
},
'public',
'geo'
)
const offers = offersData?.nearestOffers || []
// 3. For each offer, get route to hub coordinates
const offersWithRoutes = await Promise.all(
offers.map(async (offer: any) => {
try {
const routeData = await execute(
RouteToCoordinateDocument,
{
offerUuid: offer.uuid,
lat: hub.latitude,
lon: hub.longitude
},
'public',
'geo'
)
return {
sourceUuid: offer.uuid,
sourceName: offer.productName,
sourceLat: offer.latitude,
sourceLon: offer.longitude,
distanceKm: routeData?.routeToCoordinate?.distanceKm,
routes: routeData?.routeToCoordinate?.routes || []
}
} catch (e) {
console.warn('No route found for offer:', offer.uuid, e)
return {
sourceUuid: offer.uuid,
sourceName: offer.productName,
sourceLat: offer.latitude,
sourceLon: offer.longitude,
routes: []
}
}
})
)
return { offersByHub: offersWithRoutes }
}
const { data: productRoutesData, pending, error } = await useAsyncData(