diff --git a/bo/components.d.ts b/bo/components.d.ts index 42be43b..96f6d21 100644 --- a/bo/components.d.ts +++ b/bo/components.d.ts @@ -22,12 +22,16 @@ declare module 'vue' { FavoriteProducts: typeof import('./src/components/admin/FavoriteProducts.vue')['default'] LangSwitch: typeof import('./src/components/inner/LangSwitch.vue')['default'] PageAddresses: typeof import('./src/components/customer/PageAddresses.vue')['default'] + PageCart: typeof import('./src/components/customer/PageCart.vue')['default'] PageCarts: typeof import('./src/components/customer/PageCarts.vue')['default'] + PageCArts: typeof import('./src/components/customer/PageCArts.vue')['default'] + PageCreateCart: typeof import('./src/components/customer/PageCreateCart.vue')['default'] PageOrders: typeof import('./src/components/customer/PageOrders.vue')['default'] PageProduct: typeof import('./src/components/customer/PageProduct.vue')['default'] PageProducts: typeof import('./src/components/admin/PageProducts.vue')['default'] PageProfileDetails: typeof import('./src/components/customer/PageProfileDetails.vue')['default'] PageProfileDetailsAddInfo: typeof import('./src/components/customer/PageProfileDetailsAddInfo.vue')['default'] + PageSearchProducts: typeof import('./src/components/customer/PageSearchProducts.vue')['default'] PageStatistic: typeof import('./src/components/customer/PageStatistic.vue')['default'] Pl_PrivacyPolicyView: typeof import('./src/components/terms/pl_PrivacyPolicyView.vue')['default'] Pl_TermsAndConditionsView: typeof import('./src/components/terms/pl_TermsAndConditionsView.vue')['default'] @@ -44,6 +48,8 @@ declare module 'vue' { TopBar: typeof import('./src/components/TopBar.vue')['default'] TopBarLogin: typeof import('./src/components/TopBarLogin.vue')['default'] UAlert: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Alert.vue')['default'] + UApp: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/App.vue')['default'] + UAvatar: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Avatar.vue')['default'] UButton: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Button.vue')['default'] UCard: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Card.vue')['default'] UCheckbox: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Checkbox.vue')['default'] diff --git a/bo/src/App.vue b/bo/src/App.vue index c09672a..aadc18a 100644 --- a/bo/src/App.vue +++ b/bo/src/App.vue @@ -23,5 +23,3 @@ const layout = computed(() => (route.meta.layout as string) || 'default') - - diff --git a/bo/src/components/customer/PageCart.vue b/bo/src/components/customer/PageCart.vue new file mode 100644 index 0000000..f4f0583 --- /dev/null +++ b/bo/src/components/customer/PageCart.vue @@ -0,0 +1,17 @@ + + + \ No newline at end of file diff --git a/bo/src/components/customer/PageCarts.vue b/bo/src/components/customer/PageCarts.vue index 70d02ed..a2e25bb 100644 --- a/bo/src/components/customer/PageCarts.vue +++ b/bo/src/components/customer/PageCarts.vue @@ -1,201 +1,112 @@ + + + + \ No newline at end of file diff --git a/bo/src/components/customer/PageProduct.vue b/bo/src/components/customer/PageProduct.vue index ad7c3e8..3ebab33 100644 --- a/bo/src/components/customer/PageProduct.vue +++ b/bo/src/components/customer/PageProduct.vue @@ -169,21 +169,21 @@ if (productData.colors.length > 0) { const route = useRoute() -async function toggleFavorite() { - const url = `/api/v1/restricted/product/favorite/${route.params.product_id}` +// async function toggleFavorite() { +// const url = `/api/v1/restricted/product/favorite/${route.params.product_id}` - try { - if (!productData.is_favorite) { - await useFetchJson(url, { method: 'POST' }) - } else { - await useFetchJson(url, { method: 'DELETE' }) - } +// try { +// if (!productData.is_favorite) { +// await useFetchJson(url, { method: 'POST' }) +// } else { +// await useFetchJson(url, { method: 'DELETE' }) +// } - productData.is_favorite = !productData.is_favorite - } catch (e: unknown) { - console.error(e) - } -} +// productData.is_favorite = !productData.is_favorite +// } catch (e: unknown) { +// console.error(e) +// } +// } \ No newline at end of file diff --git a/bo/src/layouts/default.vue b/bo/src/layouts/default.vue index 6da881d..681d019 100644 --- a/bo/src/layouts/default.vue +++ b/bo/src/layouts/default.vue @@ -34,10 +34,33 @@
-
- - {{ pageTitle }} +
+
+ + {{ pageTitle }} +
+
+
+ + +
+

+ {{ cartStore.activeCart.name }}- + + ID: {{ cartStore.activeCart.cart_id }} + +

+ +
+
+ + + + No cart selected + +
@@ -172,6 +195,7 @@ import LangSwitch from '@/components/inner/LangSwitch.vue' import ThemeSwitch from '@/components/inner/ThemeSwitch.vue' import type { LabelTrans, TopMenuItem } from '@/types' import { useUserStore } from '@/stores/user' +import { useCartStore } from '@/stores/customer/cart' const router = useRouter() @@ -297,5 +321,11 @@ const userItems = computed(() => [ ] ]) +const cartStore = useCartStore() + +onMounted(() => { + cartStore.initCart() +}) + defineShortcuts(extractShortcuts(teamsItems.value)) diff --git a/bo/src/stores/customer/cart.ts b/bo/src/stores/customer/cart.ts index 93d4527..36eb6f3 100644 --- a/bo/src/stores/customer/cart.ts +++ b/bo/src/stores/customer/cart.ts @@ -1,22 +1,13 @@ import { defineStore } from 'pinia' -import { ref, computed } from 'vue' +import { computed, ref } from 'vue' import { useFetchJson } from '@/composable/useFetchJson' +import type { ApiResponse } from '@/types' +import { useRoute } from 'vue-router' -export interface CartItem { - id: number - productId: number - name: string - image: string - price: number - quantity: number - product_number: string -} - -export interface DeliveryMethod { +export interface Cart { id: number name: string - price: number - description: string + items: any[] } export interface Address { @@ -29,243 +20,97 @@ export interface Address { export type AddressTemplate = Record export const useCartStore = defineStore('cart', () => { - const items = ref([]) - const selectedAddressId = ref(null) - const selectedDeliveryMethodId = ref(null) - const shippingCost = ref(0) - const vatRate = ref(0.23) // 23% VAT - const currentPage = ref(1) - const deliveryMethods = ref([ - { id: 1, name: 'Standard Delivery', price: 0, description: '5-7 business days' }, - { id: 2, name: 'Express Delivery', price: 15, description: '2-3 business days' }, - { id: 3, name: 'Priority Delivery', price: 30, description: 'Next business day' } - ]) - - const addresses = ref([]) - const addressLoading = ref(false) - const addressError = ref(null) - const addressSearchQuery = ref('') - const addressCurrentPage = ref(1) - const addressPageSize = 20 - const addressTotalCount = ref(0) - - function transformAddressResponse(address: any): Address { - const info = address.address_info || address.addressInfo || {} - - return { - id: address.id ?? 0, - country_id: address.country_id ?? address.countryId ?? 1, - customer_id: address.customer_id ?? address.customerId ?? 0, - address_info: info as Record - } - } - - async function fetchAddresses() { - addressLoading.value = true - addressError.value = null + const carts = ref([]) + const activeCartId = ref(null) + const error = ref(null) + async function fetchCarts() { try { - const queryParam = addressSearchQuery.value ? `&query=${encodeURIComponent(addressSearchQuery.value)}` : '' - const response = await useFetchJson(`/api/v1/restricted/addresses/retrieve-addresses?page=${addressCurrentPage.value}&elems=${addressPageSize}${queryParam}`) - addresses.value = response.items || [] - addressTotalCount.value = response.count ?? addresses.value.length - } catch (error: unknown) { - addressError.value = error instanceof Error ? error.message : 'Failed to load addresses' - } finally { - addressLoading.value = false + const res = await useFetchJson( + `/api/v1/restricted/carts/retrieve-carts-info` + ) + + carts.value = res.items + } catch (e: any) { + error.value = e?.message ?? 'Error loading carts' } } - async function addAddress(countryId: number, formData: AddressTemplate): Promise
{ - addressLoading.value = true - addressError.value = null - + async function addNewCart(name: string) { try { - const response = await useFetchJson(`/api/v1/restricted/addresses/add-new-address?country_id=${countryId}`, { - method: 'POST', - body: JSON.stringify(formData) - }) + error.value = null - await fetchAddresses() - return transformAddressResponse(response.items ?? response) - } catch (error: unknown) { - addressError.value = error instanceof Error ? error.message : 'Failed to create address' - return null - } finally { - addressLoading.value = false - } - } + const url = `/api/v1/restricted/carts/add-new-cart` + const response = await useFetchJson(url) - async function getAddressTemplate(countryId: number): Promise { - const response = await useFetchJson(`/api/v1/restricted/addresses/get-template?country_id=${countryId}`) - return response.items ?? {} - } - - async function updateAddress(id: number, countryId: number, formData: AddressTemplate): Promise { - addressLoading.value = true - addressError.value = null - - try { - await useFetchJson(`/api/v1/restricted/addresses/modify-address?country_id=${countryId}&address_id=${id}`, { - method: 'POST', - body: JSON.stringify(formData) - }) - - await fetchAddresses() - return true - } catch (error: unknown) { - addressError.value = error instanceof Error ? error.message : 'Failed to update address' - return false - } finally { - addressLoading.value = false - } - } - - async function deleteAddress(id: number): Promise { - addressLoading.value = true - addressError.value = null - - try { - await useFetchJson(`/api/v1/restricted/addresses/delete-address?address_id=${id}`, { - method: 'DELETE' - }) - - await fetchAddresses() - return true - } catch (error: unknown) { - addressError.value = error instanceof Error ? error.message : 'Failed to delete address' - return false - } finally { - addressLoading.value = false - } - } - - const totalAddressItems = computed(() => addressTotalCount.value || addresses.value.length) - const totalAddressPages = computed(() => Math.ceil(totalAddressItems.value / addressPageSize)) - - const paginatedAddresses = computed(() => addresses.value) - - function setAddressPage(page: number) { - addressCurrentPage.value = page - return fetchAddresses() - } - - function setAddressSearchQuery(query: string) { - addressSearchQuery.value = query - addressCurrentPage.value = 1 - return fetchAddresses() - } - - - function initMockData() { - items.value = [ - { id: 1, productId: 101, name: 'Premium Widget Pro', product_number: 'NC209/7000', image: '/img/product-1.jpg', price: 129.99, quantity: 2 }, - { id: 2, productId: 102, name: 'Ultra Gadget X', product_number: 'NC234/6453', image: '/img/product-2.jpg', price: 89.50, quantity: 1 }, - { id: 3, productId: 103, name: 'Mega Tool Set', product_number: 'NC324/9030', image: '/img/product-3.jpg', price: 249.00, quantity: 3 } - ] - } - - const productsTotal = computed(() => { - return items.value.reduce((sum, item) => sum + (item.price * item.quantity), 0) - }) - - const vatAmount = computed(() => { - return productsTotal.value * vatRate.value - }) - - const orderTotal = computed(() => { - return productsTotal.value + shippingCost.value + vatAmount.value - }) - - const itemCount = computed(() => { - return items.value.reduce((sum, item) => sum + item.quantity, 0) - }) - - function updateQuantity(itemId: number, quantity: number) { - const item = items.value.find(i => i.id === itemId) - if (item) { - if (quantity <= 0) { - removeItem(itemId) - } else { - item.quantity = quantity + const newCart: Cart = { + id: response.items.cart_id, + name: response.items.name, + items: [] } + + carts.value.push(newCart) + activeCartId.value = newCart.id + + return newCart + } catch (e: any) { + error.value = e?.message ?? 'Error creating cart' } } - function deleteProduct(id: number): boolean { - const index = items.value.findIndex(a => a.id === id) - if (index === -1) return false + const route = useRoute() + const amount = ref(1); + const errorMessage = ref(''); - items.value.splice(index, 1) - resetProductPagination() + async function addProduct(product_id: number, count: number) { + if (!activeCartId.value) { + errorMessage.value = 'No active cart selected' + return + } - return true - } + try { + const res = await useFetchJson( + `/api/v1/restricted/carts/add-product-to-cart?cart_id=${activeCartId.value}&product_id=${product_id}&amount=${count}` + ) - function resetProductPagination() { - currentPage.value = 1 - } - - function removeItem(itemId: number) { - const index = items.value.findIndex(i => i.id === itemId) - if (index !== -1) { - items.value.splice(index, 1) + console.log('fsdfsdfdsfdsfs', res) + } catch (e: any) { + errorMessage.value = e?.message ?? 'Error adding product' } } - function clearCart() { - items.value = [] - selectedAddressId.value = null - selectedDeliveryMethodId.value = null - shippingCost.value = 0 - } + function setActiveCart(id: number | null) { + activeCartId.value = id - function setSelectedAddress(addressId: number | null) { - selectedAddressId.value = addressId - } - - function setDeliveryMethod(methodId: number) { - selectedDeliveryMethodId.value = methodId - const method = deliveryMethods.value.find(m => m.id === methodId) - if (method) { - shippingCost.value = method.price + if (id) { + localStorage.setItem('activeCartId', String(id)) + } else { + localStorage.removeItem('activeCartId') } } - initMockData() + function initCart() { + const saved = localStorage.getItem('activeCartId') + + if (saved) { + activeCartId.value = Number(saved) + } + } + + const activeCart = computed(() => { + return carts.value.find(c => c.cart_id === activeCartId.value) + }) return { - items, - selectedAddressId, - selectedDeliveryMethodId, - shippingCost, - vatRate, - deliveryMethods, - productsTotal, - vatAmount, - orderTotal, - itemCount, - deleteProduct, - updateQuantity, - removeItem, - clearCart, - setSelectedAddress, - setDeliveryMethod, - addresses, - addressLoading, - addressError, - addressSearchQuery, - addressCurrentPage, - addressPageSize, - paginatedAddresses, - totalAddressItems, - totalAddressPages, - fetchAddresses, - addAddress, - updateAddress, - deleteAddress, - setAddressPage, - setAddressSearchQuery, - getAddressTemplate + carts, + activeCartId, + error, + errorMessage, + activeCart, + setActiveCart, + addProduct, + fetchCarts, + addNewCart, + initCart, } -}) +}) \ No newline at end of file diff --git a/bo/src/stores/customer/customer-product.ts b/bo/src/stores/customer/customer-product.ts index 897271f..38074cc 100644 --- a/bo/src/stores/customer/customer-product.ts +++ b/bo/src/stores/customer/customer-product.ts @@ -11,6 +11,7 @@ export interface Product { productDetails?: string product_id: number is_favorite?: boolean + quantity: number } export interface ProductResponse { @@ -56,6 +57,11 @@ export const useCustomerProductStore = defineStore('customer-product', () => { } } + function updateFavoriteState(product_id: number, value: boolean) { + const p = productsList.value.find(p => p.product_id === product_id) + if (p) p.is_favorite = value + } + async function toggleFavorite(product: Product) { const productId = product.product_id const isFavorite = product.is_favorite @@ -64,11 +70,19 @@ export const useCustomerProductStore = defineStore('customer-product', () => { try { if (!isFavorite) { - await useFetchJson(url, { method: 'POST' }) + await useFetchJson(url, { + method: 'POST', + body: JSON.stringify({ + id: productId + }), + }) } else { - await useFetchJson(url, { method: 'DELETE' }) + await useFetchJson(url, { + method: 'DELETE', + }) } - product.is_favorite = !isFavorite + + product.is_favorite = !product.is_favorite } catch (e: unknown) { error.value = e instanceof Error ? e.message : 'Failed to update favorite' } @@ -77,6 +91,7 @@ export const useCustomerProductStore = defineStore('customer-product', () => { return { fetchProductList, toggleFavorite, + updateFavoriteState, productsList, total, loading, diff --git a/bruno/b2b_daniel/carts/add-product-to-cart (1).yml b/bruno/b2b_daniel/carts/add-product-to-cart (1).yml index f8b93c3..e8f5ab3 100644 --- a/bruno/b2b_daniel/carts/add-product-to-cart (1).yml +++ b/bruno/b2b_daniel/carts/add-product-to-cart (1).yml @@ -1,7 +1,7 @@ info: name: add-product-to-cart (1) type: http - seq: 1 + seq: 2 http: method: GET diff --git a/bruno/b2b_daniel/carts/add-product-to-cart.yml b/bruno/b2b_daniel/carts/add-product-to-cart.yml index 9337ab5..ee90994 100644 --- a/bruno/b2b_daniel/carts/add-product-to-cart.yml +++ b/bruno/b2b_daniel/carts/add-product-to-cart.yml @@ -1,7 +1,7 @@ info: name: add-product-to-cart type: http - seq: 14 + seq: 6 http: method: GET diff --git a/bruno/b2b_daniel/carts/change-cart-name.yml b/bruno/b2b_daniel/carts/change-cart-name.yml index 08838dc..5ca9609 100644 --- a/bruno/b2b_daniel/carts/change-cart-name.yml +++ b/bruno/b2b_daniel/carts/change-cart-name.yml @@ -1,7 +1,7 @@ info: name: change-cart-name type: http - seq: 1 + seq: 3 http: method: GET diff --git a/bruno/b2b_daniel/carts/retrieve-cart.yml b/bruno/b2b_daniel/carts/retrieve-cart.yml index 809b524..c8d5c27 100644 --- a/bruno/b2b_daniel/carts/retrieve-cart.yml +++ b/bruno/b2b_daniel/carts/retrieve-cart.yml @@ -1,7 +1,7 @@ info: name: retrieve-cart type: http - seq: 1 + seq: 4 http: method: GET diff --git a/bruno/b2b_daniel/carts/retrieve-carts-info.yml b/bruno/b2b_daniel/carts/retrieve-carts-info.yml index 479be4e..2c2b48f 100644 --- a/bruno/b2b_daniel/carts/retrieve-carts-info.yml +++ b/bruno/b2b_daniel/carts/retrieve-carts-info.yml @@ -1,7 +1,7 @@ info: name: retrieve-carts-info type: http - seq: 1 + seq: 5 http: method: GET