Refactor catalog to use coordinate-based GraphQL endpoints
All checks were successful
Build Docker Image / build (push) Successful in 3m33s
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:
@@ -1,11 +1,9 @@
|
||||
import type { InfoEntityType } from './useCatalogSearch'
|
||||
import {
|
||||
GetNodeDocument,
|
||||
GetProductsNearHubDocument,
|
||||
GetProductsBySupplierDocument,
|
||||
GetHubsNearOfferDocument,
|
||||
GetOffersByHubDocument,
|
||||
GetOffersBySupplierProductDocument
|
||||
NearestOffersDocument,
|
||||
NearestHubsDocument,
|
||||
RouteToCoordinateDocument
|
||||
} from '~/composables/graphql/public/geo-generated'
|
||||
import {
|
||||
GetOfferDocument,
|
||||
@@ -32,17 +30,41 @@ export function useCatalogInfo() {
|
||||
const nodeData = await execute(GetNodeDocument, { uuid }, 'public', 'geo')
|
||||
entity.value = nodeData?.node
|
||||
|
||||
// Load products near hub
|
||||
const productsData = await execute(
|
||||
GetProductsNearHubDocument,
|
||||
{ hubUuid: uuid, radiusKm: 500 },
|
||||
if (!entity.value?.latitude || !entity.value?.longitude) {
|
||||
console.warn('Hub has no coordinates')
|
||||
return
|
||||
}
|
||||
|
||||
// Load offers near hub and group by product
|
||||
const offersData = await execute(
|
||||
NearestOffersDocument,
|
||||
{
|
||||
lat: entity.value.latitude,
|
||||
lon: entity.value.longitude,
|
||||
radius: 500
|
||||
},
|
||||
'public',
|
||||
'geo'
|
||||
)
|
||||
relatedProducts.value = productsData?.productsNearHub || []
|
||||
|
||||
// Set default active tab to products
|
||||
activeTab.value = 'products'
|
||||
// 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++
|
||||
}
|
||||
})
|
||||
relatedProducts.value = Array.from(productsMap.values())
|
||||
|
||||
// Set default active tab to offers (first step shows products)
|
||||
activeTab.value = 'offers'
|
||||
|
||||
// Note: Suppliers loaded after product selection via loadOffersForHub
|
||||
} catch (error) {
|
||||
@@ -53,7 +75,7 @@ export function useCatalogInfo() {
|
||||
// Load supplier info: supplier details + products
|
||||
const loadSupplierInfo = async (uuid: string) => {
|
||||
try {
|
||||
// Load supplier node details
|
||||
// Load supplier node details (might be geo node)
|
||||
const nodeData = await execute(GetNodeDocument, { uuid }, 'public', 'geo')
|
||||
entity.value = nodeData?.node
|
||||
|
||||
@@ -72,17 +94,41 @@ export function useCatalogInfo() {
|
||||
// Supplier profile might not exist, ignore
|
||||
}
|
||||
|
||||
// Load products from supplier
|
||||
const productsData = await execute(
|
||||
GetProductsBySupplierDocument,
|
||||
{ supplierUuid: uuid },
|
||||
if (!entity.value?.latitude || !entity.value?.longitude) {
|
||||
console.warn('Supplier has no coordinates')
|
||||
return
|
||||
}
|
||||
|
||||
// Load offers near supplier and group by product
|
||||
const offersData = await execute(
|
||||
NearestOffersDocument,
|
||||
{
|
||||
lat: entity.value.latitude,
|
||||
lon: entity.value.longitude,
|
||||
radius: 500
|
||||
},
|
||||
'public',
|
||||
'geo'
|
||||
)
|
||||
relatedProducts.value = productsData?.productsBySupplier || []
|
||||
|
||||
// Set default active tab to products
|
||||
activeTab.value = 'products'
|
||||
// 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++
|
||||
}
|
||||
})
|
||||
relatedProducts.value = Array.from(productsMap.values())
|
||||
|
||||
// Set default active tab to offers (first step shows products)
|
||||
activeTab.value = 'offers'
|
||||
|
||||
// Note: Hubs will be loaded after product selection
|
||||
} catch (error) {
|
||||
@@ -97,14 +143,24 @@ export function useCatalogInfo() {
|
||||
const offerData = await execute(GetOfferDocument, { uuid }, 'public', 'exchange')
|
||||
entity.value = offerData?.getOffer
|
||||
|
||||
// Load hubs near offer
|
||||
if (!entity.value?.latitude || !entity.value?.longitude) {
|
||||
console.warn('Offer has no coordinates')
|
||||
return
|
||||
}
|
||||
|
||||
// Load hubs near offer coordinates
|
||||
const hubsData = await execute(
|
||||
GetHubsNearOfferDocument,
|
||||
{ offerUuid: uuid, limit: 12 },
|
||||
NearestHubsDocument,
|
||||
{
|
||||
lat: entity.value.latitude,
|
||||
lon: entity.value.longitude,
|
||||
radius: 1000,
|
||||
limit: 12
|
||||
},
|
||||
'public',
|
||||
'geo'
|
||||
)
|
||||
relatedHubs.value = hubsData?.hubsNearOffer || []
|
||||
relatedHubs.value = hubsData?.nearestHubs || []
|
||||
|
||||
// If offer has supplier UUID, load supplier profile
|
||||
if (entity.value?.teamUuid) {
|
||||
@@ -143,19 +199,73 @@ export function useCatalogInfo() {
|
||||
// Load offers for hub after product selection
|
||||
const loadOffersForHub = async (hubUuid: string, productUuid: string) => {
|
||||
try {
|
||||
const hub = entity.value
|
||||
if (!hub?.latitude || !hub?.longitude) {
|
||||
console.warn('Hub has no coordinates')
|
||||
return
|
||||
}
|
||||
|
||||
// 1. Find offers near hub for this product
|
||||
const offersData = await execute(
|
||||
GetOffersByHubDocument,
|
||||
{ hubUuid, productUuid, limit: 12 },
|
||||
NearestOffersDocument,
|
||||
{
|
||||
lat: hub.latitude,
|
||||
lon: hub.longitude,
|
||||
productUuid,
|
||||
radius: 500,
|
||||
limit: 12
|
||||
},
|
||||
'public',
|
||||
'geo'
|
||||
)
|
||||
relatedOffers.value = offersData?.offersByHub || []
|
||||
|
||||
// Extract unique suppliers from offers
|
||||
const offers = offersData?.nearestOffers || []
|
||||
|
||||
// 2. For each offer, get route to hub
|
||||
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 {
|
||||
...offer,
|
||||
sourceUuid: offer.uuid,
|
||||
sourceName: offer.productName,
|
||||
sourceLat: offer.latitude,
|
||||
sourceLon: offer.longitude,
|
||||
distanceKm: routeData?.routeToCoordinate?.distanceKm,
|
||||
routes: routeData?.routeToCoordinate?.routes || []
|
||||
}
|
||||
} catch (e) {
|
||||
// Route might not exist
|
||||
console.warn('No route found for offer:', offer.uuid, e)
|
||||
return {
|
||||
...offer,
|
||||
sourceUuid: offer.uuid,
|
||||
sourceName: offer.productName,
|
||||
sourceLat: offer.latitude,
|
||||
sourceLon: offer.longitude,
|
||||
routes: []
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
relatedOffers.value = offersWithRoutes
|
||||
|
||||
// Extract unique suppliers from offers (use supplierUuid from offers)
|
||||
const supplierUuids = new Set<string>()
|
||||
relatedOffers.value.forEach((offer: any) => {
|
||||
if (offer.teamUuid) {
|
||||
supplierUuids.add(offer.teamUuid)
|
||||
offersWithRoutes.forEach((offer: any) => {
|
||||
if (offer.supplierUuid) {
|
||||
supplierUuids.add(offer.supplierUuid)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -185,32 +295,53 @@ export function useCatalogInfo() {
|
||||
// Load offers for supplier after product selection
|
||||
const loadOffersForSupplier = async (supplierUuid: string, productUuid: string) => {
|
||||
try {
|
||||
const supplier = entity.value
|
||||
if (!supplier?.latitude || !supplier?.longitude) {
|
||||
console.warn('Supplier has no coordinates')
|
||||
return
|
||||
}
|
||||
|
||||
// Find offers near supplier for this product
|
||||
const offersData = await execute(
|
||||
GetOffersBySupplierProductDocument,
|
||||
{ supplierUuid, productUuid },
|
||||
NearestOffersDocument,
|
||||
{
|
||||
lat: supplier.latitude,
|
||||
lon: supplier.longitude,
|
||||
productUuid,
|
||||
radius: 500,
|
||||
limit: 12
|
||||
},
|
||||
'public',
|
||||
'geo'
|
||||
)
|
||||
relatedOffers.value = offersData?.offersBySupplierProduct || []
|
||||
|
||||
// Load hubs for each offer and aggregate (limit to 12)
|
||||
relatedOffers.value = offersData?.nearestOffers || []
|
||||
|
||||
// Load hubs near each offer and aggregate (limit to 12)
|
||||
const allHubs = new Map<string, any>()
|
||||
for (const offer of relatedOffers.value.slice(0, 3)) {
|
||||
// Check first 3 offers
|
||||
if (!offer.latitude || !offer.longitude) continue
|
||||
|
||||
try {
|
||||
const hubsData = await execute(
|
||||
GetHubsNearOfferDocument,
|
||||
{ offerUuid: offer.uuid, limit: 5 },
|
||||
NearestHubsDocument,
|
||||
{
|
||||
lat: offer.latitude,
|
||||
lon: offer.longitude,
|
||||
radius: 1000,
|
||||
limit: 5
|
||||
},
|
||||
'public',
|
||||
'geo'
|
||||
)
|
||||
hubsData?.hubsNearOffer?.forEach((hub: any) => {
|
||||
hubsData?.nearestHubs?.forEach((hub: any) => {
|
||||
if (!allHubs.has(hub.uuid)) {
|
||||
allHubs.set(hub.uuid, hub)
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
// Hubs might not exist for this offer
|
||||
console.warn('Error loading hubs for offer:', offer.uuid, e)
|
||||
}
|
||||
|
||||
if (allHubs.size >= 12) break
|
||||
|
||||
Reference in New Issue
Block a user