refactor: remove any types and fix TypeScript errors
All checks were successful
Build Docker Image / build (push) Successful in 3m59s

- Export InfoProductItem, InfoHubItem, InfoSupplierItem, InfoOfferItem types
- Update InfoEntity interface to have explicit fields (no index signature)
- Export CatalogHubItem, CatalogNearestHubItem from useCatalogHubs
- Fix MapItem interfaces to accept nullable GraphQL types
- Fix v-for :key bindings to handle null uuid
- Add null guards in select-location pages
- Update HubCard to accept nullable transportTypes
- Add shims.d.ts for missing module declarations
This commit is contained in:
Ruslan Bakiev
2026-01-27 10:35:14 +07:00
parent 9210f79a3d
commit 20e0e73c58
9 changed files with 133 additions and 69 deletions

View File

@@ -20,11 +20,11 @@ import { LngLatBounds } from 'mapbox-gl'
import type { ClusterPointType } from '~/composables/graphql/public/geo-generated'
interface MapItem {
uuid: string
name: string
latitude: number
longitude: number
country?: string
uuid?: string | null
name?: string | null
latitude?: number | null
longitude?: number | null
country?: string | null
}
export interface MapBounds {
@@ -186,11 +186,13 @@ const mapOptions = computed(() => ({
// Client-side clustering GeoJSON (when not using server clustering)
const geoJsonData = computed(() => ({
type: 'FeatureCollection' as const,
features: props.items.map(item => ({
type: 'Feature' as const,
properties: { uuid: item.uuid, name: item.name, country: item.country },
geometry: { type: 'Point' as const, coordinates: [item.longitude, item.latitude] }
}))
features: props.items
.filter(item => item.latitude != null && item.longitude != null)
.map(item => ({
type: 'Feature' as const,
properties: { uuid: item.uuid, name: item.name, country: item.country },
geometry: { type: 'Point' as const, coordinates: [item.longitude!, item.latitude!] }
}))
}))
// Server-side clustering GeoJSON
@@ -481,7 +483,9 @@ const initClientClusteringLayers = async (map: MapboxMapType) => {
if (!didFitBounds.value && props.items.length > 0) {
const bounds = new LngLatBounds()
props.items.forEach(item => {
bounds.extend([item.longitude, item.latitude])
if (item.longitude != null && item.latitude != null) {
bounds.extend([item.longitude, item.latitude])
}
})
map.fitBounds(bounds, { padding: 50, maxZoom: 10 })
didFitBounds.value = true

View File

@@ -48,7 +48,7 @@ interface Hub {
country?: string | null
countryCode?: string | null
distance?: string
transportTypes?: string[] | null
transportTypes?: (string | null)[] | null
}
const props = defineProps<{
@@ -81,5 +81,5 @@ const countryFlag = computed(() => {
return '🌍'
})
const hasTransport = (type: string) => props.hub.transportTypes?.includes(type)
const hasTransport = (type: string) => props.hub.transportTypes?.some(t => t === type)
</script>

View File

@@ -48,7 +48,7 @@
@click="emit('open-info', 'supplier', entity.teamUuid)"
>
<Icon name="lucide:factory" size="14" />
{{ entity.teamName || $t('catalog.info.viewSupplier') }}
{{ entity.supplierName || entity.teamName || $t('catalog.info.viewSupplier') }}
</button>
</div>
@@ -66,8 +66,8 @@
</div>
<div v-else-if="!loadingProducts" class="flex flex-col gap-2">
<ProductCard
v-for="product in relatedProducts"
:key="product.uuid"
v-for="(product, index) in relatedProducts"
:key="product.uuid ?? index"
:product="product"
compact
selectable
@@ -90,8 +90,8 @@
</div>
<div v-else-if="!loadingSuppliers" class="flex flex-col gap-2">
<SupplierCard
v-for="supplier in relatedSuppliers"
:key="supplier.uuid"
v-for="(supplier, index) in relatedSuppliers"
:key="supplier.uuid ?? index"
:supplier="supplier"
selectable
@select="onSupplierSelect(supplier)"
@@ -113,8 +113,8 @@
</div>
<div v-else-if="!loadingHubs" class="flex flex-col gap-2">
<HubCard
v-for="hub in relatedHubs"
:key="hub.uuid"
v-for="(hub, index) in relatedHubs"
:key="hub.uuid ?? index"
:hub="hub"
selectable
@select="onHubSelect(hub)"
@@ -134,15 +134,22 @@
<script setup lang="ts">
import type { InfoEntityType } from '~/composables/useCatalogSearch'
import type {
InfoEntity,
InfoProductItem,
InfoHubItem,
InfoSupplierItem,
InfoOfferItem
} from '~/composables/useCatalogInfo'
const props = defineProps<{
entityType: InfoEntityType
entityId: string
entity: any
relatedProducts?: any[]
relatedHubs?: any[]
relatedSuppliers?: any[]
relatedOffers?: any[]
entity: InfoEntity | null
relatedProducts?: InfoProductItem[]
relatedHubs?: InfoHubItem[]
relatedSuppliers?: InfoSupplierItem[]
relatedOffers?: InfoOfferItem[]
selectedProduct?: string | null
currentTab?: string
loading?: boolean
@@ -209,20 +216,17 @@ const formatPrice = (price: number | string) => {
}
// Handlers for selecting related items
const onProductSelect = (product: any) => {
if (product.uuid) {
// Navigate to offer info for this product
emit('select-product', product.uuid)
}
const onProductSelect = (product: InfoProductItem) => {
emit('select-product', product.uuid)
}
const onHubSelect = (hub: any) => {
const onHubSelect = (hub: InfoHubItem) => {
if (hub.uuid) {
emit('open-info', 'hub', hub.uuid)
}
}
const onSupplierSelect = (supplier: any) => {
const onSupplierSelect = (supplier: InfoSupplierItem) => {
if (supplier.uuid) {
emit('open-info', 'supplier', supplier.uuid)
}

View File

@@ -233,12 +233,11 @@ const activeClusterNodeType = computed(() => VIEW_MODE_NODE_TYPES[mapViewMode.va
const currentBounds = ref<MapBounds | null>(null)
interface MapItem {
uuid: string
uuid?: string | null
latitude?: number | null
longitude?: number | null
name?: string
country?: string
[key: string]: any
name?: string | null
country?: string | null
}
const props = withDefaults(defineProps<{