Files
hossein-por-shop/frontend/components/cart/global/CartSummary.vue
T

375 lines
13 KiB
Vue

<script setup lang="ts">
// imports
import useDeleteDiscountCode from "~/composables/api/orders/useDeleteDiscountCode";
import useDeleteSpecialDiscountCode from "~/composables/api/orders/useDeleteSpecialDiscountCode";
import useGetCartOrders from "~/composables/api/orders/useGetCartOrders";
import usePayOrder from "~/composables/api/orders/usePayOrder";
import useSubmitDiscountCode from "~/composables/api/orders/useSubmitDiscountCode";
import useSubmitSpecialDiscountCode from "~/composables/api/orders/useSubmitSpecialDiscountCode";
import { useToast } from "~/composables/global/useToast";
import { QUERY_KEYS } from "~/constants";
// state
const route = useRoute();
const { $queryClient: queryClient } = useNuxtApp();
const { addToast } = useToast();
// queries
const { data: cart, isLoading: cartIsLoading } = useGetCartOrders();
const discountCode = ref(cart.value?.discount_code?.code || "");
const specialDiscountCode = ref(cart.value?.special_discount_code?.code || "");
const { mutateAsync: submitDiscountCode, isPending: submitDiscountCodeIsPending } = useSubmitDiscountCode();
const { mutateAsync: deleteDiscountCode, isPending: deleteDiscountCodeIsPending } = useDeleteDiscountCode();
const { mutateAsync: submitSpecialDiscountCode, isPending: submitSpecialDiscountCodeIsPending } =
useSubmitSpecialDiscountCode();
const { mutateAsync: deleteSpecialDiscountCode, isPending: deleteSpecialDiscountCodeIsPending } =
useDeleteSpecialDiscountCode();
const { mutateAsync: pay, isPending: paymentIsPending } = usePayOrder();
const isTermsAccepted = ref(false);
// computed
const nextPage = computed(() => route.meta.nextPage as { name: string; label: string; query?: string } | undefined);
// const hasSubmittedDiscountCode = computed(() => !!cart.value?.discount_code);
const hasSubmittedSpecialDiscountCode = computed(() => !!cart.value?.special_discount_code);
// methods
// const handleSubmitDiscountCode = () => {
// submitDiscountCode(
// { code: discountCode.value },
// {
// onSuccess: () => {
// queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.cart] });
// },
// onError: () => {
// addToast({
// message: "خطایی در ثبت کد تخفیف رخ داد",
// options: {
// status: "error",
// },
// });
// discountCode.value = "";
// },
// }
// );
// };
// const handleDeleteDiscountCode = () => {
// deleteDiscountCode(undefined, {
// onSuccess: () => {
// queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.cart] });
// discountCode.value = "";
// },
// onError: () => {
// addToast({
// message: "خطایی در حذف کد تخفیف رخ داد",
// options: {
// status: "error",
// },
// });
// discountCode.value = "";
// },
// });
// };
const handleSubmitSpecialDiscountCode = () => {
submitSpecialDiscountCode(
{ code: specialDiscountCode.value },
{
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.cart] });
},
onError: () => {
addToast({
message: "خطایی در ثبت کد تخفیف ویژه رخ داد",
options: {
status: "error",
},
});
specialDiscountCode.value = "";
},
},
);
};
const handleDeleteSpecialDiscountCode = () => {
deleteSpecialDiscountCode(undefined, {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.cart] });
specialDiscountCode.value = "";
},
onError: () => {
addToast({
message: "خطایی در حذف کد تخفیف ویژه رخ داد",
options: {
status: "error",
},
});
specialDiscountCode.value = "";
},
});
};
const handlePayment = () => {
pay(
{
gateway_type: route.query["gw"] as any,
},
{
onSuccess: (data) => {
setTimeout(() => {
window.location.href = data.url;
}, 2000);
},
onError: () => {
addToast({
message: "خطایی در پرداخت رخ داد",
options: {
description: "لطفا با پشتیبانی تماس بگیرید",
status: "error",
},
});
},
},
);
};
// watch
watch(
() => cart.value?.discount_code,
(newCode) => {
if (newCode) {
discountCode.value = newCode.code;
} else {
discountCode.value = "";
}
},
);
watch(
() => cart.value?.special_discount_code,
(newCode) => {
if (newCode) {
specialDiscountCode.value = newCode.code;
} else {
specialDiscountCode.value = "";
}
},
);
</script>
<template>
<div class="flex flex-col bg-slate-50 w-full lg:w-3/12 transition-all border border-slate-200 rounded-xl">
<div class="w-full flex items-center justify-between py-5 px-4 border-b border-slate-200">
<span class="typo-sub-h-xl text-black">فاکتور خرید</span>
<Icon
name="ci:cart"
class="**:stroke-black"
size="24"
/>
</div>
<div
v-if="cartIsLoading"
class="flex flex-col p-4 gap-4 !rounded-lg"
>
<Skeleton
v-for="i in 5"
:key="i"
class="w-full !h-7"
:class="{
'!h-12': [4, 5].includes(i),
}"
/>
</div>
<div
v-else
class="flex flex-col p-4 gap-4"
>
<div class="flex items-center justify-between w-full text-slate-800">
<span class="max-w-1/2 text-sm"> جمع سبد خرید: </span>
<span class="max-w-1/2 text-sm">
{{ cart?.cart_total }}
</span>
</div>
<div class="flex items-center justify-between w-full text-gray-500">
<span class="max-w-1/2 text-sm"> تخفیف کلی محصولات: </span>
<span class="max-w-1/2 text-sm">
{{ cart?.items_discount_amount }}
</span>
</div>
<!-- <div
v-if="hasSubmittedSpecialDiscountCode"
class="flex items-center justify-between w-full text-status-error-primary text-red-700"
>
<span class="max-w-1/2 text-sm"> تخفیف: </span>
<span class="max-w-1/2 text-sm">
{{ cart?.special_discount_total }}
</span>
</div> -->
<div
v-if="!!cart?.special_discount_code"
class="flex items-center justify-between w-full text-green-700"
>
<span class="max-w-1/2 text-sm"> تخفیف ویژه: </span>
<span class="max-w-1/2 text-sm">
{{ cart?.special_discount_total }}
</span>
</div>
<div class="flex items-center justify-between w-full text-slate-800">
<span class="max-w-1/2 text-sm"> مالیات ارزش افزوده: </span>
<span class="max-w-1/2 text-sm"> {{ cart?.tax_amount }} </span>
</div>
<div class="flex items-center justify-between w-full text-slate-900">
<span class="max-w-1/2 text-sm"> جمع کل: </span>
<span class="max-w-1/2 text-sm">
{{ cart?.final_price }}
</span>
</div>
<div class="w-full flex justify-between">
<Input
v-model="specialDiscountCode"
placeholder="کد تخفیف"
class="!py-3 !pe-2 ps-2.5 w-full !rounded-none !border-e-[0px] !rounded-s-100"
:disabled="hasSubmittedSpecialDiscountCode"
/>
<button
@click="
hasSubmittedSpecialDiscountCode
? handleDeleteSpecialDiscountCode()
: handleSubmitSpecialDiscountCode()
"
class="text-xs px-5 rounded-e-100 py-1.5 text-white bg-black hover:bg-transparent hover:text-black border-[1.5px] border-black hover:border-black transition-all disabled:cursor-not-allowed"
:disabled="
!specialDiscountCode.length ||
submitSpecialDiscountCodeIsPending ||
deleteSpecialDiscountCodeIsPending
"
>
<Icon
v-if="submitSpecialDiscountCodeIsPending || deleteSpecialDiscountCodeIsPending"
name="ci:svg-spinners-180-ring-with-bg"
size="20"
class="**:fill-white"
/>
<span v-else>
{{ hasSubmittedSpecialDiscountCode ? "حذف" : "ثبت" }}
</span>
</button>
</div>
<!-- <div class="w-full flex justify-between">
<Input
v-model="specialDiscountCode"
placeholder="کد تخفیف ویژه"
class="!py-3 !pe-2 ps-2.5 w-full !rounded-none !border-e-[0px] !rounded-s-100"
:disabled="hasSubmittedSpecialDiscountCode"
/>
<button
@click="hasSubmittedSpecialDiscountCode ? handleDeleteSpecialDiscountCode() : handleSubmitSpecialDiscountCode()"
class="text-xs px-5 rounded-e-100 py-1.5 text-white bg-green-600 hover:bg-transparent hover:text-green-600 border-[1.5px] border-green-600 hover:border-green-600 transition-all disabled:cursor-not-allowed"
:disabled="!specialDiscountCode.length || submitSpecialDiscountCodeIsPending || deleteSpecialDiscountCodeIsPending"
>
<Icon
v-if="submitSpecialDiscountCodeIsPending || deleteSpecialDiscountCodeIsPending"
name="ci:svg-spinners-180-ring-with-bg"
size="20"
class="**:fill-white"
/>
<span v-else>
{{ hasSubmittedSpecialDiscountCode ? "حذف" : "ثبت" }}
</span>
</button>
</div> -->
<Button
v-if="nextPage?.name == 'payment'"
start-icon="ci:arrow-right"
class="w-full rounded-100"
@click="handlePayment"
variant="primary"
:disabled="!isTermsAccepted"
>
{{ nextPage?.label }}
</Button>
<NuxtLink
v-else
:to="{ name: nextPage?.name, query: { gw: nextPage?.query } }"
>
<Button
start-icon="ci:arrow-right"
class="w-full rounded-100 py-2 lg:typo-p-sm"
variant="primary"
>
{{ nextPage?.label }}
</Button>
</NuxtLink>
<div
v-if="nextPage?.name == 'payment'"
class="flex items-center gap-3 ps-2 pt-1 pb-3"
>
<label class="translate-y-0.5">
<input
id="payment-terms-accept-checkbox"
v-model="isTermsAccepted"
type="checkbox"
hidden
/>
<button
@click="isTermsAccepted = !isTermsAccepted"
class="rounded-sm size-5 border-[1.5px] cursor-pointer transition-colors"
:class="isTermsAccepted ? 'border-blue-500 bg-blue-500' : 'border-slate-400 bg-transparent'"
>
<Icon
name="ci:bi-check"
class="-translate-x-px **:fill-white transition-all"
:class="isTermsAccepted ? 'opacity-100' : 'opacity-0'"
/>
</button>
</label>
<div class="whitespace-nowrap text-sm">
<NuxtLink
to="/terms"
class="text-blue-600 underline"
>
قوانین و مقررات
</NuxtLink>
را خوانده و قبول دارم
</div>
</div>
<PaymentPendingModal v-model:isShow="paymentIsPending" />
</div>
</div>
</template>
<style scoped></style>