Refactor: use topnav layout + CatalogPage component
All checks were successful
Build Docker Image / build (push) Successful in 4m11s
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:
@@ -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(() => ({
|
||||
|
||||
Reference in New Issue
Block a user