Fix all TypeScript errors and remove Storybook
All checks were successful
Build Docker Image / build (push) Successful in 5m8s
All checks were successful
Build Docker Image / build (push) Successful in 5m8s
- Remove all Storybook files and configuration - Add type declarations for @vueuse/core, @formkit/core, vue3-apexcharts - Fix TypeScript configuration (typeRoots, include paths) - Fix Sentry config - move settings to plugin - Fix nullable prop assignments with ?? operator - Fix type narrowing issues with explicit type assertions - Fix Card component linkable computed properties - Update codegen with operationResultSuffix - Fix GraphQL operation type definitions
This commit is contained in:
@@ -48,5 +48,5 @@ defineEmits<{
|
||||
const localePath = useLocalePath()
|
||||
const { t } = useI18n()
|
||||
|
||||
const linkable = computed(() => !props.selectable && props.address.uuid)
|
||||
const linkable = computed(() => !props.selectable && !!props.address.uuid)
|
||||
</script>
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
<Text weight="semibold" class="mb-3">{{ country.name }}</Text>
|
||||
<Grid :cols="1" :md="2" :lg="3" :gap="4">
|
||||
<HubCard
|
||||
v-for="hub in country.hubs"
|
||||
:key="hub.uuid"
|
||||
v-for="(hub, index) in country.hubs"
|
||||
:key="hub.uuid ?? index"
|
||||
:hub="hub"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
@@ -319,20 +319,22 @@ const initClientClusteringLayers = async (map: MapboxMapType) => {
|
||||
|
||||
map.on('click', 'clusters', (e) => {
|
||||
const features = map.queryRenderedFeatures(e.point, { layers: ['clusters'] })
|
||||
if (!features.length) return
|
||||
const clusterId = features[0].properties?.cluster_id
|
||||
const feature = features[0]
|
||||
if (!feature) return
|
||||
const clusterId = feature.properties?.cluster_id
|
||||
const source = map.getSource(sourceId.value) as mapboxgl.GeoJSONSource
|
||||
source.getClusterExpansionZoom(clusterId, (err, zoom) => {
|
||||
if (err) return
|
||||
const geometry = features[0].geometry as GeoJSON.Point
|
||||
const geometry = feature.geometry as GeoJSON.Point
|
||||
map.easeTo({ center: geometry.coordinates as [number, number], zoom: zoom || 4 })
|
||||
})
|
||||
})
|
||||
|
||||
map.on('click', 'unclustered-point', (e) => {
|
||||
const features = map.queryRenderedFeatures(e.point, { layers: ['unclustered-point'] })
|
||||
if (!features.length) return
|
||||
emit('select-item', features[0].properties?.uuid)
|
||||
const feature = features[0]
|
||||
if (!feature) return
|
||||
emit('select-item', feature.properties?.uuid)
|
||||
})
|
||||
|
||||
map.on('mouseenter', 'clusters', () => { map.getCanvas().style.cursor = 'pointer' })
|
||||
@@ -406,8 +408,9 @@ const initClientClusteringLayers = async (map: MapboxMapType) => {
|
||||
// Click handlers for related points
|
||||
map.on('click', `${props.mapId}-related-circles`, (e) => {
|
||||
const features = map.queryRenderedFeatures(e.point, { layers: [`${props.mapId}-related-circles`] })
|
||||
if (!features.length) return
|
||||
const props_data = features[0].properties
|
||||
const feature = features[0]
|
||||
if (!feature) return
|
||||
const props_data = feature.properties as Record<string, any> | undefined
|
||||
emit('select-item', props_data?.uuid, props_data)
|
||||
})
|
||||
|
||||
@@ -500,9 +503,10 @@ const initServerClusteringLayers = async (map: MapboxMapType) => {
|
||||
// Click on cluster to zoom in
|
||||
map.on('click', 'server-clusters', (e) => {
|
||||
const features = map.queryRenderedFeatures(e.point, { layers: ['server-clusters'] })
|
||||
if (!features.length) return
|
||||
const expansionZoom = features[0].properties?.expansionZoom
|
||||
const geometry = features[0].geometry as GeoJSON.Point
|
||||
const feature = features[0]
|
||||
if (!feature) return
|
||||
const expansionZoom = feature.properties?.expansionZoom
|
||||
const geometry = feature.geometry as GeoJSON.Point
|
||||
map.easeTo({
|
||||
center: geometry.coordinates as [number, number],
|
||||
zoom: expansionZoom || map.getZoom() + 2
|
||||
@@ -512,8 +516,9 @@ const initServerClusteringLayers = async (map: MapboxMapType) => {
|
||||
// Click on individual point - emit full properties
|
||||
map.on('click', 'server-points', (e) => {
|
||||
const features = map.queryRenderedFeatures(e.point, { layers: ['server-points'] })
|
||||
if (!features.length) return
|
||||
const props = features[0].properties || {}
|
||||
const feature = features[0]
|
||||
if (!feature) return
|
||||
const props = feature.properties || {}
|
||||
emit('select-item', props.id, props)
|
||||
})
|
||||
|
||||
@@ -588,8 +593,9 @@ const initServerClusteringLayers = async (map: MapboxMapType) => {
|
||||
// Click handlers for related points
|
||||
map.on('click', `${props.mapId}-related-circles`, (e) => {
|
||||
const features = map.queryRenderedFeatures(e.point, { layers: [`${props.mapId}-related-circles`] })
|
||||
if (!features.length) return
|
||||
const props_data = features[0].properties
|
||||
const feature = features[0]
|
||||
if (!feature) return
|
||||
const props_data = feature.properties as Record<string, any> | undefined
|
||||
emit('select-item', props_data?.uuid, props_data)
|
||||
})
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
<!-- Hubs Tab -->
|
||||
<template v-if="activeTab === 'hubs'">
|
||||
<HubCard
|
||||
v-for="hub in hubs"
|
||||
:key="hub.uuid"
|
||||
v-for="(hub, index) in hubs"
|
||||
:key="hub.uuid ?? index"
|
||||
:hub="hub"
|
||||
selectable
|
||||
:is-selected="selectedId === hub.uuid"
|
||||
@@ -38,8 +38,8 @@
|
||||
<!-- Offers Tab -->
|
||||
<template v-if="activeTab === 'offers'">
|
||||
<OfferCard
|
||||
v-for="offer in offers"
|
||||
:key="offer.uuid"
|
||||
v-for="(offer, index) in offers"
|
||||
:key="offer.uuid ?? index"
|
||||
:offer="offer"
|
||||
selectable
|
||||
compact
|
||||
@@ -54,8 +54,8 @@
|
||||
<!-- Suppliers Tab -->
|
||||
<template v-if="activeTab === 'suppliers'">
|
||||
<SupplierCard
|
||||
v-for="supplier in suppliers"
|
||||
:key="supplier.uuid"
|
||||
v-for="(supplier, index) in suppliers"
|
||||
:key="supplier.uuid ?? index"
|
||||
:supplier="supplier"
|
||||
selectable
|
||||
:is-selected="selectedId === supplier.uuid"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<div v-if="filters && filters.length > 0" class="p-4 border-b border-base-300">
|
||||
<CatalogFilters
|
||||
:filters="filters"
|
||||
:model-value="selectedFilter"
|
||||
:model-value="selectedFilter ?? 'all'"
|
||||
@update:model-value="$emit('update:selectedFilter', $event)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
<Grid :cols="1" :md="2" :lg="3" :gap="4">
|
||||
<OfferCard
|
||||
v-for="offer in offers"
|
||||
:key="offer.uuid"
|
||||
v-for="(offer, index) in offers"
|
||||
:key="offer.uuid ?? index"
|
||||
:offer="offer"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
<Grid :cols="1" :md="2" :lg="3" :gap="4">
|
||||
<SupplierCard
|
||||
v-for="supplier in suppliers"
|
||||
:key="supplier.uuid"
|
||||
v-for="(supplier, index) in suppliers"
|
||||
:key="supplier.uuid ?? index"
|
||||
:supplier="supplier"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
@@ -66,7 +66,7 @@ defineEmits<{
|
||||
const localePath = useLocalePath()
|
||||
const { t } = useI18n()
|
||||
|
||||
const linkable = computed(() => !props.selectable && (props.linkTo || props.hub.uuid))
|
||||
const linkable = computed(() => !props.selectable && !!(props.linkTo || props.hub.uuid))
|
||||
const resolvedLink = computed(() => props.linkTo || localePath(`/catalog/hubs/${props.hub.uuid}`))
|
||||
|
||||
// ISO code to emoji flag
|
||||
|
||||
@@ -76,7 +76,7 @@ const trend = computed(() => {
|
||||
if (props.priceHistory.length < 2) return 0
|
||||
const first = props.priceHistory[0]
|
||||
const last = props.priceHistory[props.priceHistory.length - 1]
|
||||
if (!first || first === 0) return 0
|
||||
if (!first || first === 0 || !last) return 0
|
||||
return Math.round(((last - first) / first) * 100)
|
||||
})
|
||||
|
||||
|
||||
@@ -186,12 +186,18 @@ const emit = defineEmits<{
|
||||
'close': []
|
||||
'add-to-filter': []
|
||||
'open-info': [type: InfoEntityType, uuid: string]
|
||||
'select-product': [uuid: string]
|
||||
'select-product': [uuid: string | null]
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const { entityColors } = useCatalogSearch()
|
||||
|
||||
// Safe accessors for optional arrays
|
||||
const relatedProducts = computed(() => props.relatedProducts ?? [])
|
||||
const relatedHubs = computed(() => props.relatedHubs ?? [])
|
||||
const relatedSuppliers = computed(() => props.relatedSuppliers ?? [])
|
||||
const relatedOffers = computed(() => props.relatedOffers ?? [])
|
||||
|
||||
// Current active tab
|
||||
const currentTab = ref<string>('offers')
|
||||
|
||||
@@ -279,8 +285,9 @@ const availableTabs = computed(() => {
|
||||
watch(
|
||||
() => props.entityType,
|
||||
() => {
|
||||
if (availableTabs.value.length > 0) {
|
||||
currentTab.value = availableTabs.value[0].id
|
||||
const firstTab = availableTabs.value[0]
|
||||
if (firstTab) {
|
||||
currentTab.value = firstTab.id
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
|
||||
@@ -73,7 +73,7 @@ defineEmits<{
|
||||
const localePath = useLocalePath()
|
||||
const { t } = useI18n()
|
||||
|
||||
const linkable = computed(() => !props.selectable && props.offer.uuid)
|
||||
const linkable = computed(() => !props.selectable && !!props.offer.uuid)
|
||||
|
||||
const formattedDate = computed(() => {
|
||||
if (!props.offer.validUntil) return ''
|
||||
|
||||
@@ -23,7 +23,9 @@ const props = defineProps<{
|
||||
|
||||
const isUptrend = computed(() => {
|
||||
if (props.data.length < 2) return true
|
||||
return props.data[props.data.length - 1] >= props.data[0]
|
||||
const last = props.data[props.data.length - 1]
|
||||
const first = props.data[0]
|
||||
return (last ?? 0) >= (first ?? 0)
|
||||
})
|
||||
|
||||
const lineColor = computed(() => isUptrend.value ? '#22c55e' : '#ef4444')
|
||||
|
||||
@@ -48,5 +48,5 @@ defineEmits<{
|
||||
const localePath = useLocalePath()
|
||||
const { t } = useI18n()
|
||||
|
||||
const linkable = computed(() => !props.selectable && props.product.uuid)
|
||||
const linkable = computed(() => !props.selectable && !!props.product.uuid)
|
||||
</script>
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
<!-- Products -->
|
||||
<template v-if="selectMode === 'product'">
|
||||
<div
|
||||
v-for="item in filteredItems"
|
||||
:key="item.uuid"
|
||||
@mouseenter="emit('hover', item.uuid)"
|
||||
v-for="(item, index) in filteredItems"
|
||||
:key="item.uuid ?? index"
|
||||
@mouseenter="emit('hover', item.uuid ?? null)"
|
||||
@mouseleave="emit('hover', null)"
|
||||
>
|
||||
<ProductCard
|
||||
@@ -47,9 +47,9 @@
|
||||
<!-- Hubs -->
|
||||
<template v-else-if="selectMode === 'hub'">
|
||||
<div
|
||||
v-for="item in filteredItems"
|
||||
:key="item.uuid"
|
||||
@mouseenter="emit('hover', item.uuid)"
|
||||
v-for="(item, index) in filteredItems"
|
||||
:key="item.uuid ?? index"
|
||||
@mouseenter="emit('hover', item.uuid ?? null)"
|
||||
@mouseleave="emit('hover', null)"
|
||||
>
|
||||
<HubCard
|
||||
@@ -64,9 +64,9 @@
|
||||
<!-- Suppliers -->
|
||||
<template v-else-if="selectMode === 'supplier'">
|
||||
<div
|
||||
v-for="item in filteredItems"
|
||||
:key="item.uuid"
|
||||
@mouseenter="emit('hover', item.uuid)"
|
||||
v-for="(item, index) in filteredItems"
|
||||
:key="item.uuid ?? index"
|
||||
@mouseenter="emit('hover', item.uuid ?? null)"
|
||||
@mouseleave="emit('hover', null)"
|
||||
>
|
||||
<SupplierCard
|
||||
|
||||
@@ -71,7 +71,7 @@ defineEmits<{
|
||||
const localePath = useLocalePath()
|
||||
const { t } = useI18n()
|
||||
|
||||
const linkable = computed(() => !props.selectable && props.supplier.uuid)
|
||||
const linkable = computed(() => !props.selectable && !!props.supplier.uuid)
|
||||
|
||||
const reliabilityLabel = computed(() => {
|
||||
if (props.supplier.onTimeRate !== undefined && props.supplier.onTimeRate !== null) {
|
||||
|
||||
Reference in New Issue
Block a user