Files
your-gold/components/section/ProductBlock.vue
2025-07-03 15:24:28 +02:00

264 lines
7.1 KiB
Vue

<template>
<div>
<UiContainer>
<transition>
<div
v-if="showPopup && curImage"
ref="dropdownRef"
tabindex="0"
class="fixed top-0 left-0 bg-[#000000cc] w-screen h-screen z-50 flex items-center justify-center cursor-pointer"
@keyup.esc="showPopup = false"
@keyup.left="goLeft"
@keyup.right="goRight"
@click.self="showPopup = false"
>
<div
class="border border-white p-4 rounded-2xl shadow-2xl bg-white cursor-auto"
>
<img
:src="`/api/public/file/${curImage}_l.webp`"
class="max-h-[80vh] object-contain"
alt=""
@load="focusOnImgLoad"
>
</div>
<button
class="absolute top-8 p-8 right-8 text-4xl rotate-45 text-white"
@click="showPopup = false"
>
+
</button>
</div>
</transition>
<div class="flex w-full gap-1">
<div class="w-[50%] min-w-150px">
<div class="flex gap-2">
<div
v-for="image in product.picture_uuids"
:key="image"
class="flex justify-center h-20 cursor-pointer"
@click="curImage = image"
>
<img
:src="`/api/public/file/${image}_m.webp`"
:alt="product.name"
srcset=""
>
</div>
<div class="cursor-pointer"
@click="showPopup = true"
>
<img
:src="`/api/public/file/${curImage}_m.webp`"
class="w-72"
alt=""
>
</div>
</div>
</div>
<div class="w-[50%]">
<h1 class="font-bold text-2xl">
{{ product.name }}
</h1>
<div>
<span class="mx-4">Product reference:</span><span>{{ product.reference }}</span>
</div>
<div class="my-4"
v-html="product.description"
/>
<div class="my-12">
<div class="text-2xl font-bold">
<span class="mx-4">Price:</span><span>{{ formatedPrice }}</span>
</div>
<div class="">
<span class="mx-4">Tax information:</span><span>{{ product.tax_name }}</span>
</div>
<div class="font-bold">
<span class="mx-4">Buy out price:</span><span>{{ formatedBuyOutPrice }}</span>
</div>
<button
:disabled="!product.sale_active"
class="btn disabled:bg-gray-500 bg-button text-white px-4 py-4 rounded-2xl cursor-pointer"
@click="productStore.incrementCartItem(product.id)"
>
Add to cart
</button>
</div>
</div>
</div>
<div class="flex gap-4">
<div class="w-1/2 flex cursor-pointer">
<div v-for="rel in product.recommendations"
:key="rel.id"
>
<nuxt-link
:to="{
name: `id-slug___${$i18n.locale}`,
params: {
id: menuStore.getProductMenu()?.id,
slug: menuStore.getProductMenu()?.front_menu_lang[0]
.link_rewrite,
},
query: { prod_id: rel?.id, name: rel?.link_rewrite },
}"
>
<div class="w-1/3">
{{ rel.name }}
<img
:src="`/api/public/file/${rel.cover_picture_uuid}_m.webp`"
class="h-24"
alt=""
>
</div>
</nuxt-link>
</div>
</div>
<div class="w-1/2">
<div
v-for="feature in product.features"
:key="feature.feature"
class="flex gap-4 justify-around border-b"
>
<span class="mx-4">{{ feature.feature }}:</span>
<span class="mx-4">
{{ feature.value }}
</span>
</div>
</div>
</div>
</UiContainer>
</div>
</template>
<script setup lang="ts">
import type { GenericResponse, ProductItem } from '~/types'
const menuStore = useMenuStore()
const { $session } = useNuxtApp()
const productStore = useProductStore()
const dropdownRef = ref()
// const addToCart = (p: ProductItem) => {
// alert('add to cart product: ' + p.name)
// }
const formatPrice = (p: number) => {
const formatdecimal = new Intl.NumberFormat(
$session.cookieData.value.country.iso_code,
{
style: 'decimal',
maximumFractionDigits: $session.cookieData.value.currency.precision,
},
).format(p)
return $session.cookieData.value.currency.suffix
? $session.cookieData.value.currency.sign + ' ' + formatdecimal
: formatdecimal + ' ' + $session.cookieData.value.currency.sign
}
const focusOnImgLoad = () => {
dropdownRef.value.focus()
}
const formatedPrice = computed(() => {
return formatPrice(product.value.price)
})
const formatedBuyOutPrice = computed(() => {
return formatPrice(product.value.buyout_price)
})
const route = useRoute()
// if (!route.query?.prod_id) {
// throw createError({
// statusCode: 404,
// statusMessage: 'Not Found',
// fatal: true
// });
// }
const getProduct = async (): Promise<ProductItem> => {
if (route.query?.prod_id) {
const data = await useMyFetch<GenericResponse<ProductItem>>(
`/api/public/product/${route.query?.prod_id}`,
{},
)
// await new Promise(resolve => setTimeout(resolve, 200));
return data.data
}
return {} as ProductItem
}
const product = ref(await getProduct())
watch(
() => route.query?.prod_id,
async () => {
const data = await getProduct()
product.value = data
if (curImage.value != data.picture_uuids[0]) {
curImage.value = data.cover_picture_uuid
}
},
)
watch($session.cookieData, async () => {
const oldId = product.value.id
const data = await getProduct()
product.value = data
if (oldId != data.id) {
curImage.value = data.cover_picture_uuid
}
})
const showPopup = ref(false)
const curImage = ref(product.value.cover_picture_uuid)
watch(showPopup, (newValue) => {
if (newValue) {
document.body.style.overflow = 'hidden'
}
else {
document.body.style.overflow = 'unset'
}
})
const goLeft = () => {
if (!curImage.value) return
const index = product.value.picture_uuids.indexOf(curImage.value)
if (index > 0) {
curImage.value = product.value.picture_uuids[index - 1]
}
else {
curImage.value
= product.value.picture_uuids[product.value.picture_uuids.length - 1]
}
}
const goRight = () => {
if (!curImage.value) return
const index = product.value.picture_uuids.indexOf(curImage.value)
if (index < product.value.picture_uuids.length - 1) {
curImage.value = product.value.picture_uuids[index + 1]
}
else {
curImage.value = product.value.picture_uuids[0]
}
}
</script>
<style>
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
</style>