fix eslint

This commit is contained in:
2025-07-03 15:24:28 +02:00
parent e935e9f911
commit 9063846282
12 changed files with 784 additions and 1121 deletions

View File

@ -1,167 +1,55 @@
<template> <template>
<div ref="dropdownRef"> <div ref="dropdownRef">
<div @click="openCart = !openCart" class="relative cursor-pointer"> <div class="relative cursor-pointer" @click="openCart = !openCart">
<i class="uil uil-shopping-cart text-[31px]"></i> <i class="uil uil-shopping-cart text-[31px]"></i>
<div v-if="checkoutStore.products && checkoutStore.products.length > 0" <div v-if="checkoutStore.products && checkoutStore.products.length > 0"
class="w-[15px] h-[15px] rounded-full bg-accent-green-light dark:bg-accent-green-light text-white flex items-center justify-center text-[9px] absolute top-1 right-0"> class="w-[15px] h-[15px] rounded-full bg-accent-green-light dark:bg-accent-green-light text-white flex items-center justify-center text-[9px] absolute top-1 right-0">
{{ checkoutStore.products.length }}</div> {{ checkoutStore.products.length }}
</div> </div>
<div v-if="openCart" @click.self="openCart = !openCart"
class="absolute left-1/2 transform -translate-x-1/2 w-full px-4 sm:max-w-[768px] sm:px-[17px] md:max-w-[1000px] md:px-6 xl:max-w-[1920px] xl:px-20 right-0 z-50 flex items-center justify-end top-[100px] sm:top-[100px] md:top-[140px]">
<div class="xl:w-[55%] md:w-[90%] w-full px-4 md:px-0">
<div v-if="checkoutStore.products && checkoutStore.products.length > 0"
class="w-full p-[25px] sm:p-[50px] bg-bg-light dark:bg-bg-dark border border-button rounded-xl sm:rounded-[32px] h-full space-25-55">
<div>
<div v-for="item in checkoutStore.products"
class="py-[13px] sm:py-[25px] first:pt-0 border-b border-block">
<div class="flex items-center h-[100px] sm:h-[205px]">
<div
class="min-w-[100px] sm:min-w-[205px] flex items-center justify-center h-[100px] sm:h-[205px]">
<img :src="`/api/public/file/${item.picture_uuid}.webp`" alt=""
class="max-w-full max-h-full object-contain">
</div>
<div class="flex flex-col justify-between min-h-full w-full gap-[7px] sm:gap-[15px]">
<div class="w-full flex items-center justify-between">
<h3
class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] max-w-[100px] sm:max-w-[200px] md:max-w-[250px]">
{{ item.name }}
</h3>
<i @click="productStore.deleteCartItem(item.cart_item_id)"
class="uil uil-trash-alt text-lg sm:text-2xl cursor-pointer"></i>
</div>
<div class="flex flex-col gap-[10px]">
<p
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
{{ menuStore.formatPrice(Number(item.total_price)) }}
</p>
<div class="flex items-center gap-[2px] sm:gap-2 text-xl">
<div
class="w-5 min-h-5 sm:w-11 sm:min-h-11 text-[10px] sm:text-lg flex items-center justify-center">
<i class="uil uil-minus cursor-pointer text-gray dark:text-button-disabled hover:text-gray-200 transition-all"
@click="productStore.decrementCartItem(item.cart_item_id)"></i>
</div>
<div
class="w-5 min-h-5 sm:w-10 sm:min-h-11 text-[10px] sm:text-xl border border-button flex items-center justify-center rounded-[4px]">
{{ item.quantity }}
</div>
<div
class="w-5 min-h-5 sm:w-11 sm:min-h-11 text-[10px] sm:text-lg flex items-center justify-center">
<i class="uil uil-plus cursor-pointer hover:text-gray-200 transition-all"
@click="productStore.incrementCartItem(item.product_id)"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="flex items-center justify-between">
<h4 class="font-inter text-[12px] leading-[150%] font-bold uppercase sm:text-[24px]">{{
$t('total_amount') }}</h4>
<p
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
{{ menuStore.formatPrice(Number(checkoutStore.fullProductsPrice)) }}
</p>
</div>
<UiButtonArrow @click="() => {
if (userStore.isLogged) {
menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 12))
} else {
menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))
}
openCart = false
}" class="w-full" type="fill" :arrow="true" :full="true">{{ userStore.isLogged ?
$t('to_checkout') : $t('login') }}
</UiButtonArrow>
</div>
<div v-else
class="w-full p-[25px] sm:p-[50px] bg-bg-light dark:bg-bg-dark border border-button rounded-xl sm:rounded-[32px] flex items-center justify-center">
<div
class="border border-block inline-flex items-center justify-center h-[140px] sm:h-[200px] text-center rounded-[8px]">
<h4
class="font-inter text-base leading-[150%] font-bold uppercase sm:text-[20px] px-4 sm:px-10 md:text-xl">
{{ $t('empty_cart') }}</h4>
</div>
</div>
</div>
</div>
</div> </div>
<div <div v-if="openCart"
v-if="openCart" class="absolute left-1/2 transform -translate-x-1/2 w-full px-4 sm:max-w-[768px] sm:px-[17px] md:max-w-[1000px] md:px-6 xl:max-w-[1920px] xl:px-20 right-0 z-50 flex items-center justify-end top-[100px] sm:top-[100px] md:top-[140px]"
class="absolute left-1/2 transform -translate-x-1/2 w-full px-4 sm:max-w-[768px] sm:px-[17px] md:max-w-[1000px] md:px-6 xl:max-w-[1920px] xl:px-20 right-0 z-50 flex items-center justify-end top-[100px] sm:top-[100px] md:top-[140px]" @click.self="openCart = !openCart">
@click.self="openCart = !openCart"
>
<div class="xl:w-[55%] md:w-[90%] w-full px-4 md:px-0"> <div class="xl:w-[55%] md:w-[90%] w-full px-4 md:px-0">
<div <div v-if="checkoutStore.products && checkoutStore.products.length > 0"
v-if=" class="w-full p-[25px] sm:p-[50px] bg-bg-light dark:bg-bg-dark border border-button rounded-xl sm:rounded-[32px] h-full space-25-55">
productStore.cart.cart_items
&& productStore.cart.cart_items.length > 0
"
class="w-full p-[25px] sm:p-[50px] bg-bg-light dark:bg-bg-dark border border-button rounded-xl sm:rounded-[32px] h-full space-25-55"
>
<div> <div>
<!-- product --> <div v-for="(item, index) in checkoutStore.products" :key="index"
<div class="py-[13px] sm:py-[25px] first:pt-0 border-b border-block">
v-for="item in productStore.cart.cart_items" :key="item.product_id"
class="py-[13px] sm:py-[25px] first:pt-0 border-b border-block"
>
<div class="flex items-center h-[100px] sm:h-[205px]"> <div class="flex items-center h-[100px] sm:h-[205px]">
<div <div class="min-w-[100px] sm:min-w-[205px] flex items-center justify-center h-[100px] sm:h-[205px]">
class="min-w-[100px] sm:min-w-[205px] flex items-center justify-center h-[100px] sm:h-[205px]" <img :src="`/api/public/file/${item.picture_uuid}.webp`" alt=""
> class="max-w-full max-h-full object-contain">
<img
:src="`/api/public/file/${item.picture_uuid}.webp`"
alt=""
class="max-w-full max-h-full object-contain"
>
</div> </div>
<div <div class="flex flex-col justify-between min-h-full w-full gap-[7px] sm:gap-[15px]">
class="flex flex-col justify-between min-h-full w-full gap-[7px] sm:gap-[15px]"
>
<div class="w-full flex items-center justify-between"> <div class="w-full flex items-center justify-between">
<h3 <h3
class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] max-w-[100px] sm:max-w-[200px] md:max-w-[250px]" class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] max-w-[100px] sm:max-w-[200px] md:max-w-[250px]">
>
{{ item.name }} {{ item.name }}
</h3> </h3>
<i <i class="uil uil-trash-alt text-lg sm:text-2xl cursor-pointer"
class="uil uil-trash-alt text-lg sm:text-2xl cursor-pointer" @click="productStore.deleteCartItem(item.cart_item_id)"></i>
@click="productStore.deleteCartItem(item.cart_item_id)"
/>
</div> </div>
<div class="flex flex-col gap-[10px]"> <div class="flex flex-col gap-[10px]">
<p <p
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold" class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
> {{ menuStore.formatPrice(Number(item.total_price)) }}
{{ item.total_price }}
</p> </p>
<div class="flex items-center gap-[2px] sm:gap-2 text-xl"> <div class="flex items-center gap-[2px] sm:gap-2 text-xl">
<div <div
class="w-5 min-h-5 sm:w-11 sm:min-h-11 text-[10px] sm:text-lg flex items-center justify-center" class="w-5 min-h-5 sm:w-11 sm:min-h-11 text-[10px] sm:text-lg flex items-center justify-center">
> <i class="uil uil-minus cursor-pointer text-gray dark:text-button-disabled hover:text-gray-200 transition-all"
<i @click="productStore.decrementCartItem(item.cart_item_id)"></i>
class="uil uil-minus cursor-pointer text-gray dark:text-button-disabled hover:text-gray-200 transition-all"
@click="
productStore.decrementCartItem(item.cart_item_id)
"
/>
</div> </div>
<div <div
class="w-5 min-h-5 sm:w-10 sm:min-h-11 text-[10px] sm:text-xl border border-button flex items-center justify-center rounded-[4px]" class="w-5 min-h-5 sm:w-10 sm:min-h-11 text-[10px] sm:text-xl border border-button flex items-center justify-center rounded-[4px]">
>
{{ item.quantity }} {{ item.quantity }}
</div> </div>
<div <div
class="w-5 min-h-5 sm:w-11 sm:min-h-11 text-[10px] sm:text-lg flex items-center justify-center" class="w-5 min-h-5 sm:w-11 sm:min-h-11 text-[10px] sm:text-lg flex items-center justify-center">
> <i class="uil uil-plus cursor-pointer hover:text-gray-200 transition-all"
<i @click="productStore.incrementCartItem(item.product_id)"></i>
class="uil uil-plus cursor-pointer hover:text-gray-200 transition-all"
@click="
productStore.incrementCartItem(item.product_id)
"
/>
</div> </div>
</div> </div>
</div> </div>
@ -170,52 +58,34 @@
</div> </div>
</div> </div>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<h4 <h4 class="font-inter text-[12px] leading-[150%] font-bold uppercase sm:text-[24px]">
class="font-inter text-[12px] leading-[150%] font-bold uppercase sm:text-[24px]" {{
> $t('total_amount') }}
{{ $t("total_amount") }}
</h4> </h4>
<p <p
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold" class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
> {{ menuStore.formatPrice(Number(checkoutStore.fullProductsPrice)) }}
{{ productStore.cart.total_value }}
</p> </p>
</div> </div>
<UiButtonArrow <UiButtonArrow class="w-full" type="fill" :arrow="true" :full="true" @click="() => {
class="w-full" if (userStore.isLogged) {
type="fill" menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 12))
:arrow="true" }
:full="true" else {
@click=" menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))
() => { }
if (userStore.isLogged) { openCart = false
menuStore.navigateToItem( }">
menuStore.menuItems?.find((item) => item.id === 12), {{ userStore.isLogged
); ? $t('to_checkout') : $t('login') }}
}
else {
menuStore.navigateToItem(
menuStore.menuItems?.find((item) => item.id === 11),
);
}
openCart = false;
}
"
>
{{ userStore.isLogged ? $t("to_checkout") : $t("login") }}
</UiButtonArrow> </UiButtonArrow>
</div> </div>
<div <div v-else
v-else class="w-full p-[25px] sm:p-[50px] bg-bg-light dark:bg-bg-dark border border-button rounded-xl sm:rounded-[32px] flex items-center justify-center">
class="w-full p-[25px] sm:p-[50px] bg-bg-light dark:bg-bg-dark border border-button rounded-xl sm:rounded-[32px] flex items-center justify-center"
>
<div <div
class="border border-block inline-flex items-center justify-center h-[140px] sm:h-[200px] text-center rounded-[8px]" class="border border-block inline-flex items-center justify-center h-[140px] sm:h-[200px] text-center rounded-[8px]">
> <h4 class="font-inter text-base leading-[150%] font-bold uppercase sm:text-[20px] px-4 sm:px-10 md:text-xl">
<h4 {{ $t('empty_cart') }}
class="font-inter text-base leading-[150%] font-bold uppercase sm:text-[20px] px-4 sm:px-10 md:text-xl"
>
{{ $t("empty_cart") }}
</h4> </h4>
</div> </div>
</div> </div>
@ -229,7 +99,7 @@ import { onClickOutside } from '@vueuse/core'
const productStore = useProductStore() const productStore = useProductStore()
const checkoutStore = useCheckoutStore() const checkoutStore = useCheckoutStore()
const openCart = ref(false); const openCart = ref(false)
const menuStore = useMenuStore() const menuStore = useMenuStore()
const userStore = useUserStore() const userStore = useUserStore()

View File

@ -34,8 +34,8 @@
<div class="flex items-center gap-[30px]"> <div class="flex items-center gap-[30px]">
<div> <div>
<i v-if="!userStore.isLogged" <i v-if="!userStore.isLogged"
@click="menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))" class="uil uil-user text-[31px] cursor-pointer"
class="uil uil-user text-[31px] cursor-pointer"></i> @click="menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))"></i>
<div v-else class="py-[6px] px-3 border border-block rounded-sm"> <div v-else class="py-[6px] px-3 border border-block rounded-sm">
{{ userStore.user }} {{ userStore.user }}
</div> </div>
@ -375,11 +375,10 @@ import CountryCurrencySelector from './CountryCurrencySelector.vue'
import LangSwitcher from './LangSwitcher.vue' import LangSwitcher from './LangSwitcher.vue'
const userStore = useUserStore() const userStore = useUserStore()
const productStore = useProductStore()
const open = ref(false) const open = ref(false)
const colorMode = useColorMode() const colorMode = useColorMode()
const menuStore = useMenuStore(); const menuStore = useMenuStore()
const checkoutStore = useCheckoutStore(); const checkoutStore = useCheckoutStore()
checkoutStore.getUserCart() checkoutStore.getUserCart()

View File

@ -14,35 +14,30 @@
{{ component.front_section_lang[0].data.main_subtitle }} {{ component.front_section_lang[0].data.main_subtitle }}
</h4> </h4>
</div> </div>
<div <div class="rounded-2xl h-[340px] sm:h-[380px] md:min-w-[324px] xl:h-[800px] xl:min-w-[740px] m-0 sm:mx-10 md:m-0"
class="rounded-2xl h-[340px] sm:h-[380px] md:min-w-[324px] xl:h-[800px] xl:min-w-[740px] m-0 sm:mx-10 md:m-0" :style="{
:style="{ backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`, backgroundSize: 'cover',
backgroundSize: 'cover', backgroundPosition: 'center',
backgroundPosition: 'center', }"></div>
}"
></div>
</div> </div>
<div class="space-25-55-75"> <div class="space-25-55-75">
<h2 class="h2-bold-bounded"> <h2 class="h2-bold-bounded">
{{ component.front_section_lang[0].data.story_title }} {{ component.front_section_lang[0].data.story_title }}
</h2> </h2>
<div class="flex flex-col-reverse md:flex-row w-full gap-6"> <div class="flex flex-col-reverse md:flex-row w-full gap-6">
<div <div class="rounded-2xl h-[390px] md:h-auto min-w-[40%] xl:min-w-[60%]" :style="{
class="rounded-2xl h-[390px] md:h-auto min-w-[40%] xl:min-w-[60%]" backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`,
:style="{ backgroundSize: 'cover',
backgroundImage: `url('/api/public/file/${component.img[1]}_l.webp')`, backgroundPosition: 'center',
backgroundSize: 'cover', }"></div>
backgroundPosition: 'center',
}"
></div>
<div class="flex flex-col"> <div class="flex flex-col">
<p v-for="(item, index) in component.front_section_lang[0].data.story_description" :key="index"> <div v-for="(item, index) in component.front_section_lang[0].data.story_description" :key="index">
{{ item }} <p>{{ item }}</p>
</p><div v-if="index < component.front_section_lang[0].data.story_description.length - 1"> <div v-if="index < component.front_section_lang[0].data.story_description.length - 1">
<br> <br>
</div>
</div> </div>
</p>
</div> </div>
</div> </div>
<div class="flex flex-col w-full gap-6"> <div class="flex flex-col w-full gap-6">
@ -50,14 +45,12 @@
{{ component.front_section_lang[0].data.story_subtitle }} {{ component.front_section_lang[0].data.story_subtitle }}
</h4> </h4>
<div class="flex flex-col justify-between xl:max-w-[70%]"> <div class="flex flex-col justify-between xl:max-w-[70%]">
<p v-for="(el, indexEl) in component.front_section_lang[0].data.story_sub_description" <div v-for="(el, indexEl) in component.front_section_lang[0].data.story_sub_description" :key="indexEl">
:key="indexEl" <p>{{ el }}</p>
> <div v-if="indexEl < component.front_section_lang[0].data.story_sub_description.length - 1">
{{ el }} <br>
</p><div v-if="indexEl < component.front_section_lang[0].data.story_sub_description.length - 1"> </div>
<br>
</div> </div>
</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,160 +1,173 @@
<template> <template>
<UiContainer v-if="checkoutStore.modalMadeOrder">
<NuxtLink to="/" class="mt-6 text-blue-500 underline" @click="checkoutStore.modalMadeOrder = false">Go back home
</NuxtLink>
</UiContainer>
<UiContainer v-if="checkoutStore.modalMadeOrder"> <UiContainer v-else>
<NuxtLink to="/" class="mt-6 text-blue-500 underline" @click="checkoutStore.modalMadeOrder = false">Go back home <div class="xl:w-[85%] mx-auto space-25-55">
</NuxtLink> <div class="space-25-55">
</UiContainer> <div class="w-full flex items-center sm:justify-center">
<div
<UiContainer v-else> class="flex items-center justify-between sm:justify-center sm:gap-[25px] text-gray dark:text-button-disabled w-full sm:w-auto">
<div class="xl:w-[85%] mx-auto space-25-55"> <div class="sm:px-6 sm:py-3 mx-auto">
<div class="space-25-55"> {{ $t("login") }}
<div class="w-full flex items-center sm:justify-center">
<div
class="flex items-center justify-between sm:justify-center sm:gap-[25px] text-gray dark:text-button-disabled w-full sm:w-auto">
<div class="sm:px-6 sm:py-3 mx-auto">
{{ $t("login") }}
</div>
<div class="sm:px-6 sm:py-3 mx-auto">
{{ $t("address") }}
</div>
<div
class="cursor-pointer transition-all text-inter hover:bg-button-hover bg-button text-white font-medium rounded-xl px-3 py-1 sm:px-6 sm:py-3">
{{ $t("summary") }}
</div>
<div class="hidden sm:block sm:px-6 sm:py-3 sm:mx-auto">
{{ $t("order_placed") }}
</div>
</div>
</div>
</div> </div>
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-[30px]"> <div class="sm:px-6 sm:py-3 mx-auto">
<div class="col-start-1 col-end-2 sm:col-end-3 space-y-5"> {{ $t("address") }}
<h4 class="h4-uppercase-bold-inter">{{ component.front_section_lang[0].data.product_list }}</h4>
<div class="border-2 border-block rounded-[15px] p-[25px] sm:p-[50px] space-25-55">
<div v-for="(item, index) in checkoutStore.products" :key="index">
<div class="flex items-center h-[100px] sm:h-[150px]">
<div
class="min-w-[100px] sm:min-w-[150px] flex items-center justify-center h-[100px] sm:h-[150px]">
<img :src="`/api/public/file/${item.picture_uuid}.webp`" alt=""
class="max-w-full max-h-full object-contain">
</div>
<div class="flex flex-col justify-between min-h-full w-full gap-[7px] sm:gap-[15px]">
<div class="w-full flex items-center justify-between">
<h3
class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] max-w-[100px] sm:max-w-[200px] md:max-w-[250px]">
{{ item.name }}
</h3>
</div>
<div class="flex w-full justify-between gap-[10px]">
<p
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
{{ item.total_price }}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="col-start-1 col-end-2 sm:col-end-3 xl:col-auto flex flex-col sm:flex-row xl:flex-col items-center gap-[30px]">
<div class="space-y-5 w-full">
<h4 class="h4-uppercase-bold-inter">{{ component.front_section_lang[0].data.account_address }}
</h4>
<div
class="border-2 border-block rounded-[8px] px-[25px] py-[15px] flex flex-col gap-1 text-sm sm:text-lg md:text-xl">
<span>{{ checkoutStore.defaultAddress?.address.name }} {{
checkoutStore.defaultAddress?.address.surname }}</span>
<span>{{ checkoutStore.defaultAddress?.address.street }}</span>
<span>{{ checkoutStore.defaultAddress?.address.postcode }} {{
checkoutStore.defaultAddress?.address.city }}</span>
</div>
</div>
<div class="flex flex-col space-y-5 w-full h-full">
<h4 class="h4-uppercase-bold-inter">{{ component.front_section_lang[0].data.note }}</h4>
<textarea v-model="checkoutStore.vNote"
class="border-2 border-block rounded-[8px] p-[15px] w-full flex-1 resize-none placeholder:text-button"
name="rty" id="1" :placeholder="component.front_section_lang[0].data.note"></textarea>
</div>
</div>
<div class="col-start-1 col-end-2 xl:col-end-3 space-y-5">
<h4 class="h4-uppercase-bold-inter">{{ component.front_section_lang[0].data.delivery_type }}</h4>
<div
class="border-2 border-block rounded-[15px] p-[25px] sm:p-[50px] space-y-[25px] text-sm sm:text-lg md:text-xl">
<div @click="checkoutStore.setCurrentDelivery(delivery)"
v-for="delivery in checkoutStore.deliveryOption" class="flex flex-col cursor-pointer">
<div class="flex items-end justify-between">
<div class="flex gap-[15px]">
<div class="mt-1 w-4 h-4 border-2 border-button rounded-full">
<div v-if="checkoutStore.currentDelivery === delivery"
class="w-full h-full border-3 border-bg-light dark:border-bg-dark rounded-full bg-button">
</div>
</div>
<div class="flex flex-col">
<span>{{ delivery.delivery_supplier_name }}</span>
<span>{{ delivery.country_name }}</span>
</div>
</div>
<p class="font-inter text-lg sm:text-[21px] md:text-2xl leading-[150%] font-bold">
{{ menuStore.formatPrice(Number(delivery.shippment_price)) }}
</p>
</div>
</div>
</div>
</div>
<div class="space-y-5 w-full flex flex-col h-full">
<h4 class="h4-uppercase-bold-inter">{{ component.front_section_lang[0].data.payment_method }}</h4>
<div
class="border-2 border-block rounded-[8px] px-[25px] py-[25px] sm:py-[15px] flex-1 flex flex-col gap-1 text-sm sm:text-xl overflow-auto">
<UCarousel :prevIcon="'i-lucide-chevron-left'" :nextIcon="'i-lucide-chevron-right'" :ui="{
viewport: 'h-full w-full',
container: 'h-full w-full',
item: 'h-full w-full pl-7',
prev: '-start-8 sm:-start-12 ring-0 text-button disable:text-block p-0 ring-inset ring-accented bg-inherit disabled:bg-inherit',
next: '-end-8 sm:-end-12 ring-0 text-button disable:text-block p-0 text-[30px] bg-inherit disabled:bg-inherit',
arrows: ''
}" :prev="{ size: 'xl' }" :next="{ size: 'xl' }" arrows :items="checkoutStore.paymentMethods"
class="relative sm:max-w-full mx-4 sm:mx-10 h-full">
<template #default="{ item }">
<div
class="flex flex-col items-start justify-between h-full leading-[250%] sm:leading-[150%]">
<span>{{ item.bank_name }}</span>
<span>{{ item.country_name }}</span>
<span>{{ item.street_and_number }}</span>
<span>{{ item.iban }}</span>
<span>{{ item.swift }}</span>
</div>
</template>
</UCarousel>
</div>
</div>
</div> </div>
<div class="w-full border-y-2 border-block p-[25px] flex flex-col gap-[15px]"> <div
<div class="flex items-center justify-between"> class="cursor-pointer transition-all text-inter hover:bg-button-hover bg-button text-white font-medium rounded-xl px-3 py-1 sm:px-6 sm:py-3">
<p class="text-sm sm:text-xl">{{ component.front_section_lang[0].data.subtotal }}</p> {{ $t("summary") }}
<p class="text-lg sm:text-xl font-medium">{{ </div>
menuStore.formatPrice(Number(checkoutStore.fullProductsPrice)) }} <div class="hidden sm:block sm:px-6 sm:py-3 sm:mx-auto">
</p> {{ $t("order_placed") }}
</div>
</div>
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-[30px]">
<div class="col-start-1 col-end-2 sm:col-end-3 space-y-5">
<h4 class="h4-uppercase-bold-inter">
{{ component.front_section_lang[0].data.product_list }}
</h4>
<div class="border-2 border-block rounded-[15px] p-[25px] sm:p-[50px] space-25-55">
<div v-for="(item, index) in checkoutStore.products" :key="index">
<div class="flex items-center h-[100px] sm:h-[150px]">
<div class="min-w-[100px] sm:min-w-[150px] flex items-center justify-center h-[100px] sm:h-[150px]">
<img :src="`/api/public/file/${item.picture_uuid}.webp`" alt=""
class="max-w-full max-h-full object-contain">
</div> </div>
<div class="flex items-center justify-between">
<p class="text-sm sm:text-xl">{{ component.front_section_lang[0].data.shipping_cost }}</p> <div class="flex flex-col justify-between min-h-full w-full gap-[7px] sm:gap-[15px]">
<p class="text-lg sm:text-xl font-medium">{{ <div class="w-full flex items-center justify-between">
menuStore.formatPrice(Number(checkoutStore.shippingPrice)) }}</p> <h3
</div> class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] max-w-[100px] sm:max-w-[200px] md:max-w-[250px]">
<div class="flex items-center justify-between uppercase text-lg sm:text-xl"> {{ item.name }}
<p>{{ component.front_section_lang[0].data.total }}</p> </h3>
</div>
<div class="flex w-full justify-between gap-[10px]">
<p <p
class="text-accent-green-light dark:text-accent-green-dark font-inter text-xl sm:text-2xl leading-[150%] font-bold"> class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
{{ menuStore.formatPrice(Number(checkoutStore.fullPrice)) }} {{ item.total_price }}
</p> </p>
</div>
</div> </div>
</div>
</div> </div>
<div class="flex flex-col sm:flex-row items-center justify-between mt-1 gap-[55px]"> </div>
<div class="flex flex-col gap-1 text-white w-full"> </div>
<div class="flex gap-3 text-black dark:text-white items-center"> <div
<input v-model="checkoutStore.vLegal" type="checkbox" id="first" name="first" /> class="col-start-1 col-end-2 sm:col-end-3 xl:col-auto flex flex-col sm:flex-row xl:flex-col items-center gap-[30px]">
<!-- <label for="first" class="text-sm leading-snug"> <div class="space-y-5 w-full">
<h4 class="h4-uppercase-bold-inter">
{{ component.front_section_lang[0].data.account_address }}
</h4>
<div
class="border-2 border-block rounded-[8px] px-[25px] py-[15px] flex flex-col gap-1 text-sm sm:text-lg md:text-xl">
<span>{{ checkoutStore.defaultAddress?.address.name }} {{
checkoutStore.defaultAddress?.address.surname }}</span>
<span>{{ checkoutStore.defaultAddress?.address.street }}</span>
<span>{{ checkoutStore.defaultAddress?.address.postcode }} {{
checkoutStore.defaultAddress?.address.city }}</span>
</div>
</div>
<div class="flex flex-col space-y-5 w-full h-full">
<h4 class="h4-uppercase-bold-inter">
{{ component.front_section_lang[0].data.note }}
</h4>
<textarea id="1" v-model="checkoutStore.vNote"
class="border-2 border-block rounded-[8px] p-[15px] w-full flex-1 resize-none placeholder:text-button"
name="rty" :placeholder="component.front_section_lang[0].data.note"></textarea>
</div>
</div>
<div class="col-start-1 col-end-2 xl:col-end-3 space-y-5">
<h4 class="h4-uppercase-bold-inter">
{{ component.front_section_lang[0].data.delivery_type }}
</h4>
<div
class="border-2 border-block rounded-[15px] p-[25px] sm:p-[50px] space-y-[25px] text-sm sm:text-lg md:text-xl">
<div v-for="(delivery, index) in checkoutStore.deliveryOption" :key="index"
class="flex flex-col cursor-pointer" @click="checkoutStore.setCurrentDelivery(delivery)">
<div class="flex items-end justify-between">
<div class="flex gap-[15px]">
<div class="mt-1 w-4 h-4 border-2 border-button rounded-full">
<div v-if="checkoutStore.currentDelivery === delivery"
class="w-full h-full border-3 border-bg-light dark:border-bg-dark rounded-full bg-button">
</div>
</div>
<div class="flex flex-col">
<span>{{ delivery.delivery_supplier_name }}</span>
<span>{{ delivery.country_name }}</span>
</div>
</div>
<p class="font-inter text-lg sm:text-[21px] md:text-2xl leading-[150%] font-bold">
{{ menuStore.formatPrice(Number(delivery.shippment_price)) }}
</p>
</div>
</div>
</div>
</div>
<div class="space-y-5 w-full flex flex-col h-full">
<h4 class="h4-uppercase-bold-inter">
{{ component.front_section_lang[0].data.payment_method }}
</h4>
<div
class="border-2 border-block rounded-[8px] px-[25px] py-[25px] sm:py-[15px] flex-1 flex flex-col gap-1 text-sm sm:text-xl overflow-auto">
<UCarousel :prev-icon="'i-lucide-chevron-left'" :next-icon="'i-lucide-chevron-right'" :ui="{
viewport: 'h-full w-full',
container: 'h-full w-full',
item: 'h-full w-full pl-7',
prev: '-start-8 sm:-start-12 ring-0 text-button disable:text-block p-0 ring-inset ring-accented bg-inherit disabled:bg-inherit',
next: '-end-8 sm:-end-12 ring-0 text-button disable:text-block p-0 text-[30px] bg-inherit disabled:bg-inherit',
arrows: '',
}" :prev="{ size: 'xl' }" :next="{ size: 'xl' }" arrows :items="checkoutStore.paymentMethods"
class="relative sm:max-w-full mx-4 sm:mx-10 h-full">
<template #default="{ item }">
<div class="flex flex-col items-start justify-between h-full leading-[250%] sm:leading-[150%]">
<span>{{ item.bank_name }}</span>
<span>{{ item.country_name }}</span>
<span>{{ item.street_and_number }}</span>
<span>{{ item.iban }}</span>
<span>{{ item.swift }}</span>
</div>
</template>
</UCarousel>
</div>
</div>
</div>
<div class="w-full border-y-2 border-block p-[25px] flex flex-col gap-[15px]">
<div class="flex items-center justify-between">
<p class="text-sm sm:text-xl">
{{ component.front_section_lang[0].data.subtotal }}
</p>
<p class="text-lg sm:text-xl font-medium">
{{
menuStore.formatPrice(Number(checkoutStore.fullProductsPrice)) }}
</p>
</div>
<div class="flex items-center justify-between">
<p class="text-sm sm:text-xl">
{{ component.front_section_lang[0].data.shipping_cost }}
</p>
<p class="text-lg sm:text-xl font-medium">
{{
menuStore.formatPrice(Number(checkoutStore.shippingPrice)) }}
</p>
</div>
<div class="flex items-center justify-between uppercase text-lg sm:text-xl">
<p>{{ component.front_section_lang[0].data.total }}</p>
<p
class="text-accent-green-light dark:text-accent-green-dark font-inter text-xl sm:text-2xl leading-[150%] font-bold">
{{ menuStore.formatPrice(Number(checkoutStore.fullPrice)) }}
</p>
</div>
</div>
<div class="flex flex-col sm:flex-row items-center justify-between mt-1 gap-[55px]">
<div class="flex flex-col gap-1 text-white w-full">
<div class="flex gap-3 text-black dark:text-white items-center">
<input id="first" v-model="checkoutStore.vLegal" type="checkbox" name="first" />
<!-- <label for="first" class="text-sm leading-snug">
{{ $t("I accept ") }} {{ $t("I accept ") }}
<NuxtLink target="_blank" <NuxtLink target="_blank"
:to="{ name: 'lang-info-name', params: { lang: menuStore.selectedLanguage.iso_code, name: 'legal_statement.html' } }" :to="{ name: 'lang-info-name', params: { lang: menuStore.selectedLanguage.iso_code, name: 'legal_statement.html' } }"
@ -162,15 +175,17 @@
{{ $t("the legal statement*") }} {{ $t("the legal statement*") }}
</NuxtLink> </NuxtLink>
</label> --> </label> -->
<p class="text-sm sm:text-lg"> {{ $t("I accept ") }} {{ $t("the legal statement*") }}</p> <p class="text-sm sm:text-lg">
</div> {{ $t("I accept ") }} {{ $t("the legal statement*") }}
<span v-if="checkoutStore.legalValidation" class="text-xs text-red-600 ml-6"> </p>
{{ $t("You need to accept this") }} </div>
</span> <span v-if="checkoutStore.legalValidation" class="text-xs text-red-600 ml-6">
{{ $t("You need to accept this") }}
</span>
<div class="flex gap-3 text-black dark:text-white items-center mt-2"> <div class="flex gap-3 text-black dark:text-white items-center mt-2">
<input v-model="checkoutStore.vTerms" type="checkbox" id="second" name="second" /> <input id="second" v-model="checkoutStore.vTerms" type="checkbox" name="second" />
<!-- <label for="second" class="text-sm leading-snug"> <!-- <label for="second" class="text-sm leading-snug">
{{ $t("I accept ") }} {{ $t("I accept ") }}
<NuxtLink target="_blank" <NuxtLink target="_blank"
:to="{ name: 'lang-info-name', params: { lang: menuStore.selectedLanguage.iso_code, name: 'general_terms_and_conditions.html' } }" :to="{ name: 'lang-info-name', params: { lang: menuStore.selectedLanguage.iso_code, name: 'general_terms_and_conditions.html' } }"
@ -178,83 +193,27 @@
{{ $t("general terms and conditions*") }} {{ $t("general terms and conditions*") }}
</NuxtLink> </NuxtLink>
</label> --> </label> -->
<p class="text-sm sm:text-lg"> {{ $t("I accept ") }} {{ $t("general terms and conditions*") }} <p class="text-sm sm:text-lg">
</p> {{ $t("I accept ") }} {{ $t("general terms and conditions*") }}
</div> </p>
<span v-if="checkoutStore.termsValidation" class="text-xs text-red-600 ml-6"> </div>
{{ $t("You need to accept this") }} <span v-if="checkoutStore.termsValidation" class="text-xs text-red-600 ml-6">
</span> {{ $t("You need to accept this") }}
</div> </span>
</div>
<UiButtonArrow @click="checkoutStore.sendSummaryForm" type="fill" :arrow="true"> <UiButtonArrow type="fill" :arrow="true" @click="checkoutStore.sendSummaryForm">
{{ $t("Buy") }} {{ $t("Buy") }}
</UiButtonArrow> </UiButtonArrow>
</div> </div>
<div </div>
class="cursor-pointer transition-all text-inter hover:bg-button-hover bg-button text-white font-medium rounded-xl px-3 py-1 sm:px-6 sm:py-3"> </UiContainer>
{{ $t("summary") }}
</div>
<div class="hidden sm:block sm:px-6 sm:py-3 sm:mx-auto">
{{ $t("order_placed") }}
</div>
</div>
</div>
</div>
<div class="grid grid-cols-3 gap-[30px]">
<div class="col-start-1 col-end-3 space-y-5">
<h4 class="h4-uppercase-bold-inter">
Seznam produktů
</h4>
<div class="border-2 border-block rounded-2xl p-[50px] space-25-55">
<div v-for="(item, index) in checkoutStore.products" :key="index">
<div class="flex items-center h-[150px]">
<div class="min-w-[150px] flex items-center justify-center h-[150px]">
<img :src="`/api/public/file/${item.picture_uuid}.webp`" alt=""
class="max-w-full max-h-full object-contain">
</div>
<div class="flex flex-col justify-between min-h-full w-full gap-[7px] sm:gap-[15px]">
<div class="w-full flex items-center justify-between">
<h3
class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] max-w-[100px] sm:max-w-[200px] md:max-w-[250px]">
{{ item.name }}
</h3>
</div>
<div class="flex w-full justify-between gap-[10px]">
<p
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
{{ item.total_price }}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="">
<div class="space-y-5">
<h4 class="h4-uppercase-bold-inter">
Adresa účtu
</h4>
<div class="border-2 border-block rounded-2xl px-2 py-3 flex flex-col gap-1">
<span>{{ checkoutStore.defaultAddress?.address.name }}
{{ checkoutStore.defaultAddress?.address.surname }}</span>
<span>{{ checkoutStore.defaultAddress?.address.street }}</span>
<span>{{ checkoutStore.defaultAddress?.address.postcode }}
{{ checkoutStore.defaultAddress?.address.city }}</span>
</div>
</div>
</div>
</div>
</div>
</UiContainer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { UCarousel } from '#components'; import { UCarousel } from '#components'
const checkoutStore = useCheckoutStore(); const checkoutStore = useCheckoutStore()
const productStore = useProductStore()
const menuStore = useMenuStore() const menuStore = useMenuStore()
checkoutStore.getOrder() checkoutStore.getOrder()
@ -264,30 +223,30 @@ checkoutStore.getDeliveryOptions()
checkoutStore.getDefAddress() checkoutStore.getDefAddress()
defineProps<{ defineProps<{
component: { component: {
id: number id: number
name: string name: string
img: string[] img: string[]
component_name: string component_name: string
is_no_lang: boolean is_no_lang: boolean
page_name: string page_name: string
front_section_lang: { front_section_lang: {
data: { data: {
product_list: string product_list: string
account_address: string account_address: string
note: string note: string
delivery_type: string delivery_type: string
payment_method: string payment_method: string
subtotal: string subtotal: string
shipping_cost: string shipping_cost: string
total: string total: string
accept: string accept: string
legal: string legal: string
terms: string terms: string
} }
id_front_section: number id_front_section: number
id_lang: number id_lang: number
}[] }[]
} }
}>(); }>()
</script> </script>

View File

@ -1,15 +1,10 @@
<template> <template>
<UiContainer v-if="!userStore.vCodeVerify" <UiContainer v-if="!userStore.vCodeVerify" class="flex py-20 sm:py-14">
class="flex py-20 sm:py-14" <div class="hidden xl:block rounded-2xl min-w-[60%] h-[830px]" :style="{
> backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
<div backgroundSize: 'cover',
class="hidden xl:block rounded-2xl min-w-[60%] h-[830px]" backgroundPosition: 'center',
:style="{ }" />
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
backgroundSize: 'cover',
backgroundPosition: 'center',
}"
/>
<div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12"> <div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12">
<div class="space-25-55"> <div class="space-25-55">
<div class="flex flex-wrap-reverse gap-y-4 justify-between"> <div class="flex flex-wrap-reverse gap-y-4 justify-between">
@ -18,8 +13,7 @@
</h2> </h2>
<button <button
class="h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer" class="h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer"
@click="menuStore.navigateToItem()" @click="menuStore.navigateToItem()">
>
{{ $t("back_to_home") }} {{ $t("back_to_home") }}
</button> </button>
</div> </div>
@ -27,37 +21,22 @@
<p class="pl-6"> <p class="pl-6">
{{ $t("email") }} {{ $t("email") }}
</p> </p>
<input <input v-model="userStore.email" :placeholder="$t('email')" type="text"
v-model="userStore.email" class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2">
:placeholder="$t('email')"
type="text"
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
>
</div> </div>
<div class="space-y-[15px]"> <div class="space-y-[15px]">
<p class="pl-6"> <p class="pl-6">
{{ $t("password") }} {{ $t("password") }}
</p> </p>
<input <input v-model="userStore.password" :placeholder="$t('placeholder_password')" type="text"
v-model="userStore.password" class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2">
:placeholder="$t('placeholder_password')"
type="text"
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
>
</div> </div>
</div> </div>
<p <p class="text-button hover:text-button-hover transition-all font-medium mt-[30px] cursor-pointer">
class="text-button hover:text-button-hover transition-all font-medium mt-[30px] cursor-pointer"
>
{{ $t("forgot_password_question") }} {{ $t("forgot_password_question") }}
</p> </p>
<div <div class="py-[25px] sm:py-12 border-b border-gray flex justify-center w-full">
class="py-[25px] sm:py-12 border-b border-gray flex justify-center w-full" <UiButtonArrow type="fill" :arrow="true" @click="userStore.logIn()">
>
<UiButtonArrow type="fill"
:arrow="true"
@click="userStore.logIn()"
>
{{ {{
$t("login") $t("login")
}} }}
@ -74,17 +53,12 @@
</div> </div>
</UiContainer> </UiContainer>
<UiContainer v-if="userStore.vCodeVerify" <UiContainer v-if="userStore.vCodeVerify" class="flex py-20 sm:py-14">
class="flex py-20 sm:py-14" <div class="hidden xl:block rounded-2xl min-w-[60%] h-[830px]" :style="{
> backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
<div backgroundSize: 'cover',
class="hidden xl:block rounded-2xl min-w-[60%] h-[830px]" backgroundPosition: 'center',
:style="{ }" />
backgroundImage: `url('/api/public/file/${component.img[0]}_l.webp')`,
backgroundSize: 'cover',
backgroundPosition: 'center',
}"
/>
<div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12"> <div class="w-full sm:w-[80%] mx-auto my-auto xl:w-full xl:px-12">
<div class="space-25-55"> <div class="space-25-55">
<div class="flex flex-wrap-reverse gap-y-4 justify-between"> <div class="flex flex-wrap-reverse gap-y-4 justify-between">
@ -93,8 +67,7 @@
</h2> </h2>
<button <button
class="h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer" class="h-[40px] sm:h-[43px] px-[10px] sm:px-[17px] border border-gray dark:border-button-disabled text-gray dark:text-button-disabled hover:bg-gray transition-all hover:text-white rounded-[8px] cursor-pointer"
@click="menuStore.navigateToItem()" @click="menuStore.navigateToItem()">
>
{{ $t("back_to_home") }} {{ $t("back_to_home") }}
</button> </button>
</div> </div>
@ -108,21 +81,13 @@
<p class="pl-6"> <p class="pl-6">
{{ $t("code") }} {{ $t("code") }}
</p> </p>
<input <input v-model="userStore.vCode" :placeholder="$t('code')" type="text"
v-model="userStore.vCode" class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2">
:placeholder="$t('code')"
type="text"
class="border-2 border-block placeholder:text-gray dark:placeholder:text-button-disabled text-bg-dark dark:text-bg-light rounded-lg px-6 h-[50px] sm:h-[67px] w-full focus:outline-none focus:ring-0 focus:border-2"
>
</div> </div>
</div> </div>
</div> </div>
<div class="py-[25px] sm:py-12 flex justify-center w-full"> <div class="py-[25px] sm:py-12 flex justify-center w-full">
<UiButtonArrow <UiButtonArrow type="fill" :arrow="true" @click="userStore.sendFormCode(true)">
type="fill"
:arrow="true"
@click="userStore.sendFormCode(true)"
>
{{ $t("confirm") }} {{ $t("confirm") }}
</UiButtonArrow> </UiButtonArrow>
</div> </div>
@ -140,7 +105,6 @@ defineProps<{
is_no_lang: boolean is_no_lang: boolean
page_name: string page_name: string
front_section_lang: { front_section_lang: {
data: {}
id_front_section: number id_front_section: number
id_lang: number id_lang: number
}[] }[]

View File

@ -1,54 +1,40 @@
<template> <template>
<div> <div>
<nuxt-link <nuxt-link :to="{
:to="{ name: `id-slug___${$i18n.locale}`,
name: `id-slug___${$i18n.locale}`, params: {
params: { id: menuStore.getProductMenu()?.id,
id: menuStore.getProductMenu()?.id, slug: menuStore.getProductMenu()?.front_menu_lang.at(0)?.link_rewrite,
slug: menuStore.getProductMenu()?.front_menu_lang.at(0)?.link_rewrite, },
}, query: {
query: { prod_id: product.id,
prod_id: props.product?.id, name: product.link_rewrite,
name: props.product?.link_rewrite, },
}, }">
}"
>
<div <div
class="w-[150px] sm:w-[260px] md:w-[330px] px-2 py-3 sm:py-5 sm:px-[15px] bg-block rounded-2xl flex flex-col items-center gap-[15px] sm:gap-[50px]" class="w-[150px] sm:w-[260px] md:w-[330px] px-2 py-3 sm:py-5 sm:px-[15px] bg-block rounded-2xl flex flex-col items-center gap-[15px] sm:gap-[50px] h-full">
> <img :src="`/api/public/file/${product.cover_picture_uuid}.webp`" alt="Product Image"
<img class="h-[95px] sm:h-[180px] md:h-[205px] rounded-[5px]" @error="handleImageError" />
:src="`/api/public/file/${props.product?.cover_picture_uuid}.webp`"
alt="Product Image"
class="h-[95px] sm:h-[180px] md:h-[205px] rounded-[5px]"
onerror="this.onerror=null; this.src='/photo.svg';"
>
<div <div class="flex flex-col justify-between h-full w-full gap-[7px] sm:gap-[15px]">
class="flex flex-col justify-between h-full w-full gap-[7px] sSm:gap-[15px]"
>
<div class="flex flex-col gap-[7px] sm:gap-[15px] w-full"> <div class="flex flex-col gap-[7px] sm:gap-[15px] w-full">
<h3 <h3
class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] text-bg-dark" class="text-[10px] sm:text-base md:text-lg text-xl font-bold leading-[130%] sm:leading-[150%] text-bg-dark">
> {{ product.name }}
{{ props.product?.name }}
</h3> </h3>
<p class="text-[9px] sm:text-[12px] text-sm text-bg-dark"> <p class="text-[9px] sm:text-[12px] text-sm text-bg-dark">
{{ props.product?.tax_name }} {{ product.tax_name }}
</p> </p>
</div> </div>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<p <p
class="text-accent-green-light font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold" class="text-accent-green-light font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold">
> {{ product.formatted_price }}
{{ props.product?.formatted_price }}
</p> </p>
<button <button
class="w-[22px] h-[22px] sm:w-9 sm:h-9 md:w-12 md:h-12 rounded-[5px] text-bg-light sm:rounded-xl bg-button cursor-pointer hover:bg-button-hover transition-all flex items-center justify-center p-1" class="w-[22px] h-[22px] sm:w-9 sm:h-9 md:w-12 md:h-12 rounded-[5px] text-bg-light sm:rounded-xl bg-button cursor-pointer hover:bg-button-hover transition-all flex items-center justify-center p-1"
@click.self="productStore.incrementCartItem(props.product?.id)" @click.stop.prevent="productStore.incrementCartItem(product.id)">
> <i class="uil uil-shopping-cart text-lg sm:text-2xl md:text-[31px]" />
<i
class="uil uil-shopping-cart text-lg sm:text-2xl md:text-[31px] cursor-pointer"
/>
</button> </button>
</div> </div>
</div> </div>
@ -58,17 +44,22 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const props = defineProps({ interface Product {
product: Object, id: number
}) name: string
link_rewrite: string
tax_name: string
formatted_price: string
cover_picture_uuid: string
}
defineProps<{ product: Product }>()
const productStore = useProductStore() const productStore = useProductStore()
const menuStore = useMenuStore() const menuStore = useMenuStore()
const isError = ref(false);
function handleImageError(event: Event) { function handleImageError(event: Event) {
isError.value = true; const img = event.target as HTMLImageElement
(event.target as HTMLImageElement).src = '/photo.svg'; img.src = '/photo.svg'
} }
</script> </script>

View File

@ -248,17 +248,6 @@ const goRight = () => {
curImage.value = product.value.picture_uuids[0] 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> </script>
<style> <style>

View File

@ -8,89 +8,50 @@
<div class="xl:hidden flex items-center w-full"> <div class="xl:hidden flex items-center w-full">
<button <button
class="h-[40px] w-full cursor-pointer rounded-[10px] px-[22px] transition-all sm:h-[50px] md:h-[65px] md:rounded-[15px] md:px-[42px] bg-button text-text-dark group-hover:bg-button-hover" class="h-[40px] w-full cursor-pointer rounded-[10px] px-[22px] transition-all sm:h-[50px] md:h-[65px] md:rounded-[15px] md:px-[42px] bg-button text-text-dark group-hover:bg-button-hover"
@click="openCategories = !openCategories" @click="openCategories = !openCategories">
>
Otevřené kategorie a filtry Otevřené kategorie a filtry
</button> </button>
</div> </div>
<Transition> <Transition>
<div v-if="openCategories" <div v-if="openCategories" class="min-w-[250px] px-5 sm:p-0 xl:hidden">
class="min-w-[250px] px-5 sm:p-0 xl:hidden" <h1 class="font-bounded leading-[140%] font-bold text-[24px] mb-[25px]">
>
<h1
class="font-bounded leading-[140%] font-bold text-[24px] mb-[25px]"
>
{{ $t("category") }} {{ $t("category") }}
</h1> </h1>
<div class="flex flex-col gap-[25px]"> <div class="flex flex-col gap-[25px]">
<div> <div>
<div <div v-if="categoriesList && categoriesList.length < 1" class="animate-pulse">
v-if="categoriesList && categoriesList.length < 1" <div class="flex items-center justify-between mt-4 text-white rounded-lg cursor-pointer xl:pr-24">
class="animate-pulse"
>
<div
class="flex items-center justify-between mt-4 text-white rounded-lg cursor-pointer xl:pr-24"
>
<div class="w-32 h-4 bg-gray-200 rounded" /> <div class="w-32 h-4 bg-gray-200 rounded" />
<div class="w-4 h-4 bg-gray-200 rounded-full" /> <div class="w-4 h-4 bg-gray-200 rounded-full" />
</div> </div>
</div> </div>
<CategoryTree <CategoryTree :data="categoriesList" :active="categoryId" @change-category="changeCategory($event)" />
:data="categoriesList"
:active="categoryId"
@change-category="changeCategory($event)"
/>
</div> </div>
<div> <div>
<p <p class="mb-[25px] text-lg font-extrabold text-black dark:text-white">
class="mb-[25px] text-lg font-extrabold text-black dark:text-white"
>
{{ $t("filtered_by") }} {{ $t("filtered_by") }}
</p> </p>
<div <div v-for="(item, itemIndex) in filters" :key="itemIndex" :class="[
v-for="(item, itemIndex) in filters" 'mb-[30px]',
:key="itemIndex" visibleFeatures[item.feature] && 'border-b border-block pb-2',
:class="[ ]">
'mb-[30px]', <span class="flex justify-between items-center font-bold cursor-pointer mb-[25px] text-base"
visibleFeatures[item.feature] && 'border-b border-block pb-2', @click="toggleFeature(item.feature)">
]"
>
<span
class="flex justify-between items-center font-bold cursor-pointer mb-[25px] text-base"
@click="toggleFeature(item.feature)"
>
{{ item.feature }} {{ item.feature }}
<span <span :class="[
:class="[ visibleFeatures[item.feature] && 'rotate-180',
visibleFeatures[item.feature] && 'rotate-180', 'transition-all',
'transition-all', ]"><i class="iconify i-lucide:chevron-down text-button shrink-0 size-6 ms-auto" /></span>
]"
><i
class="iconify i-lucide:chevron-down text-button shrink-0 size-6 ms-auto"
/></span>
</span> </span>
<ul <ul v-show="visibleFeatures[item.feature]" class="flex flex-col gap-5">
v-show="visibleFeatures[item.feature]" <li v-for="filter in item.feature_values" :key="filter.value_id"
class="flex flex-col gap-5" class="flex items-center gap-[10px] cursor-pointer">
> <input :id="`${filter.value_id}`" v-model="selectedFilters"
<li :value="`${filter.parent}.${filter.value_id}`" type="checkbox" class="border-button !bg-inherit">
v-for="filter in item.feature_values" <label :for="`${filter.value_id}`"
:key="filter.value_id" class="cursor-pointer flex items-center justify-between w-full text-base">
class="flex items-center gap-[10px] cursor-pointer"
>
<input
:id="`${filter.value_id}`"
v-model="selectedFilters"
:value="`${filter.parent}.${filter.value_id}`"
type="checkbox"
class="border-button !bg-inherit"
>
<label
:for="`${filter.value_id}`"
class="cursor-pointer flex items-center justify-between w-full text-base"
>
<span>{{ filter.value }}</span> <span>{{ filter.value }}</span>
<span>12</span> <span>12</span>
</label> </label>
@ -109,22 +70,13 @@
</h1> </h1>
<div class="flex flex-col gap-12"> <div class="flex flex-col gap-12">
<div> <div>
<div <div v-if="categoriesList && categoriesList.length < 1" class="animate-pulse">
v-if="categoriesList && categoriesList.length < 1" <div class="flex items-center justify-between mt-4 text-white rounded-lg cursor-pointer xl:pr-24">
class="animate-pulse"
>
<div
class="flex items-center justify-between mt-4 text-white rounded-lg cursor-pointer xl:pr-24"
>
<div class="w-32 h-4 bg-gray-200 rounded" /> <div class="w-32 h-4 bg-gray-200 rounded" />
<div class="w-4 h-4 bg-gray-200 rounded-full" /> <div class="w-4 h-4 bg-gray-200 rounded-full" />
</div> </div>
</div> </div>
<CategoryTree <CategoryTree :data="categoriesList" :active="categoryId" @change-category="changeCategory($event)" />
:data="categoriesList"
:active="categoryId"
@change-category="changeCategory($event)"
/>
</div> </div>
<div> <div>
<p class="mb-10 text-2xl font-extrabold text-black dark:text-white"> <p class="mb-10 text-2xl font-extrabold text-black dark:text-white">
@ -139,52 +91,28 @@
</div> </div>
</div> --> </div> -->
<div <div v-for="(item, itemIndex) in filters" :key="itemIndex" :class="[
v-for="(item, itemIndex) in filters" 'mb-[30px]',
:key="itemIndex" visibleFeatures[item.feature] && 'border-b border-block pb-2',
:class="[ ]">
'mb-[30px]', <span class="flex justify-between items-center font-bold cursor-pointer mb-[25px]"
visibleFeatures[item.feature] && 'border-b border-block pb-2', @click="toggleFeature(item.feature)">
]"
>
<span
class="flex justify-between items-center font-bold cursor-pointer mb-[25px]"
@click="toggleFeature(item.feature)"
>
{{ item.feature }} {{ item.feature }}
<span <span :class="[
:class="[ visibleFeatures[item.feature] && 'rotate-180',
visibleFeatures[item.feature] && 'rotate-180', 'transition-all',
'transition-all', ]"><i class="iconify i-lucide:chevron-down text-button shrink-0 size-6 ms-auto" /></span>
]"
><i
class="iconify i-lucide:chevron-down text-button shrink-0 size-6 ms-auto"
/></span>
</span> </span>
<ul <ul v-show="visibleFeatures[item.feature]" class="flex flex-col gap-5">
v-show="visibleFeatures[item.feature]" <li v-for="filter in item.feature_values" :key="filter.value_id"
class="flex flex-col gap-5" class="flex items-center gap-[10px] cursor-pointer">
>
<li
v-for="filter in item.feature_values"
:key="filter.value_id"
class="flex items-center gap-[10px] cursor-pointer"
>
<!-- <input :id="`${filter.value_id}`" :value="`${filter.parent}.${filter.value_id}`" <!-- <input :id="`${filter.value_id}`" :value="`${filter.parent}.${filter.value_id}`"
v-model="selectedFilters" type="checkbox" class="border-button !bg-inherit" /> v-model="selectedFilters" type="checkbox" class="border-button !bg-inherit" />
<label :for="`${filter.value_id}`" class="cursor-pointer">{{ filter.value }}</label> --> <label :for="`${filter.value_id}`" class="cursor-pointer">{{ filter.value }}</label> -->
<input <input :id="`${filter.value_id}`" v-model="selectedFilters"
:id="`${filter.value_id}`" :value="`${filter.parent}.${filter.value_id}`" type="checkbox" class="border-button !bg-inherit">
v-model="selectedFilters" <label :for="`${filter.value_id}`" class="cursor-pointer flex items-center justify-between w-full">
:value="`${filter.parent}.${filter.value_id}`"
type="checkbox"
class="border-button !bg-inherit"
>
<label
:for="`${filter.value_id}`"
class="cursor-pointer flex items-center justify-between w-full"
>
<span>{{ filter.value }}</span> <span>{{ filter.value }}</span>
<span>12</span> <span>12</span>
</label> </label>
@ -197,57 +125,33 @@
<div class="w-full space-y-10"> <div class="w-full space-y-10">
<!-- pop-up --> <!-- pop-up -->
<div <div v-if="isInfo"
v-if="isInfo" class="w-full xl:w-[70%] mx-auto border-y border-block py-[15px] sm:p-[30px] flex gap-[55px] relative">
class="w-full xl:w-[70%] mx-auto border-y border-block py-[15px] sm:p-[30px] flex gap-[55px] relative" <UButton variant="ghost"
> class="p-0 absolute right-0 top-2 sm:right-2 sm:top-2 cursor-pointer text-button font-light hover:bg-inherit hover:text-button-hover"
<UButton size="xl" icon="i-lucide-x" @click="closeElement()" />
variant="ghost"
class="p-0 absolute right-0 top-2 sm:right-2 sm:top-2 cursor-pointer text-button font-light hover:bg-inherit hover:text-button-hover"
size="xl"
icon="i-lucide-x"
@click="closeElement()"
/>
<div class="flex flex-col sm:flex-row gap-[25px]"> <div class="flex flex-col sm:flex-row gap-[25px]">
<div class="flex flex-col justify-between gap-[25px]"> <div class="flex flex-col justify-between gap-[25px]">
<h4 <h4 class="font-inter text-lg sm:text-[24px] leading-[150%] md:leading-[120%] font-bold">
class="font-inter text-lg sm:text-[24px] leading-[150%] md:leading-[120%] font-bold"
>
{{ component.front_section_lang[0].data.title }} {{ component.front_section_lang[0].data.title }}
</h4> </h4>
<p>{{ component.front_section_lang[0].data.description }}</p> <p>{{ component.front_section_lang[0].data.description }}</p>
</div> </div>
<img <img class="max-w-[150px] mx-auto" :src="`/api/public/file/${component.img[0]}_m.webp')`">
class="max-w-[150px] mx-auto"
:src="`/api/public/file/${component.img[0]}_m.webp')`"
>
</div> </div>
</div> </div>
<div <div v-if="products.length < 1" class="grid gap-12 pt-32 pb-16 md:grid-cols-2 2xl:grid-cols-3">
v-if="products.length < 1"
class="grid gap-12 pt-32 pb-16 md:grid-cols-2 2xl:grid-cols-3"
>
<!-- <TheProductSkeleton v-for="index in 6" :key="index" /> --> <!-- <TheProductSkeleton v-for="index in 6" :key="index" /> -->
</div> </div>
<!-- products --> <!-- products -->
<div <div v-else ref="loadingElement" class="flex flex-wrap justify-center gap-5 sm:gap-10">
v-else <Product v-for="product in products" :key="product.id" :product="product" />
ref="loadingElement"
class="flex flex-wrap justify-center gap-5 sm:gap-10"
>
<Product
v-for="product in products"
:key="product.id"
:product="product"
/>
</div> </div>
<div v-if="reachedEnd" <div v-if="reachedEnd" class="w-full flex justify-center">
class="w-full flex justify-center"
>
<p> <p>
{{ $t("FrontTranslations", "You reached end of the list.") }} {{ $t("FrontTranslations", "You reached end of the list.") }}
</p> </p>
@ -297,7 +201,7 @@ defineProps<{
const openCategories = ref(false) const openCategories = ref(false)
const isInfo = ref<boolean>(true) const isInfo = ref<boolean>(true)
const selectedFilters = ref<any>([]) const selectedFilters = ref<string[]>([])
const categoryId = ref<number>(1) const categoryId = ref<number>(1)
const loading = ref(false) const loading = ref(false)
@ -482,7 +386,12 @@ async function loadMoreProducts() {
} }
} }
const changeCategory = (item: any) => { interface CategoryItem {
id: number
name: string
}
const changeCategory = (item: CategoryItem) => {
categoryId.value = item.id categoryId.value = item.id
} }

View File

@ -1,26 +1,25 @@
import type { GenericResponse, GenericResponseItems, UserCart } from "~/types"; import { validation } from '../utils/validation'
import { REGEX_PHONE } from '../utils/regex'
import type { GenericResponse, GenericResponseItems, UserCart } from '~/types'
import type { import type {
Address,
AddressesList, AddressesList,
CheckoutOrder, CheckoutOrder,
Payment, Payment,
UserAddressOfficial, UserAddressOfficial,
} from "~/types/checkout"; } from '~/types/checkout'
import { validation } from "../utils/validation"; import type { CartProduct } from '~/types/product'
import { REGEX_PHONE } from "../utils/regex";
import type { CartProduct } from "~/types/product";
export const useCheckoutStore = defineStore("checkoutStore", () => { export const useCheckoutStore = defineStore('checkoutStore', () => {
const { $toast } = useNuxtApp(); const { $toast } = useNuxtApp()
const menuStore = useMenuStore(); const menuStore = useMenuStore()
const selectedIso = ref(menuStore.selectedCountry); const selectedIso = ref(menuStore.selectedCountry)
const vLegal = ref(false); const vLegal = ref(false)
const vTerms = ref(false); const vTerms = ref(false)
const vNote = ref(""); const vNote = ref('')
const legalValidation = ref(false); const legalValidation = ref(false)
const termsValidation = ref(false); const termsValidation = ref(false)
// get address list // get address list
const addressesList = ref<AddressesList[]>() const addressesList = ref<AddressesList[]>()
@ -154,7 +153,7 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
const phoneValidation = ref<boolean | null>(null) const phoneValidation = ref<boolean | null>(null)
// send checkout form // send checkout form
const userStore = useUserStore(); const userStore = useUserStore()
async function sendForm() { async function sendForm() {
const phoneNum = vUseAccountPhoneNumber.value const phoneNum = vUseAccountPhoneNumber.value
? accountPhoneNumber.value ? accountPhoneNumber.value
@ -197,18 +196,19 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
}, },
) )
console.log(res); console.log(res)
if (res.status === 200) { if (res.status === 200) {
$toast.success('Form successfully sent', { $toast.success('Form successfully sent', {
autoClose: 5000, autoClose: 5000,
dangerouslyHTMLString: true, dangerouslyHTMLString: true,
}); })
menuStore.navigateToItem( menuStore.navigateToItem(
menuStore.menuItems?.find((item) => item.id === 13) menuStore.menuItems?.find(item => item.id === 13),
); )
} else { }
$toast.error("Failed to send form. Please try again.", { else {
$toast.error('Failed to send form. Please try again.', {
autoClose: 5000, autoClose: 5000,
dangerouslyHTMLString: true, dangerouslyHTMLString: true,
}) })
@ -219,10 +219,6 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
} }
} }
const changeActive = (item: any) => {
activeAddress.value = item
}
// get checkout // get checkout
async function getCheckout() { async function getCheckout() {
try { try {
@ -279,99 +275,80 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
} }
// get delivery options // get delivery options
const deliveryOption = ref() interface DeliveryOptionItem {
const currentDelivery = ref() country_iso: string
const shippingPrice = ref() country_name: string
delivery_supplier_id: number
delivery_supplier_name: string
id: number
shippment_price: string
}
const deliveryOption = ref<DeliveryOptionItem[]>([])
const currentDelivery = ref<DeliveryOptionItem | null>(null)
const shippingPrice = ref<number>(0)
async function getDeliveryOptions() { async function getDeliveryOptions() {
try { try {
const res = await useMyFetch< const { data } = await useMyFetch<GenericResponseItems<DeliveryOptionItem[]>>(
GenericResponseItems<object> `/api/restricted/cart/checkout/delivery-options`,
// { {
// items: [ headers: {
// { 'Content-Type': 'application/json',
// country_iso: string;
// country_name: string;
// delivery_supplier_id: number;
// delivery_supplier_name: string;
// id: number;
// shippment_price: string;
// }
// ];
// }
>(`/api/restricted/cart/checkout/delivery-options`, {
headers: {
'Content-Type': 'application/json',
},
onErrorOccured: async (_, status) => {
throw createError({
statusCode: status,
statusMessage: `HTTP error: ${status}`,
})
},
})
const data = {
items: [
{
id: 31,
shippment_price: "2",
delivery_supplier_id: 4,
delivery_supplier_name: "Personal collection",
country_iso: "pl",
country_name: "Poland",
}, },
{ onErrorOccured: async (_, status) => {
id: 34, throw createError({
shippment_price: "20", statusCode: status,
delivery_supplier_id: 1, statusMessage: `HTTP error: ${status}`,
delivery_supplier_name: "Ceska Posta", })
country_iso: "pl",
country_name: "Poland",
}, },
], },
items_count: 2, )
};
deliveryOption.value = data.items; if (data.items && data.items.length > 0) {
currentDelivery.value = data.items[0]; deliveryOption.value = data.items
shippingPrice.value = data.items[0].shippment_price; currentDelivery.value = data.items[0]
fullPrice.value = Number(fullPrice.value) + Number(shippingPrice.value); shippingPrice.value = Number(data.items[0].shippment_price)
} catch (error) { fullPrice.value += shippingPrice.value
console.error("getUserCart error:", error); }
}
catch (error) {
console.error('getDeliveryOptions error:', error)
} }
} }
const setCurrentDelivery = (item: any) => { const setCurrentDelivery = (item: DeliveryOptionItem) => {
shippingPrice.value = item.shippment_price; shippingPrice.value = Number(item.shippment_price)
currentDelivery.value = item; currentDelivery.value = item
fullPrice.value = Number(fullPrice.value) + Number(shippingPrice.value); fullPrice.value = Number(fullPrice.value) + Number(shippingPrice.value)
}; }
interface Address {
is_default: boolean | string
country_iso: string
}
const defaultAddress = ref<Address | undefined>()
const defaultAddress = ref();
async function getDefAddress() { async function getDefAddress() {
try { try {
const { data } = await useMyFetch< const { data } = await useMyFetch<GenericResponse<{ addresses: Address[] }>>(
GenericResponse<{ `/api/public/user`,
addresses: [ {
{ headers: {
is_default: string 'Content-Type': 'application/json',
}, },
] onErrorOccured: async (_, status) => {
}> throw createError({
>(`/api/public/user`, { statusCode: status,
headers: { statusMessage: `HTTP error: ${status}`,
'Content-Type': 'application/json', })
},
}, },
onErrorOccured: async (_, status) => { )
throw createError({
statusCode: status,
statusMessage: `HTTP error: ${status}`,
})
},
})
defaultAddress.value = data.addresses.find( defaultAddress.value = data.addresses.find(
(el: any) => el.is_default === true, el => el.is_default === true || el.is_default === 'true',
) )
} }
catch (error) { catch (error) {
@ -380,30 +357,31 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
} }
// get bank data // get bank data
const paymentMethods = ref([] as Payment[]); const paymentMethods = ref([] as Payment[])
const fullAddress = ref<Address>(); const fullAddress = ref<Address>()
const currentPayment = ref<Payment | null>(); const currentPayment = ref<Payment | null>()
async function getBankAccount() { async function getBankAccount() {
try { try {
const { data } = await useMyFetch<GenericResponse<Payment[]>>( const { data } = await useMyFetch<GenericResponse<Payment[]>>(
`/api/restricted/suitable-bank-accounts/${menuStore.selectedCurrency.iso_code}/${fullAddress.value?.country_iso}`, `/api/restricted/suitable-bank-accounts/${menuStore.selectedCurrency.iso_code}/${fullAddress.value?.country_iso}`,
{ {
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
onErrorOccured: async (_, status) => { onErrorOccured: async (_, status) => {
throw createError({ throw createError({
statusCode: status, statusCode: status,
statusMessage: `HTTP error: ${status}`, statusMessage: `HTTP error: ${status}`,
}); })
}, },
} },
); )
paymentMethods.value = data; paymentMethods.value = data
currentPayment.value = data[0]; currentPayment.value = data[0]
} catch (error) { }
console.error("getUserCart error:", error); catch (error) {
console.error('getUserCart error:', error)
} }
} }
@ -414,131 +392,132 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
`/api/restricted/cart/checkout/order`, `/api/restricted/cart/checkout/order`,
{ {
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
onErrorOccured: async (_, status) => { onErrorOccured: async (_, status) => {
throw createError({ throw createError({
statusCode: status, statusCode: status,
statusMessage: `HTTP error: ${status}`, statusMessage: `HTTP error: ${status}`,
}); })
}, },
} },
); )
fullAddress.value = data.delivery_details.address; fullAddress.value = data.delivery_details.address
console.log(fullAddress.value); }
} catch (error) { catch (error) {
console.error("getOrder error:", error); console.error('getOrder error:', error)
} }
} }
async function setNewAddress(indexItem: number) { async function setNewAddress(indexItem: number) {
currentPayment.value = paymentMethods.value.find( currentPayment.value = paymentMethods.value.find(
(item, index) => indexItem === index (item, index) => indexItem === index,
); )
} }
// send summary form // send summary form
async function sendSummaryForm() { async function sendSummaryForm() {
vLegal.value legalValidation.value = !vLegal.value
? (legalValidation.value = false) termsValidation.value = !vTerms.value
: (legalValidation.value = true);
vTerms.value
? (termsValidation.value = false)
: (termsValidation.value = true);
if (!vTerms.value && !vLegal.value) { if (!vTerms.value && !vLegal.value) {
return; return
} }
try { try {
await useMyFetch<GenericResponse<object>>( await useMyFetch<GenericResponse<object>>(
`/api/restricted/cart/checkout/delivery`, `/api/restricted/cart/checkout/delivery`,
{ {
method: "PUT", method: 'PUT',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ body: JSON.stringify({
accept_general_conditions: true, accept_general_conditions: true,
accept_long_purchase: true, accept_long_purchase: true,
address: fullAddress.value, address: fullAddress.value,
delivery_option_id: currentDelivery.value.id, delivery_option_id: currentDelivery.value?.id,
note: vNote.value, note: vNote.value,
}), }),
onErrorOccured: async (_, status) => { onErrorOccured: async (_, status) => {
throw createError({ throw createError({
statusCode: status, statusCode: status,
statusMessage: `HTTP error: ${status}`, statusMessage: `HTTP error: ${status}`,
}); })
}, },
} },
); )
await putCheckoutBankAccount(); await putCheckoutBankAccount()
await markOrder(); await markOrder()
await getUserCart(); await getUserCart()
} catch (error) { }
console.error("uploadAddress error:", error); catch (error) {
console.error('uploadAddress error:', error)
} }
} }
// put checkout bank-account // put checkout bank-account
async function putCheckoutBankAccount() { async function putCheckoutBankAccount() {
try { try {
const res = await useMyFetch<GenericResponse<object>>( await useMyFetch<GenericResponse<object>>(
`/api/restricted/cart/checkout/bank-account/${currentPayment.value?.id}`, `/api/restricted/cart/checkout/bank-account/${currentPayment.value?.id}`,
{ {
method: "PUT", method: 'PUT',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
onErrorOccured: async (_, status) => { onErrorOccured: async (_, status) => {
throw createError({ throw createError({
statusCode: status, statusCode: status,
statusMessage: `HTTP error: ${status}`, statusMessage: `HTTP error: ${status}`,
}); })
}, },
} },
); )
} catch (error) { }
console.error("uploadAddress error:", error); catch (error) {
console.error('uploadAddress error:', error)
} }
} }
const modalMadeOrder = ref(false); const modalMadeOrder = ref(false)
async function markOrder() { async function markOrder() {
try { try {
const res = await useMyFetch<GenericResponse<object>>( const res = await useMyFetch<GenericResponse<object>>(
`/api/restricted/cart/checkout/order`, `/api/restricted/cart/checkout/order`,
{ {
method: "POST", method: 'POST',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
onErrorOccured: async (_, status) => { onErrorOccured: async (_, status) => {
throw createError({ throw createError({
statusCode: status, statusCode: status,
statusMessage: `HTTP error: ${status}`, statusMessage: `HTTP error: ${status}`,
}); })
}, },
} },
); )
if (res.status === 200 || res.status === 201) { if (res.status === 200 || res.status === 201) {
$toast.success("Address successfully added", { $toast.success('Address successfully added', {
autoClose: 5000, autoClose: 5000,
dangerouslyHTMLString: true, dangerouslyHTMLString: true,
}); })
modalMadeOrder.value = true; modalMadeOrder.value = true
} else { }
$toast.error("Failed to add address. Please try again.", { else {
$toast.error('Failed to add address. Please try again.', {
autoClose: 5000, autoClose: 5000,
dangerouslyHTMLString: true, dangerouslyHTMLString: true,
}); })
} }
// window.location.href = `/golden-panel/my-purchases/${res._data?.data.id}`; // window.location.href = `/golden-panel/my-purchases/${res._data?.data.id}`;
} catch (error) { }
console.error("uploadAddress error:", error); catch (error) {
console.error('uploadAddress error:', error)
} }
} }
return { return {
@ -575,6 +554,7 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
defaultAddress, defaultAddress,
paymentMethods, paymentMethods,
currentPayment, currentPayment,
fullAddress,
vLegal, vLegal,
vTerms, vTerms,
@ -587,7 +567,6 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
getCheckout, getCheckout,
getAddressList, getAddressList,
getUserData, getUserData,
changeActive,
uploadAddress, uploadAddress,
sendForm, sendForm,
getUserCart, getUserCart,
@ -598,5 +577,5 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
getOrder, getOrder,
setNewAddress, setNewAddress,
sendSummaryForm, sendSummaryForm,
}; }
}); })

View File

@ -1,4 +1,4 @@
import { useStore } from "./store"; import { useStore } from './store'
import type { import type {
Country, Country,
Currency, Currency,
@ -7,78 +7,78 @@ import type {
GenericResponseItems, GenericResponseItems,
Language, Language,
UIFrontMenu, UIFrontMenu,
} from "~/types"; } from '~/types'
import { useMyFetch } from "#imports"; import { useMyFetch } from '#imports'
function buildTreeRecursive( function buildTreeRecursive(
data: (FrontMenu | UIFrontMenu)[], data: (FrontMenu | UIFrontMenu)[],
parentId: number parentId: number,
): UIFrontMenu[] { ): UIFrontMenu[] {
const children = data.filter( const children = data.filter(
(item): item is UIFrontMenu => (item): item is UIFrontMenu =>
item.id_parent === parentId && !item.is_default item.id_parent === parentId && !item.is_default,
); )
return children.map((item) => ({ return children.map(item => ({
...item, ...item,
children: buildTreeRecursive(data, item.id), children: buildTreeRecursive(data, item.id),
})); }))
} }
export const useMenuStore = defineStore("menuStore", () => { export const useMenuStore = defineStore('menuStore', () => {
const store = useStore(); const store = useStore()
const { $i18n } = useNuxtApp(); const { $i18n } = useNuxtApp()
// const session = useSession(); // const session = useSession();
const { $session } = useNuxtApp(); const { $session } = useNuxtApp()
const router = useRouter(); const router = useRouter()
const route = useRoute(); const route = useRoute()
const openMenu = ref(false); const openMenu = ref(false)
const openDropDown = ref(false); const openDropDown = ref(false)
const defaultMenu = ref(); const defaultMenu = ref()
const menu = ref([] as UIFrontMenu[]); const menu = ref([] as UIFrontMenu[])
const menuItems = ref([] as FrontMenu[]); const menuItems = ref([] as FrontMenu[])
// curr/country // curr/country
const selectedCountry = ref({} as Country); const selectedCountry = ref({} as Country)
const selectedPhoneCountry = ref({} as Country); const selectedPhoneCountry = ref({} as Country)
const selectedCurrency = ref({} as Currency); const selectedCurrency = ref({} as Currency)
const selectedLanguage = ref({} as Language); const selectedLanguage = ref({} as Language)
const countries = ref([] as Country[]); const countries = ref([] as Country[])
const currencies = ref([] as Currency[]); const currencies = ref([] as Currency[])
const languages = ref([] as Language[]); const languages = ref([] as Language[])
const getLocales = async () => { const getLocales = async () => {
const { data: countriesList } = await useMyFetch< const { data: countriesList } = await useMyFetch<
GenericResponse<Country[]> GenericResponse<Country[]>
>(`/api/public/country/list`); >(`/api/public/country/list`)
countries.value = countriesList; countries.value = countriesList
selectedCountry.value = countriesList.find( selectedCountry.value = countriesList.find(
(country) => country.iso_code === $session.currentCountryIso.value country => country.iso_code === $session.currentCountryIso.value,
) as Country; ) as Country
selectedPhoneCountry.value = countriesList.find( selectedPhoneCountry.value = countriesList.find(
(country) => country.iso_code === $session.currentCountryIso.value country => country.iso_code === $session.currentCountryIso.value,
) as Country; ) as Country
const { data: currenciesList } = await useMyFetch< const { data: currenciesList } = await useMyFetch<
GenericResponseItems<Currency[]> GenericResponseItems<Currency[]>
>(`/api/public/currencies`); >(`/api/public/currencies`)
currencies.value = currenciesList.items; currencies.value = currenciesList.items
selectedCurrency.value = currenciesList.items.find( selectedCurrency.value = currenciesList.items.find(
(currency) => currency.iso_code === $session.currentCurrencyIso.value currency => currency.iso_code === $session.currentCurrencyIso.value,
) as Currency; ) as Currency
const { data: languagesList } = await useMyFetch< const { data: languagesList } = await useMyFetch<
GenericResponseItems<Language[]> GenericResponseItems<Language[]>
>(`/api/public/languages`); >(`/api/public/languages`)
languages.value = languagesList.items; languages.value = languagesList.items
selectedLanguage.value = languagesList.items.find( selectedLanguage.value = languagesList.items.find(
(language) => language.iso_code === $session.currentLanguageIso.value language => language.iso_code === $session.currentLanguageIso.value,
) as Language; ) as Language
}; }
const loadMenu = async () => { const loadMenu = async () => {
try { try {
@ -86,81 +86,84 @@ export const useMenuStore = defineStore("menuStore", () => {
`/api/public/front/menu`, `/api/public/front/menu`,
{ {
onErrorOccured: (err, status) => { onErrorOccured: (err, status) => {
console.log(err, status); console.log(err, status)
}, },
} },
); )
menuItems.value = data; menuItems.value = data
const root = data.find((item) => item.is_root) as UIFrontMenu; const root = data.find(item => item.is_root) as UIFrontMenu
defaultMenu.value = data.find((item) => item.is_default); defaultMenu.value = data.find(item => item.is_default)
if (root) { if (root) {
menu.value = buildTreeRecursive(data, root.id); menu.value = buildTreeRecursive(data, root.id)
} else { }
console.warn("Root menu item not found"); else {
menu.value = []; console.warn('Root menu item not found')
menu.value = []
} }
} catch (error) {
console.log(error);
} }
}; catch (error) {
console.log(error)
}
}
const navigateToItem = (item?: UIFrontMenu) => { const navigateToItem = (item?: UIFrontMenu) => {
if (item) { if (item) {
router.push({ router.push({
params: { slug: item.front_menu_lang[0].link_rewrite, id: item.id }, params: { slug: item.front_menu_lang[0].link_rewrite, id: item.id },
name: `id-slug___${$i18n.locale.value}`, name: `id-slug___${$i18n.locale.value}`,
}); })
openDropDown.value = false; openDropDown.value = false
} else { }
else {
router.push({ router.push({
params: { params: {
slug: defaultMenu.value.front_menu_lang[0].link_rewrite, slug: defaultMenu.value.front_menu_lang[0].link_rewrite,
id: defaultMenu.value.id, id: defaultMenu.value.id,
}, },
name: `id-slug___${$i18n.locale.value}`, name: `id-slug___${$i18n.locale.value}`,
}); })
} }
}; }
function navigateToShop() { function navigateToShop() {
navigateToItem(menuItems.value?.find((item) => item.id === 5)); navigateToItem(menuItems.value?.find(item => item.id === 5))
} }
function getProductMenu() { function getProductMenu() {
return menuItems.value?.find((item) => item.id === 13); return menuItems.value?.find(item => item.id === 14)
} }
const getFirstImage = (size: "l" | "m" | "s" = "m", needbaseurl: boolean) => { const getFirstImage = (size: 'l' | 'm' | 's' = 'm', needbaseurl: boolean) => {
const req = useRequestEvent(); const req = useRequestEvent()
const url = useRequestURL(); const url = useRequestURL()
// let img = ""; // let img = "";
const img: string[] = []; const img: string[] = []
for (const s in store.components) { for (const s in store.components) {
if (store.components[s].front_section.img.length === 0) continue; if (store.components[s].front_section.img.length === 0) continue
img.push( img.push(
`/api/public/file/${store.components[s].front_section.img[0]}_${size}.webp` `/api/public/file/${store.components[s].front_section.img[0]}_${size}.webp`,
); )
if (img.length > 0) break; if (img.length > 0) break
} }
if (img.length > 0) { if (img.length > 0) {
if (needbaseurl) { if (needbaseurl) {
return `${req?.headers.get("x-forwarded-proto") || url.protocol}://${ return `${req?.headers.get('x-forwarded-proto') || url.protocol}://${
req?.headers.get("x-forwarded-host") || req?.headers.get('x-forwarded-host')
url.host || || url.host
req?.headers.get("host") || req?.headers.get('host')
}${img[0]}`; }${img[0]}`
} }
return img[0]; return img[0]
} }
return ""; return ''
}; }
const headMeta = computed(() => { const headMeta = computed(() => {
const item = menuItems.value?.find( const item = menuItems.value?.find(
(item) => item.id.toString() === route.params.id item => item.id.toString() === route.params.id,
); )
const meta = { const meta = {
title: item?.front_menu_lang[0].meta_title, title: item?.front_menu_lang[0].meta_title,
@ -169,77 +172,77 @@ export const useMenuStore = defineStore("menuStore", () => {
}, },
link: [ link: [
// { rel: "manifest", href: "/api/manifest.json" } // { rel: "manifest", href: "/api/manifest.json" }
{ rel: "icon", type: "image/x-icon", href: "/favicon.png" }, { rel: 'icon', type: 'image/x-icon', href: '/favicon.png' },
], ],
script: [ script: [
{ {
src: "https://leiadmin.com/leitag.js?lei=894500UT83EISNNA8D04&color=dark", src: 'https://leiadmin.com/leitag.js?lei=894500UT83EISNNA8D04&color=dark',
defer: true, defer: true,
}, },
], ],
meta: [ meta: [
{ {
hid: "description", hid: 'description',
name: "description", name: 'description',
content: item?.front_menu_lang[0].meta_description, content: item?.front_menu_lang[0].meta_description,
}, },
{ {
property: "og:title", property: 'og:title',
content: item?.front_menu_lang[0].meta_title, content: item?.front_menu_lang[0].meta_title,
}, },
{ {
property: "og:description", property: 'og:description',
content: item?.front_menu_lang[0].meta_description, content: item?.front_menu_lang[0].meta_description,
}, },
{ {
property: "og:image", property: 'og:image',
content: getFirstImage("m", true), content: getFirstImage('m', true),
}, },
{ {
property: "twitter:title", property: 'twitter:title',
content: item?.front_menu_lang[0].meta_title, content: item?.front_menu_lang[0].meta_title,
}, },
{ {
property: "twitter:description", property: 'twitter:description',
content: item?.front_menu_lang[0].meta_description, content: item?.front_menu_lang[0].meta_description,
}, },
{ {
property: "twitter:image", property: 'twitter:image',
content: getFirstImage("m", true), content: getFirstImage('m', true),
}, },
], ],
};
const preload = getFirstImage("l", false);
if (preload) {
meta.link.push({ rel: "preload", as: "image", href: preload } as never);
} }
return meta; const preload = getFirstImage('l', false)
}); if (preload) {
meta.link.push({ rel: 'preload', as: 'image', href: preload } as never)
}
return meta
})
const formatPrice = (value: number): string => { const formatPrice = (value: number): string => {
return value.toLocaleString(selectedLanguage.value.iso_code, { return value.toLocaleString(selectedLanguage.value.iso_code, {
minimumFractionDigits: selectedCurrency.value.precision, minimumFractionDigits: selectedCurrency.value.precision,
maximumFractionDigits: selectedCurrency.value.precision, maximumFractionDigits: selectedCurrency.value.precision,
currency: selectedCurrency.value.iso_code, currency: selectedCurrency.value.iso_code,
style: "currency", style: 'currency',
currencyDisplay: "symbol", currencyDisplay: 'symbol',
currencySign: "accounting", currencySign: 'accounting',
}); })
}; }
// watches // watches
watch( watch(
() => $session.cookieData, () => $session.cookieData,
async () => { async () => {
await getLocales(); await getLocales()
await loadMenu(); await loadMenu()
await store.getMinValue(); await store.getMinValue()
await store.getCalculator(); await store.getCalculator()
}, },
{ deep: true } { deep: true },
); )
return { return {
menu, menu,
@ -261,5 +264,6 @@ export const useMenuStore = defineStore("menuStore", () => {
navigateToItem, navigateToItem,
getLocales, getLocales,
getProductMenu, getProductMenu,
}; formatPrice,
}); }
})

View File

@ -1,18 +1,17 @@
import { useMyFetch } from "#imports"; import { useMyFetch } from '#imports'
import type { import type {
GenericResponse, GenericResponse,
GenericResponseChildren, GenericResponseChildren,
GenericResponseItems, GenericResponseItems,
UserCart, } from '~/types'
} from "~/types"; import type { Product } from '~/types/product'
import type { Product } from "~/types/product";
export const useProductStore = defineStore("productStore", () => { export const useProductStore = defineStore('productStore', () => {
const { $toast } = useNuxtApp(); const { $toast } = useNuxtApp()
const productList = ref<Product[]>(); const productList = ref<Product[]>()
const modules = ref(); const modules = ref()
const checkoutStore = useCheckoutStore(); const checkoutStore = useCheckoutStore()
async function getList(count: number, categoryId = 1) { async function getList(count: number, categoryId = 1) {
try { try {
@ -20,21 +19,22 @@ export const useProductStore = defineStore("productStore", () => {
`/api/public/products/category/${categoryId}?p=1&elems=${count}`, `/api/public/products/category/${categoryId}?p=1&elems=${count}`,
{ {
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
onErrorOccured: async (_, status) => { onErrorOccured: async (_, status) => {
// await navigateTo("/error", { replace: true }); // await navigateTo("/error", { replace: true });
throw createError({ throw createError({
statusCode: status, statusCode: status,
statusMessage: `HTTP error: ${status}`, statusMessage: `HTTP error: ${status}`,
}); })
}, },
} },
); )
productList.value = data.items; productList.value = data.items
} catch (error) { }
console.error("getList error:", error); catch (error) {
console.error('getList error:', error)
} }
} }
@ -44,20 +44,21 @@ export const useProductStore = defineStore("productStore", () => {
`/api/public/module/e_shop`, `/api/public/module/e_shop`,
{ {
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
onErrorOccured: (_, status) => { onErrorOccured: (_, status) => {
throw new Error(`HTTP error: ${status}`); throw new Error(`HTTP error: ${status}`)
}, },
} },
); )
modules.value = data.children.find( modules.value = data.children.find(
(item: { id: number; name: string }) => (item: { id: number, name: string }) =>
item.name === "currency_rates_bar" item.name === 'currency_rates_bar',
); )
} catch (error) { }
console.error("getList error:", error); catch (error) {
console.error('getList error:', error)
} }
} }
@ -66,34 +67,36 @@ export const useProductStore = defineStore("productStore", () => {
const res = await useMyFetch<GenericResponse<object>>( const res = await useMyFetch<GenericResponse<object>>(
`/api/public/user/cart/item/add/${id}/1`, `/api/public/user/cart/item/add/${id}/1`,
{ {
method: "PUT", method: 'PUT',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
onErrorOccured: (_, status) => { onErrorOccured: (_, status) => {
throw new Error(`HTTP error: ${status}`); throw new Error(`HTTP error: ${status}`)
}, },
} },
); )
if (res.status === 200) { if (res.status === 200) {
$toast.success("Item successfully added to your cart.", { $toast.success('Item successfully added to your cart.', {
autoClose: 5000, autoClose: 5000,
dangerouslyHTMLString: true, dangerouslyHTMLString: true,
}); })
checkoutStore.getUserCart(); checkoutStore.getUserCart()
} else {
$toast.error("Failed to add item to cart. Please try again.", {
autoClose: 5000,
dangerouslyHTMLString: true,
});
} }
} catch (error) { else {
$toast.error("An unexpected error occurred while updating your cart.", { $toast.error('Failed to add item to cart. Please try again.', {
autoClose: 5000,
dangerouslyHTMLString: true,
})
}
}
catch (error) {
$toast.error('An unexpected error occurred while updating your cart.', {
autoClose: 5000, autoClose: 5000,
dangerouslyHTMLString: true, dangerouslyHTMLString: true,
}); })
console.error("incrementCartItem error:", error); console.error('incrementCartItem error:', error)
} }
} }
@ -102,34 +105,36 @@ export const useProductStore = defineStore("productStore", () => {
const res = await useMyFetch<GenericResponse<object>>( const res = await useMyFetch<GenericResponse<object>>(
`/api/public/user/cart/item/subtract/${id}/1`, `/api/public/user/cart/item/subtract/${id}/1`,
{ {
method: "PUT", method: 'PUT',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
onErrorOccured: (_, status) => { onErrorOccured: (_, status) => {
throw new Error(`HTTP error: ${status}`); throw new Error(`HTTP error: ${status}`)
}, },
} },
); )
if (res.status === 200) { if (res.status === 200) {
$toast.success("Item successfully removed from your cart.", { $toast.success('Item successfully removed from your cart.', {
autoClose: 5000, autoClose: 5000,
dangerouslyHTMLString: true, dangerouslyHTMLString: true,
}); })
checkoutStore.getUserCart(); checkoutStore.getUserCart()
} else {
$toast.error("Failed to removed item from cart. Please try again.", {
autoClose: 5000,
dangerouslyHTMLString: true,
});
} }
} catch (error) { else {
$toast.error("An unexpected error occurred while updating your cart.", { $toast.error('Failed to removed item from cart. Please try again.', {
autoClose: 5000,
dangerouslyHTMLString: true,
})
}
}
catch (error) {
$toast.error('An unexpected error occurred while updating your cart.', {
autoClose: 5000, autoClose: 5000,
dangerouslyHTMLString: true, dangerouslyHTMLString: true,
}); })
console.error("decrementCartItem error:", error); console.error('decrementCartItem error:', error)
} }
} }
@ -138,34 +143,36 @@ export const useProductStore = defineStore("productStore", () => {
const res = await useMyFetch<GenericResponse<object>>( const res = await useMyFetch<GenericResponse<object>>(
`/api/public/user/cart/item/${id}`, `/api/public/user/cart/item/${id}`,
{ {
method: "DELETE", method: 'DELETE',
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
onErrorOccured: (_, status) => { onErrorOccured: (_, status) => {
throw new Error(`HTTP error: ${status}`); throw new Error(`HTTP error: ${status}`)
}, },
} },
); )
if (res.status === 200) { if (res.status === 200) {
$toast.success("Item successfully removed from your cart.", { $toast.success('Item successfully removed from your cart.', {
autoClose: 5000, autoClose: 5000,
dangerouslyHTMLString: true, dangerouslyHTMLString: true,
}); })
checkoutStore.getUserCart(); checkoutStore.getUserCart()
} else {
$toast.error("Failed to removed item from cart. Please try again.", {
autoClose: 5000,
dangerouslyHTMLString: true,
});
} }
} catch (error) { else {
$toast.error("An unexpected error occurred while updating your cart.", { $toast.error('Failed to removed item from cart. Please try again.', {
autoClose: 5000,
dangerouslyHTMLString: true,
})
}
}
catch (error) {
$toast.error('An unexpected error occurred while updating your cart.', {
autoClose: 5000, autoClose: 5000,
dangerouslyHTMLString: true, dangerouslyHTMLString: true,
}); })
console.error("deleteCartItem error:", error); console.error('deleteCartItem error:', error)
} }
} }
@ -177,5 +184,5 @@ export const useProductStore = defineStore("productStore", () => {
incrementCartItem, incrementCartItem,
decrementCartItem, decrementCartItem,
deleteCartItem, deleteCartItem,
}; }
}); })

View File

@ -32,40 +32,39 @@ export interface UserAddressOfficial {
} }
export interface Payment { export interface Payment {
bank_name: string; bank_name: string
city: string; city: string
country_account_number: string; country_account_number: string
country_iso: string; country_iso: string
country_name: string; country_name: string
currency_iso: string; currency_iso: string
iban: string; iban: string
id: number; id: number
postcode: string; postcode: string
street_and_number: string; street_and_number: string
swift: string; swift: string
} }
export interface CheckoutOrder { export interface CheckoutOrder {
cart_id: number; cart_id: number
currency_iso: string; currency_iso: string
customer_id: number; customer_id: number
delivery_details: { delivery_details: {
address: Address; address: Address
contact_email: string; contact_email: string
contact_phone_number: string; contact_phone_number: string
delivery_option_id: number; delivery_option_id: number
note: string; }
}; payment_bank_account_id: number
payment_bank_account_id: number;
} }
export interface Address { export interface Address {
city: string; city: string
country_iso: { country_iso: {
str: string; str: string
}; }
name: string; name: string
postcode: string; postcode: string
street: string; street: string
surname: string; surname: string
} }