Create update quantity component for changing cart item quantity
This commit is contained in:
@@ -0,0 +1,87 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
// import
|
||||||
|
|
||||||
|
import useGetProduct from "~/composables/api/product/useGetProduct";
|
||||||
|
import useAddCartItem from "~/composables/api/orders/useAddCartItem";
|
||||||
|
import type { ProductVariantProvideType } from "~/pages/product/[id].vue";
|
||||||
|
|
||||||
|
// provide / inject
|
||||||
|
|
||||||
|
const { selectedVariant } = inject(
|
||||||
|
"productVariant"
|
||||||
|
) as ProductVariantProvideType;
|
||||||
|
|
||||||
|
// state
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const id = route.params.id as string | undefined;
|
||||||
|
|
||||||
|
const { refetch: refetchProduct } = useGetProduct(id);
|
||||||
|
const { mutateAsync: addCartItem, isPending: isAddCartItemPending } = useAddCartItem();
|
||||||
|
|
||||||
|
const timer = ref<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
|
const quantity = ref(1);
|
||||||
|
|
||||||
|
// methods
|
||||||
|
|
||||||
|
const onInput = (e: any) => {
|
||||||
|
const value = Number(e.target.value);
|
||||||
|
if (value > 0 && value <= selectedVariant.value!.in_stock) {
|
||||||
|
quantity.value = value;
|
||||||
|
} else {
|
||||||
|
quantity.value = 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => quantity.value,
|
||||||
|
(newValue) => {
|
||||||
|
if (timer.value) clearTimeout(timer.value);
|
||||||
|
timer.value = setTimeout(async () => {
|
||||||
|
await addCartItem({ id: selectedVariant.value!.id, quantity: newValue });
|
||||||
|
await refetchProduct();
|
||||||
|
}, 350);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(selectedVariant, (newValue) => {
|
||||||
|
quantity.value = newValue!.cart_quantity;
|
||||||
|
});
|
||||||
|
|
||||||
|
// lifecycle
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
quantity.value = selectedVariant.value!.cart_quantity;
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NumberFieldRoot
|
||||||
|
class="rounded-full border-slate-200 border-[1.5px] flex items-center bg-white gap-4 p-4"
|
||||||
|
v-model="quantity"
|
||||||
|
:min="1"
|
||||||
|
:max="selectedVariant!.in_stock"
|
||||||
|
>
|
||||||
|
<NumberFieldIncrement class="cursor-pointer">
|
||||||
|
<Icon name="ci:plus" class="**:stroke-slate-500 size-5" />
|
||||||
|
</NumberFieldIncrement>
|
||||||
|
<div class="relative">
|
||||||
|
<div
|
||||||
|
:class="isAddCartItemPending ? 'opacity-100' : 'opacity-0'"
|
||||||
|
class="w-[40px] h-[25px] flex-center transition-all absolute bg-white"
|
||||||
|
>
|
||||||
|
<Icon :name="'svg-spinners:180-ring-with-bg'" class="size-[25px]" />
|
||||||
|
</div>
|
||||||
|
<NumberFieldInput
|
||||||
|
@input="onInput"
|
||||||
|
:class="!isAddCartItemPending ? 'opacity-100' : 'opacity-0'"
|
||||||
|
class="transition-all field-sizing-content w-[40px] h-[25px] bg-transparent text-center outline-none typo-label-md text-black"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<NumberFieldDecrement class="cursor-pointer">
|
||||||
|
<Icon name="ci:minus" class="**:stroke-slate-500 size-5" />
|
||||||
|
</NumberFieldDecrement>
|
||||||
|
</NumberFieldRoot>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user