Add address detail view and link from list

This commit is contained in:
Ruslan Bakiev
2026-01-07 09:13:04 +07:00
parent 8baeb627a1
commit 7f27fc3d99
4 changed files with 146 additions and 3 deletions

View File

@@ -0,0 +1,128 @@
<template>
<Section variant="plain" paddingY="md">
<Stack gap="6">
<PageHeader
:title="t('profileAddresses.header.title')"
:actions="[{ label: t('common.back'), icon: 'lucide:arrow-left', to: localePath('/clientarea/addresses') }]"
/>
<Card v-if="isLoading || !address" padding="lg">
<Stack align="center" gap="3">
<Spinner v-if="isLoading" />
<Text tone="muted">
{{ isLoading ? t('profileAddresses.states.loading') : t('profileAddresses.states.not_found') }}
</Text>
</Stack>
</Card>
<Card v-else padding="lg">
<Stack gap="4">
<Input
:model-value="address.name"
:label="t('profileAddresses.form.name.label')"
disabled
/>
<Input
:model-value="address.address"
:label="t('profileAddresses.form.address.label')"
disabled
/>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input
:model-value="address.latitude"
label="Latitude"
disabled
/>
<Input
:model-value="address.longitude"
label="Longitude"
disabled
/>
</div>
<div v-if="hasCoords" class="h-72 rounded-box overflow-hidden">
<ClientOnly>
<MapboxGlobe
map-id="address-detail-map"
:locations="locations"
:height="288"
/>
</ClientOnly>
</div>
<Text v-else tone="muted">
{{ t('profileAddresses.states.no_coords') }}
</Text>
<div class="flex flex-wrap gap-3">
<Button variant="outline" :as="NuxtLink" :to="localePath('/clientarea/addresses/new')">
{{ t('profileAddresses.actions.add') }}
</Button>
<Button variant="ghost" tone="error" @click="handleDelete">
{{ t('profileAddresses.actions.delete') }}
</Button>
</div>
<Text tone="muted" size="sm">
{{ t('profileAddresses.states.edit_hint') }}
</Text>
</Stack>
</Card>
</Stack>
</Section>
</template>
<script setup lang="ts">
import { NuxtLink } from '#components'
definePageMeta({
middleware: ['auth-oidc']
})
const { t } = useI18n()
const route = useRoute()
const localePath = useLocalePath()
const {
items,
isLoading,
init,
load,
deleteAddress
} = useTeamAddresses()
await init()
onMounted(async () => {
if (!address.value) {
await load()
}
})
const address = computed(() => items.value.find((a) => a?.uuid === route.params.uuid))
const hasCoords = computed(() =>
Boolean(address.value?.latitude && address.value?.longitude)
)
const locations = computed(() =>
hasCoords.value
? [{
uuid: address.value?.uuid,
name: address.value?.name,
latitude: address.value?.latitude,
longitude: address.value?.longitude,
country: address.value?.countryCode
}]
: []
)
const handleDelete = async () => {
if (!address.value) return
const success = await deleteAddress(address.value.uuid)
if (success) {
navigateTo(localePath('/clientarea/addresses'))
}
}
</script>

View File

@@ -25,7 +25,14 @@
</NuxtLink>
<Grid :cols="1" :md="2" :gap="4">
<Card v-for="addr in items" :key="addr.uuid" padding="small" interactive>
<Card
v-for="addr in items"
:key="addr.uuid"
padding="small"
interactive
:as="NuxtLink"
:to="localePath(`/clientarea/addresses/${addr.uuid}`)"
>
<div class="flex flex-col gap-1">
<div class="flex items-center justify-between">
<Text size="base" weight="semibold" class="truncate">{{ addr.name }}</Text>
@@ -72,6 +79,8 @@ definePageMeta({
middleware: ['auth-oidc']
})
import { NuxtLink } from '#components'
const { t } = useI18n()
const localePath = useLocalePath()

View File

@@ -31,7 +31,10 @@
"mapLabel": "Select a point on the map"
},
"states": {
"loading": "Loading addresses..."
"loading": "Loading addresses...",
"not_found": "Address not found",
"no_coords": "No coordinates provided for this address",
"edit_hint": "Editing is not available yet: you can delete this address and create a new one."
},
"labels": {
"default": "Default"

View File

@@ -31,7 +31,10 @@
"saving": "Сохранение..."
},
"states": {
"loading": "Загружаем адреса..."
"loading": "Загружаем адреса...",
"not_found": "Адрес не найден",
"no_coords": "Координаты для этого адреса не указаны",
"edit_hint": "Редактирование адреса пока недоступно: вы можете удалить его и создать новый."
},
"labels": {
"default": "По умолчанию"