import type { InfoEntityType } from './useCatalogSearch' import { GetNodeDocument, NearestOffersDocument, NearestHubsDocument, RouteToCoordinateDocument } from '~/composables/graphql/public/geo-generated' import { GetOfferDocument, GetSupplierProfileDocument } from '~/composables/graphql/public/exchange-generated' export function useCatalogInfo() { const { execute } = useGraphQL() // State const entity = ref(null) const relatedProducts = ref([]) const relatedHubs = ref([]) const relatedSuppliers = ref([]) const relatedOffers = ref([]) const selectedProduct = ref(null) const activeTab = ref('products') const isLoading = ref(false) // Load hub info: hub details + products + suppliers const loadHubInfo = async (uuid: string) => { try { // Load hub node details const nodeData = await execute(GetNodeDocument, { uuid }, 'public', 'geo') entity.value = nodeData?.node 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' ) // Group offers by product const productsMap = new Map() 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) { console.error('Error loading hub info:', error) } } // Load supplier info: supplier details + products const loadSupplierInfo = async (uuid: string) => { try { // Load supplier node details (might be geo node) const nodeData = await execute(GetNodeDocument, { uuid }, 'public', 'geo') entity.value = nodeData?.node // Also try to get supplier profile from exchange API for additional details try { const profileData = await execute( GetSupplierProfileDocument, { uuid }, 'public', 'exchange' ) if (profileData?.getSupplierProfile) { entity.value = { ...entity.value, ...profileData.getSupplierProfile } } } catch (e) { // Supplier profile might not exist, ignore } 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' ) // Group offers by product const productsMap = new Map() 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) { console.error('Error loading supplier info:', error) } } // Load offer info: offer details + supplier + hubs const loadOfferInfo = async (uuid: string) => { try { // Load offer details from exchange API const offerData = await execute(GetOfferDocument, { uuid }, 'public', 'exchange') entity.value = offerData?.getOffer if (!entity.value?.latitude || !entity.value?.longitude) { console.warn('Offer has no coordinates') return } // Load hubs near offer coordinates const hubsData = await execute( NearestHubsDocument, { lat: entity.value.latitude, lon: entity.value.longitude, radius: 1000, limit: 12 }, 'public', 'geo' ) relatedHubs.value = hubsData?.nearestHubs || [] // If offer has supplier UUID, load supplier profile if (entity.value?.teamUuid) { try { const supplierData = await execute( GetSupplierProfileDocument, { uuid: entity.value.teamUuid }, 'public', 'exchange' ) relatedSuppliers.value = supplierData?.getSupplierProfile ? [supplierData.getSupplierProfile] : [] } catch (e) { // Supplier might not exist } } // Set default active tab to hubs activeTab.value = 'hubs' // Set product as "related product" (single item) if (entity.value?.productUuid && entity.value?.productName) { relatedProducts.value = [ { uuid: entity.value.productUuid, name: entity.value.productName } ] } } catch (error) { console.error('Error loading offer info:', error) } } // 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( NearestOffersDocument, { lat: hub.latitude, lon: hub.longitude, productUuid, radius: 500, limit: 12 }, 'public', 'geo' ) 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() offersWithRoutes.forEach((offer: any) => { if (offer.supplierUuid) { supplierUuids.add(offer.supplierUuid) } }) // Load supplier profiles (limit to 12) const suppliers: any[] = [] for (const uuid of Array.from(supplierUuids).slice(0, 12)) { try { const supplierData = await execute( GetSupplierProfileDocument, { uuid }, 'public', 'exchange' ) if (supplierData?.getSupplierProfile) { suppliers.push(supplierData.getSupplierProfile) } } catch (e) { // Supplier might not exist } } relatedSuppliers.value = suppliers } catch (error) { console.error('Error loading offers for hub:', error) } } // 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( NearestOffersDocument, { lat: supplier.latitude, lon: supplier.longitude, productUuid, radius: 500, limit: 12 }, 'public', 'geo' ) relatedOffers.value = offersData?.nearestOffers || [] // Load hubs near each offer and aggregate (limit to 12) const allHubs = new Map() 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: any) => { if (!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) } catch (error) { console.error('Error loading offers for supplier:', error) } } // Select product (triggers offers loading) const selectProduct = async (productUuid: string) => { selectedProduct.value = productUuid if (!entity.value) return const entityType = entity.value.uuid if (!entityType) return // Load offers based on entity type if (entity.value.transportTypes) { // This is a hub (has transportTypes) await loadOffersForHub(entity.value.uuid, productUuid) activeTab.value = 'offers' } else if (entity.value.teamUuid || entity.value.onTimeRate !== undefined) { // This is a supplier await loadOffersForSupplier(entity.value.uuid, productUuid) activeTab.value = 'offers' } } // Set active tab const setActiveTab = (tab: string) => { activeTab.value = tab } // Main load method - dispatches to specific loaders const loadInfo = async (type: InfoEntityType, uuid: string) => { isLoading.value = true clearInfo() // Clear previous data try { if (type === 'hub') { await loadHubInfo(uuid) } else if (type === 'supplier') { await loadSupplierInfo(uuid) } else if (type === 'offer') { await loadOfferInfo(uuid) } } finally { isLoading.value = false } } // Clear all info data const clearInfo = () => { entity.value = null relatedProducts.value = [] relatedHubs.value = [] relatedSuppliers.value = [] relatedOffers.value = [] selectedProduct.value = null activeTab.value = 'products' } return { // State entity, relatedProducts, relatedHubs, relatedSuppliers, relatedOffers, selectedProduct, activeTab, isLoading, // Actions loadInfo, selectProduct, setActiveTab, clearInfo } }