Refactor: use topnav layout + CatalogPage component
All checks were successful
Build Docker Image / build (push) Successful in 4m11s

- Remove catalog.vue layout and useCatalogLayout.ts (broken provide/inject)
- All catalog/clientarea list pages now use topnav layout
- Pages use CatalogPage component for SearchBar + Map functionality
- Clean architecture: layout handles nav, component handles features
This commit is contained in:
Ruslan Bakiev
2026-01-15 11:18:57 +07:00
parent 7ea96a97b3
commit 03485b77a5
8 changed files with 401 additions and 1092 deletions

View File

@@ -1,29 +1,32 @@
<template>
<div>
<!-- List content -->
<div v-if="isLoading" class="flex items-center justify-center py-8">
<Card padding="lg">
<Stack align="center" justify="center" gap="3">
<Spinner />
<Text tone="muted">{{ t('catalogLanding.states.loading') }}</Text>
</Stack>
</Card>
</div>
<CatalogPage
:items="displayItems"
:map-items="itemsWithCoords"
:loading="isLoading"
with-map
map-id="suppliers-map"
point-color="#3b82f6"
:selected-id="selectedSupplierId"
:hovered-id="hoveredSupplierId"
:total-count="total"
@select="onSelectSupplier"
@update:hovered-id="hoveredSupplierId = $event"
>
<template #searchBar="{ displayedCount, totalCount }">
<CatalogSearchBar
v-model:search-query="searchQuery"
:active-filters="[]"
:displayed-count="displayedCount"
:total-count="totalCount"
@search="onSearch"
/>
</template>
<template v-else>
<Stack gap="3">
<div
v-for="item in displayItems"
:key="item.uuid || item.teamUuid"
:class="{ 'ring-2 ring-primary rounded-lg': (item.uuid || item.teamUuid) === selectedSupplierId }"
@click="onSelectSupplier(item)"
@mouseenter="hoveredSupplierId = item.uuid || item.teamUuid"
@mouseleave="hoveredSupplierId = undefined"
>
<SupplierCard :supplier="item" />
</div>
</Stack>
<template #card="{ item }">
<SupplierCard :supplier="item" />
</template>
<template #pagination>
<PaginationLoadMore
v-if="displayItems.length > 0"
:shown="displayItems.length"
@@ -34,20 +37,19 @@
@load-more="loadMore"
class="mt-4"
/>
<Stack v-if="displayItems.length === 0" align="center" gap="2" class="py-8">
<Text tone="muted">{{ t('catalogSuppliersSection.empty.no_suppliers') }}</Text>
</Stack>
</template>
</div>
<template #empty>
<Text tone="muted">{{ t('catalogSuppliersSection.empty.no_suppliers') }}</Text>
</template>
</CatalogPage>
</template>
<script setup lang="ts">
import type { MapBounds } from '~/components/catalog/CatalogMap.vue'
import { provideCatalogLayout } from '~/composables/useCatalogLayout'
definePageMeta({
layout: 'catalog'
layout: 'topnav'
})
const { t } = useI18n()
@@ -73,10 +75,6 @@ const searchQuery = ref('')
const searchWithMap = ref(false)
const currentBounds = ref<MapBounds | null>(null)
const onBoundsChange = (bounds: MapBounds) => {
currentBounds.value = bounds
}
// Filter items with valid coordinates for map
const itemsWithCoords = computed(() =>
items.value.filter(item =>
@@ -104,54 +102,15 @@ const displayItems = computed(() => {
})
})
// Hovered item with coordinates for map highlight
const hoveredItem = computed(() => {
if (!hoveredSupplierId.value) return null
const item = items.value.find(i => (i.uuid || i.teamUuid) === hoveredSupplierId.value)
if (!item?.latitude || !item?.longitude) return null
return { latitude: Number(item.latitude), longitude: Number(item.longitude) }
})
// Search handler (for future use)
const onSearch = () => {
// TODO: Implement search
}
// No filters for suppliers
const onRemoveFilter = (_id: string) => {
// No filters to remove
}
const onSelectSupplier = (supplier: any) => {
selectedSupplierId.value = supplier.uuid || supplier.teamUuid
}
// Handle selection from map
const onMapSelect = (uuid: string) => {
const supplier = items.value.find(i => (i.uuid || i.teamUuid) === uuid)
if (supplier) {
selectedSupplierId.value = uuid
}
}
// Provide data to layout (no filter component for suppliers)
provideCatalogLayout({
searchQuery,
activeFilters: ref([]),
displayedCount: computed(() => displayItems.value.length),
totalCount: computed(() => total.value),
onSearch,
onRemoveFilter,
mapItems: itemsWithCoords,
mapId: 'suppliers-map',
pointColor: '#3b82f6',
hoveredItemId: hoveredSupplierId,
hoveredItem,
onMapSelect,
onBoundsChange,
searchWithMap
})
await init()
useHead(() => ({