1 Commits
main ... linter

Author SHA1 Message Date
69b0c0f976 errors fixing 2025-07-03 13:27:25 +02:00
13 changed files with 488 additions and 689 deletions

View File

@ -1,55 +1,94 @@
<template>
<div ref="dropdownRef">
<div class="relative cursor-pointer" @click="openCart = !openCart">
<i class="uil uil-shopping-cart text-[31px]"></i>
<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">
{{ checkoutStore.products.length }}
<div class="relative cursor-pointer"
@click="openCart = !openCart"
>
<i class="uil uil-shopping-cart text-[31px]" />
<div
v-if="
productStore.cart.cart_items
&& productStore.cart.cart_items.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"
>
{{ productStore.cart.cart_items.length }}
</div>
</div>
<div 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]"
@click.self="openCart = !openCart">
<div
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]"
@click.self="openCart = !openCart"
>
<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
v-if="
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 v-for="(item, index) in checkoutStore.products" :key="index"
class="py-[13px] sm:py-[25px] first:pt-0 border-b border-block">
<!-- product -->
<div
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="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
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="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]">
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 class="uil uil-trash-alt text-lg sm:text-2xl cursor-pointer"
@click="productStore.deleteCartItem(item.cart_item_id)"></i>
<i
class="uil uil-trash-alt text-lg sm:text-2xl cursor-pointer"
@click="productStore.deleteCartItem(item.cart_item_id)"
/>
</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)) }}
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 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>
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)
"
/>
</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 }}
</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>
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)
"
/>
</div>
</div>
</div>
@ -58,34 +97,52 @@
</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
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)) }}
class="text-accent-green-light dark:text-accent-green-dark font-inter text-[12px] sm:text-[21px] md:text-2xl leading-[150%] font-bold"
>
{{ productStore.cart.total_value }}
</p>
</div>
<UiButtonArrow class="w-full" type="fill" :arrow="true" :full="true" @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
}">
{{ userStore.isLogged
? $t('to_checkout') : $t('login') }}
<UiButtonArrow
class="w-full"
type="fill"
:arrow="true"
:full="true"
@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;
}
"
>
{{ 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
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') }}
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>
@ -98,7 +155,6 @@
import { onClickOutside } from '@vueuse/core'
const productStore = useProductStore()
const checkoutStore = useCheckoutStore()
const openCart = ref(false)
const menuStore = useMenuStore()

View File

@ -32,11 +32,30 @@
</ClientOnly>
<div class="w-full flex items-center justify-between">
<div class="flex items-center gap-[30px]">
<p
class="cursor-pointer"
@click="
menuStore.navigateToItem(
menuStore.menuItems?.find((item) => item.id === 13),
)
"
>
button
</p>
<div>
<i v-if="!userStore.isLogged"
class="uil uil-user text-[31px] cursor-pointer"
@click="menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))"></i>
<div v-else class="py-[6px] px-3 border border-block rounded-sm">
<i
v-if="!userStore.isLogged"
class="uil uil-user text-[31px] cursor-pointer"
@click="
menuStore.navigateToItem(
menuStore.menuItems?.find((item) => item.id === 11),
)
"
/>
<div
v-else
class="py-[6px] px-3 border border-block rounded-sm"
>
{{ userStore.user }}
</div>
</div>
@ -374,13 +393,13 @@ import CartPopup from './CartPopup.vue'
import CountryCurrencySelector from './CountryCurrencySelector.vue'
import LangSwitcher from './LangSwitcher.vue'
const menuStore = useMenuStore()
const userStore = useUserStore()
const productStore = useProductStore()
const open = ref(false)
const colorMode = useColorMode()
const menuStore = useMenuStore()
const checkoutStore = useCheckoutStore()
checkoutStore.getUserCart()
productStore.getCart()
const route = useRoute()
const isDark = computed({

View File

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

View File

@ -1,15 +1,11 @@
<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-else>
<UiContainer>
<div class="xl:w-[85%] mx-auto space-25-55">
<div class="space-25-55">
<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">
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>
@ -17,7 +13,8 @@
{{ $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">
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">
@ -26,29 +23,40 @@
</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">
<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">
{{ component.front_section_lang[0].data.product_list }}
Seznam produktů
</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 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="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]">
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">
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>
@ -57,196 +65,31 @@
</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">
<div class="">
<div class="space-y-5">
<h4 class="h4-uppercase-bold-inter">
{{ component.front_section_lang[0].data.account_address }}
Adresa účtu
</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>
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 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>
<span>{{ checkoutStore.defaultAddress?.address.postcode }}
{{ checkoutStore.defaultAddress?.address.city }}</span>
</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 ") }}
<NuxtLink target="_blank"
:to="{ name: 'lang-info-name', params: { lang: menuStore.selectedLanguage.iso_code, name: 'legal_statement.html' } }"
class="underline cursor-pointer">
{{ $t("the legal statement*") }}
</NuxtLink>
</label> -->
<p class="text-sm sm:text-lg">
{{ $t("I accept ") }} {{ $t("the legal statement*") }}
</p>
</div>
<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">
<input id="second" v-model="checkoutStore.vTerms" type="checkbox" name="second" />
<!-- <label for="second" class="text-sm leading-snug">
{{ $t("I accept ") }}
<NuxtLink target="_blank"
:to="{ name: 'lang-info-name', params: { lang: menuStore.selectedLanguage.iso_code, name: 'general_terms_and_conditions.html' } }"
class="underline cursor-pointer">
{{ $t("general terms and conditions*") }}
</NuxtLink>
</label> -->
<p class="text-sm sm:text-lg">
{{ $t("I accept ") }} {{ $t("general terms and conditions*") }}
</p>
</div>
<span v-if="checkoutStore.termsValidation" class="text-xs text-red-600 ml-6">
{{ $t("You need to accept this") }}
</span>
</div>
<UiButtonArrow type="fill" :arrow="true" @click="checkoutStore.sendSummaryForm">
{{ $t("Buy") }}
</UiButtonArrow>
</div>
</div>
</UiContainer>
</template>
<script setup lang="ts">
import { UCarousel } from '#components'
const checkoutStore = useCheckoutStore()
const menuStore = useMenuStore()
checkoutStore.getOrder()
checkoutStore.getBankAccount()
checkoutStore.getUserCart()
checkoutStore.getDeliveryOptions()
checkoutStore.getDefAddress()
defineProps<{
component: {
id: number
name: string
img: string[]
component_name: string
is_no_lang: boolean
page_name: string
front_section_lang: {
data: {
product_list: string
account_address: string
note: string
delivery_type: string
payment_method: string
subtotal: string
shipping_cost: string
total: string
accept: string
legal: string
terms: string
}
id_front_section: number
id_lang: number
}[]
}
}>()
</script>

View File

@ -104,12 +104,9 @@ defineProps<{
component_name: string
is_no_lang: boolean
page_name: string
front_section_lang: {
id_front_section: number
id_lang: number
}[]
}
}>()
const userStore = useUserStore()
const menuStore = useMenuStore()
</script>

View File

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

View File

@ -248,6 +248,17 @@ const goRight = () => {
curImage.value = product.value.picture_uuids[0]
}
}
/**
* INSERT INTO `front_page` (`created_at`, `updated_at`, `name`, `is_default`, `id`) VALUES ('2025-06-25 11:07:28.000','2025-06-25 11:07:28.000','product','0','13');
* INSERT INTO `front_menu` (`created_at`, `updated_at`, `active`, `position_id`, `id_front_page`, `is_default`, `is_root`, `id`) VALUES ('2025-06-25 11:07:28.000','2025-06-25 11:07:28.000','1','1','13','0','0','13');
* INSERT INTO `front_menu_lang` (`name`, `id_lang`, `id_front_menu`, `link_rewrite`) VALUES ('Product','2','13','product');
* INSERT INTO `front_menu_lang` (`link_rewrite`, `id_front_menu`, `id_lang`, `name`) VALUES ('produkt','13','1','Produkt');
* INSERT INTO `front_menu_lang` (`name`, `id_lang`, `id_front_menu`, `link_rewrite`) VALUES ('Produkt','3','13','produkt');
* INSERT INTO `front_section` (`id`, `created_at`, `updated_at`, `name`, `img`, `component_name`, `is_no_lang`) VALUES ('32','2025-06-25 11:07:28.000','2025-06-25 11:07:28.000','product','[]','ProductBlock','1');
* INSERT INTO `front_page_section` (`id_front_page`, `id_position`, `id_front_section`) VALUES ('13','1','32');
* INSERT INTO `front_page_section` (`id_front_page`, `id_position`, `id_front_section`) VALUES ('13','2','4');
*/
</script>
<style>

View File

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

View File

@ -1,3 +1,3 @@
<svg width="76" height="53" viewBox="0 0 76 53" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M76 49.8V2C76 0.9 75.1 0 74 0H2C0.9 0 0 0.9 0 2V50C0 52.5 3.3 52 2 52H74C77 52 75.6 47.4 76 49.8ZM6 48L28 19.3L46.4 43.4L49.9 48H6ZM55 48L50.5 42.2L58 32.4L69.9 48H55ZM72 44L59.6 27.8C58.8 26.7 57.2 26.7 56.4 27.8L48 38.8L29.6 14.8C28.8 13.7 27.2 13.7 26.4 14.8L4 44.1V4H72V44ZM49 10C45.1 10 42 13.1 42 17C42 20.9 45.1 24 49 24C52.9 24 56 20.9 56 17C56 13.1 52.8 10 49 10ZM49 20C47.4 20 46 18.7 46 17C46 15.3 47.3 14 49 14C50.7 14 52 15.3 52 17C52 18.7 50.6 20 49 20Z" fill="#525252"/>
<path d="M76 49.8V2C76 0.9 75.1 0 74 0H2C0.9 0 0 0.9 0 2V50C0 52.5 3.3 52 2 52H74C77 52 75.6 47.4 76 49.8ZM6 48L28 19.3L46.4 43.4L49.9 48H6ZM55 48L50.5 42.2L58 32.4L69.9 48H55ZM72 44L59.6 27.8C58.8 26.7 57.2 26.7 56.4 27.8L48 38.8L29.6 14.8C28.8 13.7 27.2 13.7 26.4 14.8L4 44.1V4H72V44ZM49 10C45.1 10 42 13.1 42 17C42 20.9 45.1 24 49 24C52.9 24 56 20.9 56 17C56 13.1 52.8 10 49 10ZM49 20C47.4 20 46 18.7 46 17C46 15.3 47.3 14 49 14C50.7 14 52 15.3 52 17C52 18.7 50.6 20 49 20Z" fill="#004F3D"/>
</svg>

Before

Width:  |  Height:  |  Size: 598 B

After

Width:  |  Height:  |  Size: 598 B

View File

@ -1,25 +1,14 @@
import { validation } from '../utils/validation'
import { REGEX_PHONE } from '../utils/regex'
import type { GenericResponse, GenericResponseItems, UserCart } from '~/types'
import type {
AddressesList,
CheckoutOrder,
Payment,
UserAddressOfficial,
} from '~/types/checkout'
import type { AddressesList, UserAddressOfficial } from '~/types/checkout'
import type { CartProduct } from '~/types/product'
export const useCheckoutStore = defineStore('checkoutStore', () => {
const { $toast } = useNuxtApp()
const menuStore = useMenuStore()
const selectedIso = ref(menuStore.selectedCountry)
const vLegal = ref(false)
const vTerms = ref(false)
const vNote = ref('')
const legalValidation = ref(false)
const termsValidation = ref(false)
const showSummary = ref(false)
// get address list
const addressesList = ref<AddressesList[]>()
@ -152,8 +141,8 @@ export const useCheckoutStore = defineStore('checkoutStore', () => {
}
const phoneValidation = ref<boolean | null>(null)
// send checkout form
const userStore = useUserStore()
// send form
async function sendForm() {
const phoneNum = vUseAccountPhoneNumber.value
? accountPhoneNumber.value
@ -196,16 +185,13 @@ export const useCheckoutStore = defineStore('checkoutStore', () => {
},
)
console.log(res)
if (res.status === 200) {
$toast.success('Form successfully sent', {
autoClose: 5000,
dangerouslyHTMLString: true,
})
menuStore.navigateToItem(
menuStore.menuItems?.find(item => item.id === 13),
)
// redirectToSummary();
showSummary.value = true
}
else {
$toast.error('Failed to send form. Please try again.', {
@ -219,7 +205,10 @@ export const useCheckoutStore = defineStore('checkoutStore', () => {
}
}
// get checkout
const changeActive = (item: AddressesList) => {
activeAddress.value = item
}
async function getCheckout() {
try {
await useMyFetch<GenericResponse<object>>(
@ -274,8 +263,7 @@ export const useCheckoutStore = defineStore('checkoutStore', () => {
}
}
// get delivery options
interface DeliveryOptionItem {
type DeliveryOption = {
country_iso: string
country_name: string
delivery_supplier_id: number
@ -284,71 +272,62 @@ export const useCheckoutStore = defineStore('checkoutStore', () => {
shippment_price: string
}
const deliveryOption = ref<DeliveryOptionItem[]>([])
const currentDelivery = ref<DeliveryOptionItem | null>(null)
const shippingPrice = ref<number>(0)
// get delivery options
const deliveryOption = ref()
const currentDelivery = ref()
const shippingPrice = ref()
async function getDeliveryOptions() {
try {
const { data } = await useMyFetch<GenericResponseItems<DeliveryOptionItem[]>>(
`/api/restricted/cart/checkout/delivery-options`,
{
headers: {
'Content-Type': 'application/json',
},
onErrorOccured: async (_, status) => {
throw createError({
statusCode: status,
statusMessage: `HTTP error: ${status}`,
})
},
const { data } = await useMyFetch<
GenericResponseItems<DeliveryOption[]>
>(`/api/restricted/cart/checkout/delivery-options`, {
headers: {
'Content-Type': 'application/json',
},
)
onErrorOccured: async (_, status) => {
throw createError({
statusCode: status,
statusMessage: `HTTP error: ${status}`,
})
},
})
if (data.items && data.items.length > 0) {
deliveryOption.value = data.items
currentDelivery.value = data.items[0]
shippingPrice.value = Number(data.items[0].shippment_price)
fullPrice.value += shippingPrice.value
}
console.log(data)
deliveryOption.value = data.items
currentDelivery.value = data.items[0]
shippingPrice.value = data.items[0].shippment_price
fullPrice.value = Number(fullPrice.value) + Number(shippingPrice.value)
}
catch (error) {
console.error('getDeliveryOptions error:', error)
console.error('getUserCart error:', error)
}
}
const setCurrentDelivery = (item: DeliveryOptionItem) => {
shippingPrice.value = Number(item.shippment_price)
currentDelivery.value = item
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() {
try {
const { data } = await useMyFetch<GenericResponse<{ addresses: Address[] }>>(
`/api/public/user`,
{
headers: {
'Content-Type': 'application/json',
},
onErrorOccured: async (_, status) => {
throw createError({
statusCode: status,
statusMessage: `HTTP error: ${status}`,
})
},
const { data } = await useMyFetch<
GenericResponse<{
addresses: [
{
is_default: boolean
},
]
}>
>(`/api/public/user`, {
headers: {
'Content-Type': 'application/json',
},
)
onErrorOccured: async (_, status) => {
throw createError({
statusCode: status,
statusMessage: `HTTP error: ${status}`,
})
},
})
defaultAddress.value = data.addresses.find(
el => el.is_default === true || el.is_default === 'true',
(el: { is_default: boolean }) => el.is_default === true,
)
}
catch (error) {
@ -356,170 +335,6 @@ export const useCheckoutStore = defineStore('checkoutStore', () => {
}
}
// get bank data
const paymentMethods = ref([] as Payment[])
const fullAddress = ref<Address>()
const currentPayment = ref<Payment | null>()
async function getBankAccount() {
try {
const { data } = await useMyFetch<GenericResponse<Payment[]>>(
`/api/restricted/suitable-bank-accounts/${menuStore.selectedCurrency.iso_code}/${fullAddress.value?.country_iso}`,
{
headers: {
'Content-Type': 'application/json',
},
onErrorOccured: async (_, status) => {
throw createError({
statusCode: status,
statusMessage: `HTTP error: ${status}`,
})
},
},
)
paymentMethods.value = data
currentPayment.value = data[0]
}
catch (error) {
console.error('getUserCart error:', error)
}
}
// get order (summary)
async function getOrder() {
try {
const { data } = await useMyFetch<GenericResponse<CheckoutOrder>>(
`/api/restricted/cart/checkout/order`,
{
headers: {
'Content-Type': 'application/json',
},
onErrorOccured: async (_, status) => {
throw createError({
statusCode: status,
statusMessage: `HTTP error: ${status}`,
})
},
},
)
fullAddress.value = data.delivery_details.address
}
catch (error) {
console.error('getOrder error:', error)
}
}
async function setNewAddress(indexItem: number) {
currentPayment.value = paymentMethods.value.find(
(item, index) => indexItem === index,
)
}
// send summary form
async function sendSummaryForm() {
legalValidation.value = !vLegal.value
termsValidation.value = !vTerms.value
if (!vTerms.value && !vLegal.value) {
return
}
try {
await useMyFetch<GenericResponse<object>>(
`/api/restricted/cart/checkout/delivery`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
accept_general_conditions: true,
accept_long_purchase: true,
address: fullAddress.value,
delivery_option_id: currentDelivery.value?.id,
note: vNote.value,
}),
onErrorOccured: async (_, status) => {
throw createError({
statusCode: status,
statusMessage: `HTTP error: ${status}`,
})
},
},
)
await putCheckoutBankAccount()
await markOrder()
await getUserCart()
}
catch (error) {
console.error('uploadAddress error:', error)
}
}
// put checkout bank-account
async function putCheckoutBankAccount() {
try {
await useMyFetch<GenericResponse<object>>(
`/api/restricted/cart/checkout/bank-account/${currentPayment.value?.id}`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
onErrorOccured: async (_, status) => {
throw createError({
statusCode: status,
statusMessage: `HTTP error: ${status}`,
})
},
},
)
}
catch (error) {
console.error('uploadAddress error:', error)
}
}
const modalMadeOrder = ref(false)
async function markOrder() {
try {
const res = await useMyFetch<GenericResponse<object>>(
`/api/restricted/cart/checkout/order`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
onErrorOccured: async (_, status) => {
throw createError({
statusCode: status,
statusMessage: `HTTP error: ${status}`,
})
},
},
)
if (res.status === 200 || res.status === 201) {
$toast.success('Address successfully added', {
autoClose: 5000,
dangerouslyHTMLString: true,
})
modalMadeOrder.value = true
}
else {
$toast.error('Failed to add address. Please try again.', {
autoClose: 5000,
dangerouslyHTMLString: true,
})
}
// window.location.href = `/golden-panel/my-purchases/${res._data?.data.id}`;
}
catch (error) {
console.error('uploadAddress error:', error)
}
}
return {
addressesList,
activeAddress,
@ -544,6 +359,7 @@ export const useCheckoutStore = defineStore('checkoutStore', () => {
vNewAddressCode,
vNewAddressCity,
vNewAddressCountry,
showSummary,
products,
fullPrice,
@ -552,30 +368,16 @@ export const useCheckoutStore = defineStore('checkoutStore', () => {
currentDelivery,
shippingPrice,
defaultAddress,
paymentMethods,
currentPayment,
fullAddress,
vLegal,
vTerms,
vNote,
legalValidation,
termsValidation,
modalMadeOrder,
changePrefix,
getCheckout,
getAddressList,
getUserData,
changeActive,
uploadAddress,
sendForm,
getUserCart,
getDeliveryOptions,
getDefAddress,
setCurrentDelivery,
getBankAccount,
getOrder,
setNewAddress,
sendSummaryForm,
}
})

View File

@ -132,7 +132,7 @@ export const useMenuStore = defineStore('menuStore', () => {
}
function getProductMenu() {
return menuItems.value?.find(item => item.id === 14)
return menuItems.value?.find(item => item.id === 13)
}
const getFirstImage = (size: 'l' | 'm' | 's' = 'm', needbaseurl: boolean) => {
@ -149,11 +149,7 @@ export const useMenuStore = defineStore('menuStore', () => {
}
if (img.length > 0) {
if (needbaseurl) {
return `${req?.headers.get('x-forwarded-proto') || url.protocol}://${
req?.headers.get('x-forwarded-host')
|| url.host
|| req?.headers.get('host')
}${img[0]}`
return `${req?.headers.get('x-forwarded-proto') || url.protocol}://${req?.headers.get('x-forwarded-host') || url.host || req?.headers.get('host')}${img[0]}`
}
return img[0]
}
@ -221,17 +217,6 @@ export const useMenuStore = defineStore('menuStore', () => {
return meta
})
const formatPrice = (value: number): string => {
return value.toLocaleString(selectedLanguage.value.iso_code, {
minimumFractionDigits: selectedCurrency.value.precision,
maximumFractionDigits: selectedCurrency.value.precision,
currency: selectedCurrency.value.iso_code,
style: 'currency',
currencyDisplay: 'symbol',
currencySign: 'accounting',
})
}
// watches
watch(
() => $session.cookieData,
@ -258,12 +243,10 @@ export const useMenuStore = defineStore('menuStore', () => {
selectedLanguage,
defaultMenu,
headMeta,
navigateToShop,
loadMenu,
navigateToItem,
getLocales,
getProductMenu,
formatPrice,
}
})

View File

@ -3,6 +3,7 @@ import type {
GenericResponse,
GenericResponseChildren,
GenericResponseItems,
UserCart,
} from '~/types'
import type { Product } from '~/types/product'
@ -11,8 +12,6 @@ export const useProductStore = defineStore('productStore', () => {
const productList = ref<Product[]>()
const modules = ref()
const checkoutStore = useCheckoutStore()
async function getList(count: number, categoryId = 1) {
try {
const { data } = await useMyFetch<GenericResponseItems<[]>>(
@ -82,7 +81,7 @@ export const useProductStore = defineStore('productStore', () => {
autoClose: 5000,
dangerouslyHTMLString: true,
})
checkoutStore.getUserCart()
getCart()
}
else {
$toast.error('Failed to add item to cart. Please try again.', {
@ -120,7 +119,7 @@ export const useProductStore = defineStore('productStore', () => {
autoClose: 5000,
dangerouslyHTMLString: true,
})
checkoutStore.getUserCart()
getCart()
}
else {
$toast.error('Failed to removed item from cart. Please try again.', {
@ -158,7 +157,7 @@ export const useProductStore = defineStore('productStore', () => {
autoClose: 5000,
dangerouslyHTMLString: true,
})
checkoutStore.getUserCart()
getCart()
}
else {
$toast.error('Failed to removed item from cart. Please try again.', {
@ -176,13 +175,37 @@ export const useProductStore = defineStore('productStore', () => {
}
}
const cart = ref({} as UserCart)
async function getCart() {
try {
const { data } = await useMyFetch<GenericResponse<UserCart>>(
`/api/public/user/cart`,
{
headers: {
'Content-Type': 'application/json',
},
onErrorOccured: (_, status) => {
throw new Error(`HTTP error: ${status}`)
},
},
)
cart.value = data
}
catch (error) {
console.error('getList error:', error)
}
}
return {
productList,
modules,
cart,
getList,
getModules,
incrementCartItem,
decrementCartItem,
deleteCartItem,
getCart,
}
})

View File

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