This commit is contained in:
marzban-dev
2025-03-17 13:40:58 +03:30
parent 1b7eec58b1
commit bb9c7232d0
2 changed files with 65 additions and 19 deletions
@@ -2,7 +2,7 @@
// provide / inject // provide / inject
import type { ProductVariantProvideType } from "~/pages/product/[id].vue"; import type { ProductVariantProvideType } from "~/pages/product/types";
const { selectedVariant } = inject("productVariant") as ProductVariantProvideType; const { selectedVariant } = inject("productVariant") as ProductVariantProvideType;
+64 -18
View File
@@ -5,13 +5,17 @@
import useGetProduct from "~/composables/api/product/useGetProduct"; import useGetProduct from "~/composables/api/product/useGetProduct";
import { sanitize } from "isomorphic-dompurify"; import { sanitize } from "isomorphic-dompurify";
import type { ProductVariantProvideType } from "~/pages/product/[id].vue"; import type { ProductVariantProvideType } from "~/pages/product/[id].vue";
import useAddCartItem from "~/composables/api/orders/useAddCartItem";
import { useAuth } from "~/composables/api/auth/useAuth";
// state // state
const route = useRoute(); const route = useRoute();
const id = route.params.id as string | undefined; const id = route.params.id as string | undefined;
const { data: product } = useGetProduct(id); const { token } = useAuth();
const { data: product, refetch: refetchProduct } = useGetProduct(id);
const { mutateAsync: addCartItem, isPending: isAddCartItemPending } = useAddCartItem();
const selectedVariantId = ref(product.value!.variants[0].id); const selectedVariantId = ref(product.value!.variants[0].id);
const selectedQuantity = ref(1); const selectedQuantity = ref(1);
@@ -23,6 +27,16 @@ const selectedColor = ref(product.value!.colors[0]);
const { selectedVariant, changeSelectedVariant } = inject("productVariant") as ProductVariantProvideType; const { selectedVariant, changeSelectedVariant } = inject("productVariant") as ProductVariantProvideType;
// method
const addItemToCart = async () => {
await addCartItem({
id: selectedVariant.value!.id,
quantity: selectedQuantity.value
});
await refetchProduct();
};
// computed // computed
const sanitizedProductDescription = computed(() => { const sanitizedProductDescription = computed(() => {
@@ -44,7 +58,7 @@ watch(() => selectedColor.value, (newValue) => {
immediate: true immediate: true
}); });
watch(() => selectedVariant.value, (newValue) => { watch(() => selectedVariant.value!, (newValue) => {
selectedQuantity.value = 1; selectedQuantity.value = 1;
selectedSlide.value = newValue.images[0].id; selectedSlide.value = newValue.images[0].id;
}); });
@@ -60,24 +74,24 @@ watch(() => selectedVariant.value, (newValue) => {
<div class="flex items-end gap-4"> <div class="flex items-end gap-4">
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<span <span
v-if="selectedVariant.discount > 0" v-if="selectedVariant!.discount > 0"
class="typo-p-lg relative flex-center w-fit" class="typo-p-lg relative flex-center w-fit"
:class="'after:w-full after:h-[2px] after:bg-black after:absolute'" :class="'after:w-full after:h-[2px] after:bg-black after:absolute'"
> >
{{ selectedVariant.price }} {{ selectedVariant!.price }}
</span> </span>
<span <span
class="typo-p-2xl relative flex-center w-fit font-medium" class="typo-p-2xl relative flex-center w-fit font-medium"
> >
{{ selectedVariant.discount > 0 ? selectedVariant.price : selectedVariant.price }} {{ selectedVariant!.discount > 0 ? selectedVariant!.price : selectedVariant!.price }}
</span> </span>
</div> </div>
<div <div
v-if="selectedVariant.discount > 0" v-if="selectedVariant!.discount > 0"
class="text-white bg-blue-500 mb-1 px-4 py-2 text-xs rounded-full flex items-center gap-1" class="text-white bg-blue-500 mb-1 px-4 py-2 text-xs rounded-full flex items-center gap-1"
> >
<Icon name="material-symbols:percent" class="size-4" /> <Icon name="material-symbols:percent" class="size-4" />
{{ selectedVariant.discount }} {{ selectedVariant!.discount }}
درصد تخفیف درصد تخفیف
</div> </div>
</div> </div>
@@ -87,7 +101,7 @@ watch(() => selectedVariant.value, (newValue) => {
<Slider <Slider
class="w-full lg:w-1/2 lg:max-w-[620px]" class="w-full lg:w-1/2 lg:max-w-[620px]"
v-model:selectedSlide="selectedSlide" v-model:selectedSlide="selectedSlide"
:slides="selectedVariant.images" :slides="selectedVariant!.images"
/> />
<div class="lg:w-1/2 flex flex-col gap-3 lg:mt-12"> <div class="lg:w-1/2 flex flex-col gap-3 lg:mt-12">
<NuxtLink <NuxtLink
@@ -101,24 +115,24 @@ watch(() => selectedVariant.value, (newValue) => {
<div class="flex items-end gap-4"> <div class="flex items-end gap-4">
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<span <span
v-if="selectedVariant.discount > 0" v-if="selectedVariant!.discount > 0"
class="typo-p-lg relative flex-center w-fit" class="typo-p-lg relative flex-center w-fit"
:class="'after:w-full after:h-[2px] after:bg-black after:absolute'" :class="'after:w-full after:h-[2px] after:bg-black after:absolute'"
> >
{{ selectedVariant.price }} {{ selectedVariant!.price }}
</span> </span>
<span <span
class="typo-p-2xl relative flex-center w-fit font-medium" class="typo-p-2xl relative flex-center w-fit font-medium"
> >
{{ selectedVariant.discount > 0 ? selectedVariant.price : selectedVariant.price }} {{ selectedVariant!.discount > 0 ? selectedVariant!.price : selectedVariant!.price }}
</span> </span>
</div> </div>
<div <div
v-if="selectedVariant.discount > 0" v-if="selectedVariant!.discount > 0"
class="text-white bg-blue-500 mb-1 px-4 py-2 text-xs rounded-full flex items-center gap-1" class="text-white bg-blue-500 mb-1 px-4 py-2 text-xs rounded-full flex items-center gap-1"
> >
<Icon name="material-symbols:percent" class="size-4" /> <Icon name="material-symbols:percent" class="size-4" />
{{ selectedVariant.discount }} {{ selectedVariant!.discount }}
<span class="max-sm:hidden">درصد</span> <span class="max-sm:hidden">درصد</span>
تخفیف تخفیف
</div> </div>
@@ -166,18 +180,50 @@ watch(() => selectedVariant.value, (newValue) => {
<div class="w-full flex flex-col gap-6 mt-10"> <div class="w-full flex flex-col gap-6 mt-10">
<RemainQuantity <RemainQuantity
:maxQuantity="selectedVariant.in_stock" :maxQuantity="selectedVariant!.in_stock"
:quantity="selectedQuantity" :quantity="selectedQuantity"
/> />
<div class="w-full flex gap-3"> <div class="w-full flex gap-3">
<Button class="w-full rounded-full" end-icon="ci:plus"> <template v-if="token">
افزودن به سبد خرید <Button
</Button> v-if="selectedVariant!.cart_quantity === 0"
@click="addItemToCart"
:loading="isAddCartItemPending"
:disabled="isAddCartItemPending"
class="w-full rounded-full"
end-icon="ci:plus"
>
افزودن به سبد خرید
</Button>
<NuxtLink v-else to="/cart" class="w-full">
<Button
class="w-full rounded-full h-full"
end-icon="ci:cart"
>
مشاهده در سبد خرید
</Button>
</NuxtLink>
</template>
<NuxtLink v-else to="/signin" class="w-full">
<Button
class="w-full rounded-full h-full"
end-icon="ci:user"
>
ابتدا وارد شوید
</Button>
</NuxtLink>
<QuantityCounter <QuantityCounter
v-if="selectedVariant!.cart_quantity === 0"
:disable="isAddCartItemPending"
v-model="selectedQuantity" v-model="selectedQuantity"
:max="selectedVariant.in_stock" :max="selectedVariant!.in_stock"
/> />
<UpdateQuantity v-else />
</div> </div>
<InfoCard /> <InfoCard />