Simplify OfferResultCard and use daisyUI Steps
All checks were successful
Build Docker Image / build (push) Successful in 4m42s

- Remove sourceName, latitude, longitude props from OfferResultCard
- Remove LocationMiniMap component (not needed, main map is on the side)
- Convert RouteStepper to use daisyUI steps-horizontal
- Update hub page and CalcResultContent to remove unused props
This commit is contained in:
Ruslan Bakiev
2026-01-15 00:33:17 +07:00
parent f03554893b
commit 0337cebc63
5 changed files with 19 additions and 143 deletions

View File

@@ -20,14 +20,11 @@
<OfferResultCard
v-for="option in productRouteOptions"
:key="option.sourceUuid"
:source-name="option.sourceName || 'Склад'"
:location-name="getOfferData(option.sourceUuid)?.locationName"
:product-name="productName"
:price-per-unit="getOfferData(option.sourceUuid)?.pricePerUnit"
:currency="getOfferData(option.sourceUuid)?.currency"
:unit="getOfferData(option.sourceUuid)?.unit"
:latitude="option.sourceLat"
:longitude="option.sourceLon"
:stages="getRouteStages(option)"
/>
</div>

View File

@@ -1,103 +0,0 @@
<template>
<div class="rounded-lg overflow-hidden border border-base-300">
<ClientOnly>
<MapboxMap
:key="mapId"
:map-id="mapId"
:style="`height: ${height}px; width: 100%;`"
:options="mapOptions"
@load="onMapCreated"
/>
<template #fallback>
<div :style="`height: ${height}px`" class="w-full bg-base-200 flex items-center justify-center">
<span class="loading loading-spinner loading-xs"></span>
</div>
</template>
</ClientOnly>
</div>
</template>
<script setup lang="ts">
import type { Map as MapboxMapType } from 'mapbox-gl'
import { getCurrentInstance } from 'vue'
const props = withDefaults(defineProps<{
latitude: number
longitude: number
height?: number
}>(), {
height: 120
})
const mapRef = ref<MapboxMapType | null>(null)
const instanceId = getCurrentInstance()?.uid || Math.floor(Math.random() * 100000)
const mapId = computed(() => `location-mini-map-${instanceId}`)
const mapOptions = computed(() => ({
style: 'mapbox://styles/mapbox/streets-v12',
center: [props.longitude, props.latitude] as [number, number],
zoom: 5,
interactive: false,
attributionControl: false
}))
const onMapCreated = (map: MapboxMapType) => {
mapRef.value = map
const initMap = () => {
map.addSource('location-point', {
type: 'geojson',
data: {
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [props.longitude, props.latitude]
}
}
})
map.addLayer({
id: 'location-point-layer',
type: 'circle',
source: 'location-point',
paint: {
'circle-radius': 8,
'circle-color': '#10b981',
'circle-stroke-width': 2,
'circle-stroke-color': '#ffffff'
}
})
}
if (map.loaded()) {
initMap()
} else {
map.on('load', initMap)
}
}
watch(
() => [props.latitude, props.longitude],
() => {
const map = mapRef.value
if (!map) return
map.setCenter([props.longitude, props.latitude])
const source = map.getSource('location-point') as mapboxgl.GeoJSONSource | undefined
if (source) {
source.setData({
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [props.longitude, props.latitude]
}
})
}
}
)
</script>

View File

@@ -1,32 +1,18 @@
<template>
<Card padding="md" interactive @click="$emit('select')">
<!-- Header: Source name + Location + Price -->
<!-- Header: Location + Price -->
<div class="flex items-start justify-between mb-3">
<div>
<Text weight="semibold">{{ sourceName }}</Text>
<Text v-if="locationName" tone="muted" size="sm">{{ locationName }}</Text>
<Text weight="semibold">{{ locationName || 'Локация' }}</Text>
<Text v-if="productName" tone="muted" size="sm">{{ productName }}</Text>
</div>
<div class="text-right">
<Text v-if="priceDisplay" weight="semibold" class="text-primary text-lg">
{{ priceDisplay }}
</Text>
</div>
</div>
<!-- Product name + Route stepper -->
<div v-if="productName" class="mb-3">
<Text size="sm" class="mb-1">{{ productName }}</Text>
<!-- Route stepper -->
<RouteStepper v-if="stages.length > 0" :stages="stages" />
</div>
<RouteStepper v-else-if="stages.length > 0" :stages="stages" class="mb-3" />
<!-- Mini map -->
<LocationMiniMap
v-if="latitude && longitude"
:latitude="latitude"
:longitude="longitude"
:height="100"
/>
</Card>
</template>
@@ -34,14 +20,11 @@
import type { RouteStage } from './RouteStepper.vue'
const props = withDefaults(defineProps<{
sourceName: string
locationName?: string
productName?: string
pricePerUnit?: number | null
currency?: string | null
unit?: string | null
latitude?: number | null
longitude?: number | null
stages?: RouteStage[]
}>(), {
stages: () => []

View File

@@ -1,13 +1,14 @@
<template>
<div class="flex items-center gap-1 flex-wrap text-xs">
<template v-for="(stage, index) in stages" :key="index">
<div v-if="index > 0" class="w-3 h-px bg-base-300" />
<div class="flex items-center gap-0.5">
<span>{{ getTransportIcon(stage.transportType) }}</span>
<span class="text-base-content/70">{{ formatDistance(stage.distanceKm) }}км</span>
</div>
</template>
</div>
<ul class="steps steps-horizontal text-xs w-full">
<li
v-for="(stage, index) in stages"
:key="index"
class="step step-primary"
:data-content="getTransportIcon(stage.transportType)"
>
{{ formatDistance(stage.distanceKm) }} км
</li>
</ul>
</template>
<script setup lang="ts">
@@ -27,6 +28,7 @@ const getTransportIcon = (type?: string | null) => {
case 'sea':
return '🚢'
case 'road':
case 'auto':
default:
return '🚛'
}

View File

@@ -60,14 +60,11 @@
<template #card="{ item }">
<OfferResultCard
:source-name="item.name"
:location-name="getOfferData(item.uuid)?.locationName"
:product-name="selectedProductName"
:price-per-unit="getOfferData(item.uuid)?.pricePerUnit"
:currency="getOfferData(item.uuid)?.currency"
:unit="getOfferData(item.uuid)?.unit"
:latitude="item.latitude"
:longitude="item.longitude"
:stages="item.stages"
/>
</template>