204 lines
7.4 KiB
Vue
204 lines
7.4 KiB
Vue
<script setup lang="ts">
|
|
// imports
|
|
|
|
import useGetAllAddress from "~/composables/api/account/useGetAllAddress";
|
|
import useSetOrderAddress from "~/composables/api/orders/useSetOrderAddress";
|
|
import { useToast } from "~/composables/global/useToast";
|
|
import { QUERY_KEYS } from "~/constants";
|
|
|
|
// meta
|
|
|
|
definePageMeta({
|
|
layout: "cart",
|
|
middleware: "check-is-logged-in",
|
|
pageTitle: "انتخاب آدرس",
|
|
prevPage: { name: "cart", label: "سبد خرید" },
|
|
nextPage: { name: "cart-checkout", label: "تسویه حساب", query: "ZARINPAL" },
|
|
});
|
|
|
|
// types
|
|
|
|
type DeliveryData = {
|
|
address: Address | null;
|
|
deliveryMethod: {
|
|
tipax: boolean;
|
|
pishtaz: boolean;
|
|
peyk: boolean;
|
|
};
|
|
};
|
|
|
|
// queries
|
|
|
|
const { data: addresses, isLoading: addressesIsLoading } = useGetAllAddress();
|
|
|
|
const { mutateAsync: setOrderAddress, isPending: setOrderAddressIsPending } =
|
|
useSetOrderAddress();
|
|
|
|
// computed
|
|
|
|
const selectedAddress = computed(() => {
|
|
return addresses.value?.find((i) => i.is_main) ?? null;
|
|
});
|
|
|
|
// state
|
|
|
|
const { $queryClient: queryClient } = useNuxtApp();
|
|
const { addToast } = useToast();
|
|
|
|
const deliveryData = ref<DeliveryData>({
|
|
address: selectedAddress.value,
|
|
deliveryMethod: {
|
|
peyk: false,
|
|
pishtaz: true,
|
|
tipax: false,
|
|
},
|
|
});
|
|
|
|
// methods
|
|
|
|
const handleSelectAddress = (address: Address) => {
|
|
deliveryData.value.address = { ...address };
|
|
};
|
|
|
|
// watch
|
|
|
|
whenever(
|
|
() => deliveryData.value.address,
|
|
(nv) => {
|
|
setOrderAddress(
|
|
{ address_id: nv.id! },
|
|
{
|
|
onSettled: () => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: [QUERY_KEYS.addresses],
|
|
});
|
|
},
|
|
onError: () => {
|
|
addToast({
|
|
message: "در انتخاب آدرس خطایی رخ داد",
|
|
options: {
|
|
description: "لطفا مجدد تلاش کنید",
|
|
},
|
|
});
|
|
},
|
|
}
|
|
);
|
|
},
|
|
{
|
|
deep: true,
|
|
}
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex flex-col w-full gap-5">
|
|
<AddressItem />
|
|
<div class="flex flex-col w-full gap-6">
|
|
<div class="flex items-center gap-3 py-3">
|
|
<NuxtImg src="/img/location.gif" class="size-12 pb-1 -mr-3" />
|
|
<span class="typo-sub-h-xl -mr-3"> آدرس های شما </span>
|
|
<Icon
|
|
name="svg-spinners:180-ring-with-bg"
|
|
size="20"
|
|
v-if="setOrderAddressIsPending"
|
|
class="pb-0.5"
|
|
/>
|
|
</div>
|
|
<div v-if="addressesIsLoading" class="flex flex-col gap-6 w-full">
|
|
<Skeleton v-for="i in 3" class="w-full !h-[8rem] !rounded-xl" />
|
|
</div>
|
|
<template v-else>
|
|
<div
|
|
v-if="!addresses?.length"
|
|
class="flex flex-grow w-full"
|
|
v-auto-animate
|
|
>
|
|
<Placeholder
|
|
title="آدرسی یافت نشد :("
|
|
icon="bi:map"
|
|
class="!py-[2rem]"
|
|
/>
|
|
</div>
|
|
|
|
<div v-else class="flex flex-col gap-6 w-full">
|
|
<AddressItem
|
|
v-for="(address, index) in addresses"
|
|
:key="index"
|
|
:address="address"
|
|
@select="handleSelectAddress"
|
|
:isSelected="address.id == deliveryData.address?.id"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
|
|
<div
|
|
class="flex flex-col items-center w-full gap-4 my-3 p-4 border border-slate-200 rounded-xl bg-slate-50"
|
|
>
|
|
<span
|
|
class="flex items-center justify-start w-full lg:text-[1.125rem] font-semibold text-slate-900"
|
|
>
|
|
شیوه ارسال
|
|
</span>
|
|
|
|
<label
|
|
@click="deliveryData.deliveryMethod.pishtaz = true"
|
|
:class="
|
|
deliveryData.deliveryMethod.pishtaz
|
|
? 'ring-black ring-offset-2 ring-2'
|
|
: ''
|
|
"
|
|
class="flex flex-col select-none w-full gap-2 p-3 transition-all border cursor-pointer delivery-option focus-within:ring-2 ring-blue-500 ring-offset-2 focus-within:border-blue-500 rounded-100 border-slate-200 bg-slate-50"
|
|
>
|
|
<div class="flex items-center justify-between w-full">
|
|
<div class="flex items-center gap-2.5">
|
|
<SwitchRoot
|
|
v-model="deliveryData.deliveryMethod.pishtaz"
|
|
:defaultValue="false"
|
|
class="w-[3rem] h-[1.8rem] shrink-0 flex data-[state=unchecked]:bg-slate-200 data-[state=checked]:bg-blue-500 border border-slate-200 data-[state=checked]:border-blue-500/20 rounded-full relative transition-all focus-within:outline-none"
|
|
>
|
|
<SwitchThumb
|
|
class="size-6 my-auto bg-white text-sm ms-1 flex items-center justify-center shadow-xl rounded-full transition-transform translate-x-0.5 will-change-transform data-[state=checked]:-translate-x-[68%]"
|
|
/>
|
|
</SwitchRoot>
|
|
<span
|
|
class="w-full text-slate-800 text-sm lg:text-[1rem]"
|
|
>پست پیشتاز</span
|
|
>
|
|
</div>
|
|
|
|
<span class="text-slate-800 text-sm lg:text-[1rem]">
|
|
۱۵۰٬۰۰۰ تومان
|
|
</span>
|
|
</div>
|
|
</label>
|
|
|
|
<label
|
|
class="flex items-center opacity-50 select-none pointer-events-none justify-between w-full p-3 transition-all border cursor-pointer delivery-option focus-within:ring-2 ring-blue-500 ring-offset-2 focus-within:border-blue-500 rounded-100 border-slate-200 bg-slate-50"
|
|
>
|
|
<div class="flex items-center gap-2.5">
|
|
<SwitchRoot
|
|
v-model="deliveryData.deliveryMethod.tipax"
|
|
class="w-[3rem] h-[1.8rem] shrink-0 flex data-[state=unchecked]:bg-slate-200 data-[state=checked]:bg-blue-500 border border-slate-200 data-[state=checked]:border-blue-500/20 rounded-full relative transition-all focus-within:outline-none"
|
|
>
|
|
<SwitchThumb
|
|
class="size-6 my-auto bg-white text-sm ms-1 flex items-center justify-center shadow-xl rounded-full transition-transform translate-x-0.5 will-change-transform data-[state=checked]:-translate-x-[68%]"
|
|
/>
|
|
</SwitchRoot>
|
|
<span class="w-full text-slate-800 text-sm lg:text-[1rem]"
|
|
>تیپاکس</span
|
|
>
|
|
</div>
|
|
|
|
<span class="text-slate-800 text-sm lg:text-[1rem]">
|
|
۱۵۰٬۰۰۰ تومان
|
|
</span>
|
|
</label>
|
|
</div>
|
|
|
|
<OrderSummary />
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped></style>
|