Updated
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
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";
|
||||||
|
|
||||||
// state
|
// state
|
||||||
|
|
||||||
@@ -12,47 +13,69 @@ const id = route.params.id as string | undefined;
|
|||||||
|
|
||||||
const { data: product } = useGetProduct(id);
|
const { data: product } = useGetProduct(id);
|
||||||
|
|
||||||
const quantity = ref(1);
|
const selectedVariantId = ref(product.value!.variants[0].id);
|
||||||
|
const selectedQuantity = ref(1);
|
||||||
|
const selectedSlide = ref(product.value!.variants[0].images[0].id);
|
||||||
|
|
||||||
const selectedSlide = ref(0);
|
// provide / inject
|
||||||
|
|
||||||
|
const { selectedVariant, changeSelectedVariant } = inject("productVariant") as ProductVariantProvideType;
|
||||||
|
|
||||||
// computed
|
// computed
|
||||||
|
|
||||||
const slides = computed(() => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
id: 0,
|
|
||||||
picture: product.value!.image1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
picture: product.value?.image2 ?? product.value!.image1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
picture: product.value!.image3 ?? product.value!.image1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
const sanitizedProductDescription = computed(() => {
|
const sanitizedProductDescription = computed(() => {
|
||||||
return sanitize(product.value!.description);
|
return sanitize(product.value!.description);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// watch
|
||||||
|
|
||||||
|
watch(() => selectedVariantId.value, (newId) => {
|
||||||
|
const newVariant = product.value!.variants.find(variant => variant.id === newId)!;
|
||||||
|
changeSelectedVariant(newVariant);
|
||||||
|
}, {
|
||||||
|
immediate: true
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => selectedVariant.value, (newValue) => {
|
||||||
|
selectedQuantity.value = 1;
|
||||||
|
selectedSlide.value = newValue.images[0].id;
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex gap-12 container pt-[5rem]">
|
<div class="flex gap-16 container pt-[5rem] pb-28">
|
||||||
<Slider
|
<Slider
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
v-model:selectedSlide="selectedSlide"
|
v-model:selectedSlide="selectedSlide"
|
||||||
:slides="slides"
|
:slides="selectedVariant.images"
|
||||||
/>
|
/>
|
||||||
<div class="flex-1 flex flex-col gap-3 mt-12">
|
<div class="flex-1 flex flex-col gap-3 mt-12">
|
||||||
<span class="typo-label-sm"> سامسونگ </span>
|
<span class="typo-label-sm"> سامسونگ </span>
|
||||||
<h1 class="typo-h-2"> {{ product!.name }} </h1>
|
<h1 class="typo-h-2"> {{ product!.name }} </h1>
|
||||||
<div class="flex w-full items-center justify-between">
|
<div class="flex w-full items-center justify-between h-[85px]">
|
||||||
<span class="typo-p-2xl"> {{ product!.price }} </span>
|
<div class="flex items-end gap-4">
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<span
|
||||||
|
v-if="selectedVariant.discount > 0"
|
||||||
|
class="typo-p-lg relative flex-center w-fit"
|
||||||
|
:class="'after:w-full after:h-[2px] after:bg-black after:absolute'"
|
||||||
|
>
|
||||||
|
{{ selectedVariant.price }}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="typo-p-2xl relative flex-center w-fit font-medium"
|
||||||
|
>
|
||||||
|
{{ selectedVariant.discount > 0 ? selectedVariant.price : selectedVariant.price }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div 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">
|
||||||
|
<Icon name="material-symbols:percent" class="size-4" />
|
||||||
|
{{ selectedVariant.discount }}
|
||||||
|
درصد تخفیف
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<Rating />
|
<Rating />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -61,11 +84,21 @@ const sanitizedProductDescription = computed(() => {
|
|||||||
v-html="sanitizedProductDescription"
|
v-html="sanitizedProductDescription"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="w-full flex flex-col gap-6 mt-4">
|
<div class="flex items-center gap-6 flex-wrap">
|
||||||
|
<ProductVariant
|
||||||
|
@click="variant.in_stock > 0 ? selectedVariantId = variant.id : undefined"
|
||||||
|
v-for="variant in product!.variants"
|
||||||
|
:key="variant.id"
|
||||||
|
:variantDetail="variant"
|
||||||
|
:isSelected="selectedVariantId === variant.id"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-full flex flex-col gap-6 mt-10">
|
||||||
|
|
||||||
<RemainQuantity
|
<RemainQuantity
|
||||||
:maxQuantity="product!.in_stock"
|
:maxQuantity="selectedVariant.in_stock"
|
||||||
:quantity="quantity"
|
:quantity="selectedQuantity"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="w-full flex gap-3 flex-col">
|
<div class="w-full flex gap-3 flex-col">
|
||||||
@@ -74,8 +107,8 @@ const sanitizedProductDescription = computed(() => {
|
|||||||
افزودن به سبد خرید
|
افزودن به سبد خرید
|
||||||
</Button>
|
</Button>
|
||||||
<QuantityCounter
|
<QuantityCounter
|
||||||
v-model="quantity"
|
v-model="selectedQuantity"
|
||||||
:max="product!.in_stock"
|
:max="selectedVariant.in_stock"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button class="w-full rounded-full" variant="outlined">
|
<Button class="w-full rounded-full" variant="outlined">
|
||||||
|
|||||||
Reference in New Issue
Block a user