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

@ -1,5 +1,11 @@
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 { REGEX_PHONE } from "../utils/regex";
import type { CartProduct } from "~/types/product";
@ -8,7 +14,12 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
const { $toast } = useNuxtApp();
const menuStore = useMenuStore();
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
const addressesList = ref<AddressesList[]>();
@ -137,8 +148,8 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
};
const phoneValidation = ref<boolean | null>(null);
// send checkout form
const userStore = useUserStore();
// send form
async function sendForm() {
let phoneNum = vUseAccountPhoneNumber.value
? accountPhoneNumber.value
@ -186,8 +197,9 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
autoClose: 5000,
dangerouslyHTMLString: true,
});
// redirectToSummary();
showSummary.value = true;
menuStore.navigateToItem(
menuStore.menuItems?.find((item) => item.id === 13)
);
} else {
$toast.error("Failed to send form. Please try again.", {
autoClose: 5000,
@ -203,6 +215,7 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
activeAddress.value = item;
};
// get checkout
async function getCheckout() {
try {
const res = await useMyFetch<GenericResponse<object>>(
@ -261,19 +274,20 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
const shippingPrice = ref();
async function getDeliveryOptions() {
try {
const { data } = await useMyFetch<
GenericResponseItems<{
items: [
{
country_iso: string;
country_name: string;
delivery_supplier_id: number;
delivery_supplier_name: string;
id: number;
shippment_price: string;
}
];
}>
const res = await useMyFetch<
GenericResponseItems<object>
// {
// items: [
// {
// 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",
@ -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;
currentDelivery.value = data.items[0];
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();
async function getDefAddress() {
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 {
addressesList,
activeAddress,
@ -351,7 +523,6 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
vNewAddressCode,
vNewAddressCity,
vNewAddressCountry,
showSummary,
products,
fullPrice,
@ -360,6 +531,14 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
currentDelivery,
shippingPrice,
defaultAddress,
paymentMethods,
currentPayment,
vLegal,
vTerms,
vNote,
legalValidation,
termsValidation,
changePrefix,
getCheckout,
@ -371,5 +550,9 @@ export const useCheckoutStore = defineStore("checkoutStore", () => {
getUserCart,
getDeliveryOptions,
getDefAddress,
setCurrentDelivery,
getBankAccount,
getOrder,
setNewAddress,
};
});

View File

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