190 lines
5.1 KiB
Vue
190 lines
5.1 KiB
Vue
<template>
|
|
<CatalogPage
|
|
:items="itemsWithCoords"
|
|
:loading="isLoading"
|
|
map-id="select-location-map"
|
|
point-color="#10b981"
|
|
:selected-id="selectedHubId"
|
|
v-model:hovered-id="hoveredHubId"
|
|
:has-sub-nav="false"
|
|
@select="selectHub"
|
|
>
|
|
<template #header>
|
|
<Stack gap="4">
|
|
<!-- Back button -->
|
|
<div class="flex justify-between items-center">
|
|
<Heading :level="2">{{ t('common.selectLocation') }}</Heading>
|
|
<button class="btn btn-ghost btn-sm" @click="router.back()">
|
|
<Icon name="lucide:x" size="20" />
|
|
</button>
|
|
</div>
|
|
|
|
<!-- My addresses section -->
|
|
<Stack v-if="isAuthenticated && teamAddresses?.length" gap="3">
|
|
<Text weight="semibold">{{ t('profileAddresses.header.title') }}</Text>
|
|
<Stack gap="2">
|
|
<Card
|
|
v-for="addr in teamAddresses"
|
|
:key="addr.uuid"
|
|
padding="sm"
|
|
interactive
|
|
:class="{ 'ring-2 ring-primary': isSelected('address', addr.uuid) }"
|
|
@click="selectAddress(addr)"
|
|
>
|
|
<Stack gap="1">
|
|
<Stack direction="row" align="center" gap="2">
|
|
<Icon name="lucide:map-pin" size="16" class="text-primary" />
|
|
<Text size="sm" weight="semibold">{{ addr.name }}</Text>
|
|
<Pill v-if="addr.isDefault" variant="outline" size="sm">Default</Pill>
|
|
</Stack>
|
|
<Text tone="muted" size="xs">{{ addr.address }}</Text>
|
|
</Stack>
|
|
</Card>
|
|
</Stack>
|
|
</Stack>
|
|
|
|
<!-- Hubs section header -->
|
|
<Text weight="semibold">{{ t('catalogMap.hubsTab') }}</Text>
|
|
</Stack>
|
|
</template>
|
|
|
|
<template #filters>
|
|
<CatalogFilterSelect :filters="filters" v-model="selectedFilter" />
|
|
</template>
|
|
|
|
<template #card="{ item }">
|
|
<HubCard
|
|
:hub="item"
|
|
selectable
|
|
:is-selected="isSelected('hub', item.uuid)"
|
|
/>
|
|
</template>
|
|
|
|
<template #pagination>
|
|
<PaginationLoadMore
|
|
:shown="items.length"
|
|
:total="total"
|
|
:can-load-more="canLoadMore"
|
|
:loading="isLoadingMore"
|
|
@load-more="loadMore"
|
|
/>
|
|
</template>
|
|
|
|
<template #empty>
|
|
<EmptyState :title="t('catalogMap.noHubs')" />
|
|
</template>
|
|
</CatalogPage>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useLocationStore } from '~/stores/location'
|
|
|
|
definePageMeta({
|
|
layout: 'topnav'
|
|
})
|
|
|
|
const router = useRouter()
|
|
const route = useRoute()
|
|
const { t } = useI18n()
|
|
const localePath = useLocalePath()
|
|
const { isAuthenticated } = useAuth()
|
|
const locationStore = useLocationStore()
|
|
const searchStore = useSearchStore()
|
|
const isSearchMode = computed(() => route.query.mode === 'search')
|
|
|
|
// Use shared composable for hubs
|
|
const {
|
|
items,
|
|
total,
|
|
selectedFilter,
|
|
filters,
|
|
isLoading,
|
|
isLoadingMore,
|
|
itemsWithCoords,
|
|
canLoadMore,
|
|
loadMore,
|
|
init
|
|
} = useCatalogHubs()
|
|
|
|
// Selected/hovered hub for map
|
|
const selectedHubId = ref<string>()
|
|
const hoveredHubId = ref<string>()
|
|
|
|
await init()
|
|
|
|
// Load team addresses
|
|
const teamAddresses = ref<any[]>([])
|
|
|
|
if (isAuthenticated.value) {
|
|
try {
|
|
const { execute } = useGraphQL()
|
|
const { GetTeamAddressesDocument } = await import('~/composables/graphql/team/teams-generated')
|
|
const data = await execute(GetTeamAddressesDocument, {}, 'team', 'teams')
|
|
teamAddresses.value = data?.teamAddresses || []
|
|
} catch {
|
|
// Not critical
|
|
}
|
|
}
|
|
|
|
const isSelected = (type: 'address' | 'hub', uuid: string) => {
|
|
return locationStore.selectedLocation?.type === type && locationStore.selectedLocation?.uuid === uuid
|
|
}
|
|
|
|
const goToRequestIfReady = () => {
|
|
if (route.query.after === 'request' && searchStore.searchForm.productUuid && searchStore.searchForm.locationUuid) {
|
|
router.push({
|
|
path: '/request',
|
|
query: {
|
|
productUuid: searchStore.searchForm.productUuid,
|
|
product: searchStore.searchForm.product,
|
|
locationUuid: searchStore.searchForm.locationUuid,
|
|
location: searchStore.searchForm.location,
|
|
quantity: searchStore.searchForm.quantity || undefined
|
|
}
|
|
})
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
const selectHub = async (hub: any) => {
|
|
selectedHubId.value = hub.uuid
|
|
|
|
if (isSearchMode.value) {
|
|
searchStore.setLocation(hub.name)
|
|
searchStore.setLocationUuid(hub.uuid)
|
|
if (goToRequestIfReady()) return
|
|
router.back()
|
|
return
|
|
}
|
|
|
|
try {
|
|
const success = await locationStore.select('hub', hub.uuid, hub.name, hub.latitude, hub.longitude)
|
|
if (success) {
|
|
router.back()
|
|
}
|
|
} catch (e) {
|
|
console.error('[selectHub] Error:', e)
|
|
}
|
|
}
|
|
|
|
const selectAddress = async (addr: any) => {
|
|
if (isSearchMode.value) {
|
|
searchStore.setLocation(addr.address || addr.name)
|
|
searchStore.setLocationUuid(addr.uuid)
|
|
if (goToRequestIfReady()) return
|
|
router.back()
|
|
return
|
|
}
|
|
|
|
try {
|
|
const success = await locationStore.select('address', addr.uuid, addr.name, addr.latitude, addr.longitude)
|
|
if (success) {
|
|
router.back()
|
|
}
|
|
} catch (e) {
|
|
console.error('[selectAddress] Error:', e)
|
|
}
|
|
}
|
|
</script>
|