Files
webapp/app/components/LocationsContent.vue
2026-01-07 09:10:35 +07:00

121 lines
3.7 KiB
Vue

<template>
<Stack gap="8">
<!-- My addresses (for authenticated users) -->
<Stack v-if="isAuthenticated && teamAddresses?.length" gap="4">
<PageHeader title="My addresses">
<template #actions>
<NuxtLink
:to="localePath('/clientarea/addresses')"
class="btn btn-sm btn-ghost gap-2"
>
<Icon name="lucide:settings" size="16" />
Manage
</NuxtLink>
</template>
</PageHeader>
<Grid :cols="1" :md="2" :lg="3" :gap="4">
<Card
v-for="addr in teamAddresses"
:key="addr.uuid"
padding="small"
interactive
@click="selectTeamAddress(addr)"
>
<Stack gap="2">
<Stack direction="row" align="center" gap="2">
<Icon name="lucide:map-pin" size="18" class="text-primary" />
<Text size="base" weight="semibold">{{ addr.name }}</Text>
<Pill v-if="addr.isDefault" variant="outline" size="sm">Default</Pill>
</Stack>
<Text tone="muted" size="sm">{{ addr.address }}</Text>
</Stack>
</Card>
</Grid>
</Stack>
<!-- Terminals and logistics hubs -->
<Stack gap="4">
<PageHeader title="Terminals and logistics hubs" />
<div v-if="pending" class="flex items-center justify-center p-8">
<span class="loading loading-spinner loading-lg" />
</div>
<Alert v-else-if="error" variant="error">
<Stack gap="2">
<Heading :level="4" weight="semibold">Load error</Heading>
<Button @click="refresh()">Try again</Button>
</Stack>
</Alert>
<EmptyState
v-else-if="!locationsData?.length"
title="No locations"
description="Logistics hubs not added yet"
/>
<Grid v-else :cols="1" :md="2" :lg="3" :gap="4">
<HubCard
v-for="location in locationsData"
:key="location.uuid"
:hub="location"
selectable
@select="selectLocation(location)"
/>
</Grid>
</Stack>
</Stack>
</template>
<script setup lang="ts">
import { GetNodesDocument } from '~/composables/graphql/public/geo-generated'
const searchStore = useSearchStore()
const { isAuthenticated } = useAuth()
const localePath = useLocalePath()
const calculateDistance = (lat: number, lng: number) => {
const moscowLat = 55.76
const moscowLng = 37.64
const distance = Math.sqrt(Math.pow(lat - moscowLat, 2) + Math.pow(lng - moscowLng, 2)) * 111
return `${Math.round(distance)} km`
}
// Load logistics hubs
const { data: locationsDataRaw, pending, error, refresh } = await useServerQuery('locations', GetNodesDocument, {}, 'public', 'geo')
const locationsData = computed(() => {
return (locationsDataRaw.value || []).map((location: any) => ({
...location,
distance: location?.latitude && location?.longitude
? calculateDistance(location.latitude, location.longitude)
: undefined,
}))
})
// Load team addresses (if authenticated)
const teamAddresses = ref<any[]>([])
if (isAuthenticated.value) {
try {
const { GetTeamAddressesDocument } = await import('~/composables/graphql/team/teams-generated')
const { data: addressData } = await useServerQuery('locations-team-addresses', GetTeamAddressesDocument, {}, 'team', 'teams')
teamAddresses.value = addressData.value?.teamAddresses || []
} catch (e) {
console.log('Team addresses not available')
}
}
const selectLocation = (location: any) => {
searchStore.setLocation(location.name)
searchStore.setLocationUuid(location.uuid)
history.back()
}
const selectTeamAddress = (addr: any) => {
searchStore.setLocation(addr.address)
searchStore.setLocationUuid(addr.uuid)
history.back()
}
</script>