summary checkout

This commit is contained in:
2025-07-02 15:55:13 +02:00
parent fbb6c071af
commit 834b48a307
7 changed files with 464 additions and 61 deletions

View File

@ -18,8 +18,7 @@
</ClientOnly> </ClientOnly>
<div class="w-full flex items-center justify-between"> <div class="w-full flex items-center justify-between">
<div class="flex items-center gap-[30px]"> <div class="flex items-center gap-[30px]">
<p @click="menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 13))" class="cursor-pointer">button</p> <div>
<div>
<i v-if="!userStore.isLogged" <i v-if="!userStore.isLogged"
@click="menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))" @click="menuStore.navigateToItem(menuStore.menuItems?.find((item) => item.id === 11))"
class="uil uil-user text-[31px] cursor-pointer"></i> class="uil uil-user text-[31px] cursor-pointer"></i>

View File

@ -23,13 +23,13 @@
</div> </div>
<div class="grid grid-cols-3 gap-[30px]"> <div class="grid grid-cols-3 gap-[30px]">
<div class="col-start-1 col-end-3 space-y-5"> <div class="col-start-1 col-end-3 space-y-5">
<h4 class="h4-uppercase-bold-inter">Seznam produktů</h4> <h4 class="h4-uppercase-bold-inter">{{ component.front_section_lang[0].data.product_list }}</h4>
<div class="border-2 border-block rounded-2xl p-[50px] space-25-55"> <div class="border-2 border-block rounded-[15px] p-[50px] space-25-55">
<div v-for="(item, index) in checkoutStore.products" :key="index"> <div v-for="(item, index) in checkoutStore.products" :key="index">
<div class="flex items-center h-[150px]"> <div class="flex items-center h-[150px]">
<div class="min-w-[150px] flex items-center justify-center h-[150px]"> <div class="min-w-[150px] flex items-center justify-center h-[150px]">
<img :src="`/api/public/file/${item.picture_uuid}.webp`" <img :src="`/api/public/file/${item.picture_uuid}.webp`" alt=""
alt="" class="max-w-full max-h-full object-contain"> class="max-w-full max-h-full object-contain">
</div> </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]">
@ -50,10 +50,12 @@
</div> </div>
</div> </div>
</div> </div>
<div class=""> <div class="flex flex-col items-center gap-[30px]">
<div class="space-y-5"> <div class="space-y-5 w-full">
<h4 class="h4-uppercase-bold-inter">Adresa účtu</h4> <h4 class="h4-uppercase-bold-inter">{{ component.front_section_lang[0].data.account_address }}
<div class="border-2 border-block rounded-2xl px-2 py-3 flex flex-col gap-1"> </h4>
<div
class="border-2 border-block rounded-[8px] px-[25px] py-[15px] flex flex-col gap-1 text-xl">
<span>{{ checkoutStore.defaultAddress?.address.name }} {{ <span>{{ checkoutStore.defaultAddress?.address.name }} {{
checkoutStore.defaultAddress?.address.surname }}</span> checkoutStore.defaultAddress?.address.surname }}</span>
<span>{{ checkoutStore.defaultAddress?.address.street }}</span> <span>{{ checkoutStore.defaultAddress?.address.street }}</span>
@ -61,17 +63,161 @@
checkoutStore.defaultAddress?.address.city }}</span> checkoutStore.defaultAddress?.address.city }}</span>
</div> </div>
</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-3 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>
<div class="col-start-1 col-end-3 space-y-5">
<h4 class="h4-uppercase-bold-inter">Typ doručení</h4>
<div class="border-2 border-block rounded-[15px] p-[50px] space-y-[25px] 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-[12px] 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-[15px] flex-1 flex flex-col gap-1 text-xl overflow-auto">
<UCarousel :prevIcon="'i-lucide-chevron-left'" :nextIcon="'i-lucide-chevron-right'" :ui="{
viewport: 'h-full',
container: 'h-full',
item: 'h-full',
prev: 'ring-0 text-button disable:text-block p-0 ring-inset ring-accented bg-inherit disabled:bg-inherit',
next: '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 max-w-full mx-10 h-full">
<template #default="{ item }">
<div class="flex flex-col items-start justify-between h-full">
<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] text-xl">
<div class="flex items-center justify-between">
<p>{{ component.front_section_lang[0].data.subtotal }}</p>
<p>5,043.18</p>
</div>
<div class="flex items-center justify-between">
<p>{{ component.front_section_lang[0].data.shipping_cost }}</p>
<p>5,043.18</p>
</div>
<div class="flex items-center justify-between uppercase">
<p>{{ component.front_section_lang[0].data.total }}</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">
5,043.18
</p>
</div>
</div>
<div class="flex justify-between mt-1">
<div class="flex flex-col gap-1 text-white w-full">
<div class="flex gap-3 text-black dark:text-white items-center">
<input v-model="checkoutStore.vLegal" type="checkbox" id="first" 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-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 v-model="checkoutStore.vTerms" type="checkbox" id="second" 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-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">
{{ $t("Buy") }}
</UiButtonArrow>
</div> </div>
</div> </div>
</UiContainer> </UiContainer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { UCarousel } from '#components';
const checkoutStore = useCheckoutStore(); const checkoutStore = useCheckoutStore();
const productStore = useProductStore() const productStore = useProductStore()
const menuStore = useMenuStore()
checkoutStore.getOrder()
checkoutStore.getBankAccount()
checkoutStore.getUserCart() checkoutStore.getUserCart()
checkoutStore.getDeliveryOptions() checkoutStore.getDeliveryOptions()
checkoutStore.getDefAddress() 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> </script>

View File

@ -1,9 +1,10 @@
<template> <template>
<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]">
<img :src="`/api/public/file/${props.product?.cover_picture_uuid}.webp`" alt="Product Image" <img :src="`/api/public/file/${props.product?.cover_picture_uuid}.webp`" alt="Product Image" :class="[
class="h-[95px] sm:h-[180px] md:h-[205px] rounded-[5px]" 'h-[95px] sm:min-h-[180px] md:min-h-[205px] rounded-[5px]',
onerror="this.onerror=null; this.src='/photo.svg';" /> isError ? 'max-w-[50%]' : ''
]" @error="handleImageError" />
<div class="flex flex-col justify-between h-full w-full gap-[7px] sSm: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"> <div class="flex flex-col gap-[7px] sm:gap-[15px] w-full">
@ -33,4 +34,11 @@ const props = defineProps({
}); });
const productStore = useProductStore() const productStore = useProductStore()
const isError = ref(false);
function handleImageError(event: Event) {
isError.value = true;
(event.target as HTMLImageElement).src = '/photo.svg';
}
</script> </script>

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"> <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="#004F3D"/> <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"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 598 B

After

Width:  |  Height:  |  Size: 598 B

View File

@ -1,5 +1,11 @@
import type { GenericResponse, GenericResponseItems, UserCart } from "~/types"; import type { GenericResponse, GenericResponseItems, UserCart } from "~/types";
import type { AddressesList, UserAddressOfficial } from "~/types/checkout"; import type {
Address,
AddressesList,
CheckoutOrder,
Payment,
UserAddressOfficial,
} from "~/types/checkout";
import { validation } from "../utils/validation"; import { validation } from "../utils/validation";
import { REGEX_PHONE } from "../utils/regex"; import { REGEX_PHONE } from "../utils/regex";
import type { CartProduct } from "~/types/product"; import type { CartProduct } from "~/types/product";
@ -8,7 +14,12 @@ 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 showSummary = ref(false);
const vLegal = ref(false);
const vTerms = ref(false);
const vNote = ref("");
const legalValidation = ref(false);
const termsValidation = ref(false);
// get address list // get address list
const addressesList = ref<AddressesList[]>(); const addressesList = ref<AddressesList[]>();
@ -137,8 +148,8 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
}; };
const phoneValidation = ref<boolean | null>(null); const phoneValidation = ref<boolean | null>(null);
// send checkout form
const userStore = useUserStore(); const userStore = useUserStore();
// send form
async function sendForm() { async function sendForm() {
let phoneNum = vUseAccountPhoneNumber.value let phoneNum = vUseAccountPhoneNumber.value
? accountPhoneNumber.value ? accountPhoneNumber.value
@ -186,8 +197,9 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
autoClose: 5000, autoClose: 5000,
dangerouslyHTMLString: true, dangerouslyHTMLString: true,
}); });
// redirectToSummary(); menuStore.navigateToItem(
showSummary.value = true; menuStore.menuItems?.find((item) => item.id === 13)
);
} else { } else {
$toast.error("Failed to send form. Please try again.", { $toast.error("Failed to send form. Please try again.", {
autoClose: 5000, autoClose: 5000,
@ -203,6 +215,7 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
activeAddress.value = item; activeAddress.value = item;
}; };
// get checkout
async function getCheckout() { async function getCheckout() {
try { try {
const res = await useMyFetch<GenericResponse<object>>( const res = await useMyFetch<GenericResponse<object>>(
@ -261,19 +274,20 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
const shippingPrice = ref(); const shippingPrice = ref();
async function getDeliveryOptions() { async function getDeliveryOptions() {
try { try {
const { data } = await useMyFetch< const res = await useMyFetch<
GenericResponseItems<{ GenericResponseItems<object>
items: [ // {
{ // items: [
country_iso: string; // {
country_name: string; // country_iso: string;
delivery_supplier_id: number; // country_name: string;
delivery_supplier_name: string; // delivery_supplier_id: number;
id: number; // delivery_supplier_name: string;
shippment_price: string; // id: number;
} // shippment_price: string;
]; // }
}> // ];
// }
>(`/api/restricted/cart/checkout/delivery-options`, { >(`/api/restricted/cart/checkout/delivery-options`, {
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -286,7 +300,28 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
}, },
}); });
console.log(data); const data = {
items: [
{
id: 31,
shippment_price: "2",
delivery_supplier_id: 4,
delivery_supplier_name: "Personal collection",
country_iso: "pl",
country_name: "Poland",
},
{
id: 34,
shippment_price: "20",
delivery_supplier_id: 1,
delivery_supplier_name: "Ceska Posta",
country_iso: "pl",
country_name: "Poland",
},
],
items_count: 2,
};
deliveryOption.value = data.items; deliveryOption.value = data.items;
currentDelivery.value = data.items[0]; currentDelivery.value = data.items[0];
shippingPrice.value = data.items[0].shippment_price; shippingPrice.value = data.items[0].shippment_price;
@ -296,6 +331,12 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
} }
} }
const setCurrentDelivery = (item: any) => {
shippingPrice.value = item.shippment_price;
currentDelivery.value = item;
fullPrice.value = Number(fullPrice.value) + Number(shippingPrice.value);
};
const defaultAddress = ref(); const defaultAddress = ref();
async function getDefAddress() { async function getDefAddress() {
try { try {
@ -327,6 +368,137 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
} }
} }
// get bank data
const paymentMethods = ref([] as Payment[]);
const fullAddress = ref<Address>();
const currentPayment = ref<Payment | null>(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;
console.log(fullAddress.value);
} catch (error) {
console.error("getOrder error:", error);
}
}
async function setNewAddress(index: number) {
currentPayment.value = paymentMethods.value.find(
(item, index) => index === index
);
}
// send summary form
async function sendSummaryForm() {
vLegal.value
? (legalValidation.value = false)
: (legalValidation.value = true);
vTerms.value
? (termsValidation.value = false)
: (termsValidation.value = true);
// if (vTerms.value && vLegal.value) {
// isModalOpen.value = true;
// }
try {
const res = 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}`,
});
},
}
);
putCheckoutBankAccount();
} catch (error) {
console.error("uploadAddress error:", error);
}
}
// put checkout bank-account
async function putCheckoutBankAccount() {
try {
const res = await useMyFetch<GenericResponse<object>>(
`restricted/cart/checkout/bank-account/${currentPayment.value?.id}`,
{
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}`,
});
},
}
);
} catch (error) {
console.error("uploadAddress error:", error);
}
}
return { return {
addressesList, addressesList,
activeAddress, activeAddress,
@ -351,7 +523,6 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
vNewAddressCode, vNewAddressCode,
vNewAddressCity, vNewAddressCity,
vNewAddressCountry, vNewAddressCountry,
showSummary,
products, products,
fullPrice, fullPrice,
@ -360,6 +531,14 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
currentDelivery, currentDelivery,
shippingPrice, shippingPrice,
defaultAddress, defaultAddress,
paymentMethods,
currentPayment,
vLegal,
vTerms,
vNote,
legalValidation,
termsValidation,
changePrefix, changePrefix,
getCheckout, getCheckout,
@ -371,5 +550,9 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
getUserCart, getUserCart,
getDeliveryOptions, getDeliveryOptions,
getDefAddress, getDefAddress,
setCurrentDelivery,
getBankAccount,
getOrder,
setNewAddress,
}; };
}); });

View File

@ -11,7 +11,6 @@ import { useStore } from "./store";
import { useMyFetch } from "#imports"; import { useMyFetch } from "#imports";
// import { useSession } from "~/plugins/01_i18n"; // import { useSession } from "~/plugins/01_i18n";
function buildTreeRecursive( function buildTreeRecursive(
data: (FrontMenu | UIFrontMenu)[], data: (FrontMenu | UIFrontMenu)[],
parentId: number parentId: number
@ -40,42 +39,50 @@ export const useMenuStore = defineStore("menuStore", () => {
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<GenericResponse<Country[]>>(`/api/public/country/list`); const { data: countriesList } = await useMyFetch<
GenericResponse<Country[]>
>(`/api/public/country/list`);
countries.value = countriesList; countries.value = countriesList;
selectedCountry.value = countriesList.find((country) => country.iso_code === $session.currentCountryIso.value) as Country; selectedCountry.value = countriesList.find(
selectedPhoneCountry.value = countriesList.find((country) => country.iso_code === $session.currentCountryIso.value) as Country; (country) => country.iso_code === $session.currentCountryIso.value
) as Country;
selectedPhoneCountry.value = countriesList.find(
(country) => country.iso_code === $session.currentCountryIso.value
) as Country;
const { data: currenciesList } = await useMyFetch<
const { data: currenciesList } = await useMyFetch<GenericResponseItems<Currency[]>>(`/api/public/currencies`) GenericResponseItems<Currency[]>
>(`/api/public/currencies`);
currencies.value = currenciesList.items; currencies.value = currenciesList.items;
selectedCurrency.value = currenciesList.items.find((currency) => currency.iso_code === $session.currentCurrencyIso.value) as Currency; selectedCurrency.value = currenciesList.items.find(
(currency) => currency.iso_code === $session.currentCurrencyIso.value
) as Currency;
const { data: languagesList } = await useMyFetch<GenericResponseItems<Language[]>>(`/api/public/languages`) const { data: languagesList } = await useMyFetch<
GenericResponseItems<Language[]>
>(`/api/public/languages`);
languages.value = languagesList.items; languages.value = languagesList.items;
selectedLanguage.value = languagesList.items.find((language) => language.iso_code === $session.currentLanguageIso.value) as Language; selectedLanguage.value = languagesList.items.find(
(language) => language.iso_code === $session.currentLanguageIso.value
) as Language;
}; };
const loadMenu = async () => { const loadMenu = async () => {
try { try {
const { data } = await useMyFetch<GenericResponse<FrontMenu[]>>( const { data } = await useMyFetch<GenericResponse<FrontMenu[]>>(
`/api/public/front/menu`, `/api/public/front/menu`,
{ {
@ -100,7 +107,6 @@ export const useMenuStore = defineStore("menuStore", () => {
} }
}; };
const navigateToItem = (item?: UIFrontMenu) => { const navigateToItem = (item?: UIFrontMenu) => {
if (item) { if (item) {
router.push({ router.push({
@ -127,15 +133,21 @@ export const useMenuStore = defineStore("menuStore", () => {
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(`/api/public/file/${store.components[s].front_section.img[0]}_${size}.webp`) img.push(
if (img.length > 0) break;; `/api/public/file/${store.components[s].front_section.img[0]}_${size}.webp`
);
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}://${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]; return img[0];
} }
@ -197,16 +209,30 @@ export const useMenuStore = defineStore("menuStore", () => {
} }
return meta; 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 // watches
watch(() => $session.cookieData, async () => { watch(
await getLocales(); () => $session.cookieData,
await loadMenu(); async () => {
await store.getMinValue(); await getLocales();
await store.getCalculator(); await loadMenu();
}, { deep: true }); await store.getMinValue();
await store.getCalculator();
},
{ deep: true }
);
return { return {
menu, menu,
@ -222,9 +248,11 @@ export const useMenuStore = defineStore("menuStore", () => {
selectedLanguage, selectedLanguage,
defaultMenu, defaultMenu,
headMeta, headMeta,
navigateToShop, navigateToShop,
loadMenu, loadMenu,
navigateToItem, navigateToItem,
getLocales, getLocales,
formatPrice,
}; };
}); });

View File

@ -30,3 +30,42 @@ 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;
note: string;
};
payment_bank_account_id: number;
}
export interface Address {
city: string;
country_iso: {
str: string;
};
name: string;
postcode: string;
street: string;
surname: string;
}