159 lines
5.1 KiB
Vue
159 lines
5.1 KiB
Vue
<script setup lang="ts">
|
|
// imports
|
|
|
|
import useDeleteAddress from "~/composables/api/account/useDeleteAddress";
|
|
import useSetOrderAddress from "~/composables/api/orders/useSetOrderAddress";
|
|
import { useToast } from "~/composables/global/useToast";
|
|
import { QUERY_KEYS } from "~/constants";
|
|
|
|
// types
|
|
|
|
type Props = {
|
|
address?: Address;
|
|
isSelected?: boolean;
|
|
selectable?: boolean;
|
|
};
|
|
|
|
// props
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
selectable: true,
|
|
});
|
|
|
|
const { address } = toRefs(props);
|
|
|
|
// state
|
|
|
|
const { $queryClient: queryClient } = useNuxtApp();
|
|
|
|
const { addToast } = useToast();
|
|
|
|
// queries
|
|
|
|
const { mutateAsync: deleteAddress, isPending: deleteAddressIsPending } = useDeleteAddress();
|
|
|
|
const { mutateAsync: setOrderAddress, isPending: setOrderAddressIsPending } = useSetOrderAddress();
|
|
|
|
// methods
|
|
|
|
const handleSelectAddress = () => {
|
|
setOrderAddress(
|
|
{ address_id: address.value?.id! },
|
|
{
|
|
onSettled: () => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: [QUERY_KEYS.cart],
|
|
});
|
|
queryClient.invalidateQueries({
|
|
queryKey: [QUERY_KEYS.addresses],
|
|
});
|
|
},
|
|
onError: () => {
|
|
addToast({
|
|
message: "در انتخاب آدرس خطایی رخ داد",
|
|
options: {
|
|
description: "لطفا مجدد تلاش کنید",
|
|
},
|
|
});
|
|
},
|
|
}
|
|
);
|
|
};
|
|
|
|
const handleDeleteAddress = (id: number) => {
|
|
deleteAddress(
|
|
{ id },
|
|
{
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: [QUERY_KEYS.cart],
|
|
});
|
|
queryClient.invalidateQueries({
|
|
queryKey: [QUERY_KEYS.addresses],
|
|
});
|
|
|
|
addToast({
|
|
message: "آدرس با موفقیت حذف شد",
|
|
options: {
|
|
status: "success",
|
|
},
|
|
});
|
|
},
|
|
onError: () => {
|
|
addToast({
|
|
message: "مشکلی در حذف آدرس رخ داد",
|
|
options: {
|
|
status: "error",
|
|
},
|
|
});
|
|
},
|
|
}
|
|
);
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<button
|
|
@click.prevent="!!address && selectable ? handleSelectAddress() : null"
|
|
:class="isSelected ? 'border-transparent ring-2 ring-offset-2 ring-blue-500' : 'border-slate-200'"
|
|
class="flex flex-col items-center transition-all relative cursor-pointer w-full group gap-2 lg:gap-4 p-4 border rounded-xl bg-slate-50 overflow-hidden"
|
|
>
|
|
<div
|
|
v-if="deleteAddressIsPending"
|
|
class="absolute inset-0"
|
|
>
|
|
<Skeleton class="!size-full !rounded-xl" />
|
|
</div>
|
|
<span class="flex items-center justify-between w-full gap-3">
|
|
<div class="flex items-center gap-3 max-lg:text-sm font-semibold text-slate-900">
|
|
{{ !!address ? address.name : "آدرس" }}
|
|
<span
|
|
v-if="isSelected || setOrderAddressIsPending"
|
|
class="bg-blue-500 rounded-lg px-3 py-2 text-slate-200 text-[10px] lg:text-xs"
|
|
>
|
|
<span v-if="setOrderAddressIsPending">
|
|
<Icon
|
|
name="ci:svg-spinners-3-dots-bounce"
|
|
class="**:fill-white"
|
|
/>
|
|
</span>
|
|
<span v-else-if="isSelected && !setOrderAddressIsPending"> انتخاب شده </span>
|
|
</span>
|
|
</div>
|
|
|
|
<button
|
|
v-if="!!address"
|
|
@click.stop="handleDeleteAddress(address.id!)"
|
|
class="size-8 bg-slate-200/50 rounded-sm flex-center me-2 opacity-0 group-hover:opacity-100 transition-opacity"
|
|
>
|
|
<Icon
|
|
name="ci:bi-trash"
|
|
class="**:fill-red-500"
|
|
/>
|
|
</button>
|
|
</span>
|
|
|
|
<div class="flex flex-col items-center justify-between w-full gap-3 lg:gap-8 lg:flex-row">
|
|
<div class="w-full lg:w-9/12 overflow-hidden">
|
|
<div
|
|
class="w-full overflow-hidden overflow-ellipsis gap-5 text-start whitespace-pre text-xs lg:text-sm text-slate-700"
|
|
>
|
|
{{
|
|
!!address
|
|
? `ایران, ${address.province}, ${address.city}, ${address.address}, کدپستی ${address.postal_code}`
|
|
: "افزودن آدرس جدید"
|
|
}}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center justify-end w-full lg:w-3/12">
|
|
<ClientOnly>
|
|
<AddressModal :address="address" />
|
|
</ClientOnly>
|
|
</div>
|
|
</div>
|
|
</button>
|
|
</template>
|
|
|
|
<style scoped></style>
|