137 lines
5.5 KiB
Vue
137 lines
5.5 KiB
Vue
<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>
|