Files
web-frontend/app/pages/profile/addresses.vue
2026-04-06 21:37:17 +07:00

137 lines
5.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { useMutation, useQuery } from '@vue/apollo-composable';
import {
DeleteMyDeliveryAddressDocument,
MyDeliveryAddressesDocument,
SetMyDefaultDeliveryAddressDocument,
type MyDeliveryAddressesQuery,
} from '~/composables/graphql/generated';
type DeliveryAddressItem = MyDeliveryAddressesQuery['myDeliveryAddresses'][number];
const route = useRoute();
const addressFeedback = ref(route.query.created === '1' ? 'Адрес сохранён.' : '');
const addressFeedbackTone = ref<'success' | 'error'>(route.query.created === '1' ? 'success' : 'error');
const deliveryAddressesQuery = useQuery(MyDeliveryAddressesDocument);
const setDefaultAddressMutation = useMutation(SetMyDefaultDeliveryAddressDocument, { throws: 'never' });
const deleteAddressMutation = useMutation(DeleteMyDeliveryAddressDocument, { throws: 'never' });
const addressBusyId = ref<string | null>(null);
const deliveryAddresses = computed<DeliveryAddressItem[]>(() => deliveryAddressesQuery.result.value?.myDeliveryAddresses ?? []);
async function setDefaultAddress(addressId: string) {
addressFeedback.value = '';
addressBusyId.value = addressId;
const result = await setDefaultAddressMutation.mutate({ addressId });
const payload = result?.data?.setMyDefaultDeliveryAddress;
addressBusyId.value = null;
if (!payload) {
addressFeedbackTone.value = 'error';
addressFeedback.value = setDefaultAddressMutation.error.value?.message || 'Не удалось сделать адрес основным.';
return;
}
addressFeedbackTone.value = 'success';
addressFeedback.value = 'Основной адрес обновлён.';
await deliveryAddressesQuery.refetch();
}
async function deleteAddress(addressId: string) {
addressFeedback.value = '';
addressBusyId.value = addressId;
const result = await deleteAddressMutation.mutate({ addressId });
const payload = result?.data?.deleteMyDeliveryAddress;
addressBusyId.value = null;
if (!payload) {
addressFeedbackTone.value = 'error';
addressFeedback.value = deleteAddressMutation.error.value?.message || 'Не удалось удалить адрес.';
return;
}
addressFeedbackTone.value = 'success';
addressFeedback.value = 'Адрес удалён.';
await deliveryAddressesQuery.refetch();
}
</script>
<template>
<section class="space-y-6">
<NuxtLink to="/profile" class="link link-hover text-sm"> Назад в профиль</NuxtLink>
<div class="flex flex-col gap-4 md:flex-row md:items-end md:justify-between">
<div class="space-y-2">
<h1 class="text-3xl font-extrabold text-[#0f2f20]">Адреса доставки</h1>
<p class="text-sm leading-6 text-[#466653]">
Выберите основной адрес для заказов или добавьте новый.
</p>
</div>
<NuxtLink
to="/profile/addresses/new"
class="btn rounded-full border-0 bg-[#123824] px-6 text-white hover:bg-[#0f2f20]"
>
Добавить
</NuxtLink>
</div>
<div
v-if="addressFeedback"
class="rounded-[24px] border px-4 py-3 text-sm font-medium"
:class="addressFeedbackTone === 'success'
? 'border-[#cbe9d6] bg-[#f1fbf5] text-[#1c6b45]'
: 'border-[#f1d1c7] bg-[#fff3ef] text-[#9d4426]'"
>
{{ addressFeedback }}
</div>
<div v-if="deliveryAddressesQuery.loading.value" class="rounded-[28px] bg-white px-5 py-4 text-sm text-[#355947] shadow-[0_18px_38px_rgba(18,56,36,0.08)]">
Загружаем адреса...
</div>
<div v-else-if="deliveryAddresses.length === 0" class="rounded-[28px] bg-white px-5 py-4 text-sm text-[#355947] shadow-[0_18px_38px_rgba(18,56,36,0.08)]">
Пока нет адресов доставки.
</div>
<div v-else class="space-y-4">
<article
v-for="address in deliveryAddresses"
:key="address.id"
class="rounded-[28px] bg-white px-5 py-4 shadow-[0_18px_38px_rgba(18,56,36,0.08)]"
>
<div class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
<div class="min-w-0 space-y-1">
<div class="flex flex-wrap items-center gap-2">
<p class="text-lg font-bold text-[#123824]">{{ address.label || 'Адрес доставки' }}</p>
<span v-if="address.isDefault" class="badge border-0 bg-[#e8f5ec] text-[#1c6b45]">Основной</span>
</div>
<p class="text-sm leading-6 text-[#557562]">{{ address.unrestrictedValue || address.address }}</p>
</div>
<div class="flex flex-wrap gap-2">
<button
v-if="!address.isDefault"
class="btn rounded-full border border-[#d7e6dc] bg-white px-5 text-[#123824] hover:border-[#bed6c7] hover:bg-[#f6fbf8]"
:disabled="addressBusyId === address.id"
@click="setDefaultAddress(address.id)"
>
{{ addressBusyId === address.id ? 'Сохраняем...' : 'Сделать основным' }}
</button>
<button
class="btn rounded-full border border-[#e5cfc7] bg-[#fff5f1] px-5 text-[#a64d2d] hover:border-[#deb5a8] hover:bg-[#ffe8e0]"
:disabled="addressBusyId === address.id"
@click="deleteAddress(address.id)"
>
{{ addressBusyId === address.id ? 'Удаляем...' : 'Удалить' }}
</button>
</div>
</div>
</article>
</div>
</section>
</template>