275 lines
8.3 KiB
Vue
275 lines
8.3 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]
|
|
}
|
|
}
|
|
|
|
/**
|
|
* INSERT INTO `front_page` (`created_at`, `updated_at`, `name`, `is_default`, `id`) VALUES ('2025-06-25 11:07:28.000','2025-06-25 11:07:28.000','product','0','13');
|
|
* INSERT INTO `front_menu` (`created_at`, `updated_at`, `active`, `position_id`, `id_front_page`, `is_default`, `is_root`, `id`) VALUES ('2025-06-25 11:07:28.000','2025-06-25 11:07:28.000','1','1','13','0','0','13');
|
|
* INSERT INTO `front_menu_lang` (`name`, `id_lang`, `id_front_menu`, `link_rewrite`) VALUES ('Product','2','13','product');
|
|
* INSERT INTO `front_menu_lang` (`link_rewrite`, `id_front_menu`, `id_lang`, `name`) VALUES ('produkt','13','1','Produkt');
|
|
* INSERT INTO `front_menu_lang` (`name`, `id_lang`, `id_front_menu`, `link_rewrite`) VALUES ('Produkt','3','13','produkt');
|
|
* INSERT INTO `front_section` (`id`, `created_at`, `updated_at`, `name`, `img`, `component_name`, `is_no_lang`) VALUES ('32','2025-06-25 11:07:28.000','2025-06-25 11:07:28.000','product','[]','ProductBlock','1');
|
|
* INSERT INTO `front_page_section` (`id_front_page`, `id_position`, `id_front_section`) VALUES ('13','1','32');
|
|
* INSERT INTO `front_page_section` (`id_front_page`, `id_position`, `id_front_section`) VALUES ('13','2','4');
|
|
*/
|
|
</script>
|
|
|
|
<style>
|
|
.v-enter-active,
|
|
.v-leave-active {
|
|
transition: opacity 0.5s ease;
|
|
}
|
|
|
|
.v-enter-from,
|
|
.v-leave-to {
|
|
opacity: 0;
|
|
}
|
|
</style>
|