Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate
This commit is contained in:
@@ -1,21 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-5 md:gap-10">
|
<div class="flex flex-col gap-5 md:gap-10">
|
||||||
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Shopping Cart') }}</h1>
|
<div class="flex flex-col md:flex-row justify-between items-center gap-4">
|
||||||
<div class="flex flex-col lg:flex-row gap-5 md:gap-10">
|
<h1 class="text-2xl font-bold text-black dark:text-white">{{ t('Shopping Carts') }}</h1>
|
||||||
<div class="flex-1">
|
<div class="flex gap-3">
|
||||||
<div
|
<UButton color="primary" @click="showCreateModal = true"
|
||||||
class="bg-(--second-light) dark:bg-(--main-dark) rounded-lg border border-(--border-light) dark:border-(--border-dark) overflow-hidden">
|
class="bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) text-white hover:bg-(--accent-blue-dark) dark:hover:bg-(--accent-blue-light)">
|
||||||
<h2
|
<UIcon name="mdi:plus" class="mr-1" />
|
||||||
class="text-lg font-semibold text-black dark:text-white p-4 border-b border-(--border-light) dark:border-(--border-dark)">
|
{{ t('New Cart') }}
|
||||||
{{ t('Selected Products') }}
|
</UButton>
|
||||||
</h2>
|
|
||||||
<div v-if="cartStore.items.length > 0">
|
|
||||||
<div v-for="item in cartStore.items" :key="item.id"
|
|
||||||
class="grid grid-cols-5 items-center p-4 border-b border-(--border-light) dark:border-(--border-dark) w-[100%]">
|
|
||||||
<div
|
|
||||||
class="bg-(--second-light) dark:bg-(--main-dark) rounded flex items-center justify-center overflow-hidden">
|
|
||||||
<img v-if="item.image" :src="item.image" :alt="item.name" class="w-full h-full object-cover" />
|
|
||||||
<UIcon v-else name="mdi:package-variant" class="text-2xl text-gray-400" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -24,102 +16,72 @@
|
|||||||
class="bg-(--second-light) dark:bg-(--main-dark) rounded-lg border border-(--border-light) dark:border-(--border-dark) overflow-hidden">
|
class="bg-(--second-light) dark:bg-(--main-dark) rounded-lg border border-(--border-light) dark:border-(--border-dark) overflow-hidden">
|
||||||
<h2
|
<h2
|
||||||
class="text-lg font-semibold text-black dark:text-white p-4 border-b border-(--border-light) dark:border-(--border-dark)">
|
class="text-lg font-semibold text-black dark:text-white p-4 border-b border-(--border-light) dark:border-(--border-dark)">
|
||||||
{{ t('Selected Products') }}
|
{{ t('Your Carts') }}
|
||||||
</h2>
|
</h2>
|
||||||
<div v-if="cartStore.items.length > 0">
|
<div v-if="cartStore.carts?.length > 0"
|
||||||
<div v-for="item in cartStore.items" :key="item.id"
|
class="divide-y divide-(--border-light) dark:divide-(--border-dark)">
|
||||||
class="grid grid-cols-5 items-center p-4 border-b border-(--border-light) dark:border-(--border-dark) w-[100%]">
|
<div v-for="cart in cartStore.carts" :key="cart.cart_id"
|
||||||
<div
|
@click="cartStore.setActiveCart(cart.cart_id)"
|
||||||
class="bg-(--second-light) dark:bg-(--main-dark) rounded flex items-center justify-center overflow-hidden">
|
class="p-4 cursor-pointer flex gap-2 items-center justify-between" :class="cartStore.activeCartId === cart.cart_id
|
||||||
<img v-if="item.image" :src="item.image" :alt="item.name"
|
? 'bg-blue-50 dark:bg-blue-900/20'
|
||||||
class="w-full h-full object-cover" />
|
: 'hover:bg-gray-50 dark:hover:bg-gray-800 border-l-4 border-transparent'">
|
||||||
<UIcon v-else name="mdi:package-variant" class="text-2xl text-gray-400" />
|
<div class="flex-1 min-w-0">
|
||||||
</div>
|
<div class="flex items-center gap-2">
|
||||||
</div>
|
<p class="text-red-600 font-medium truncate">{{ cart.cart_id }}</p>
|
||||||
|
<p class="text-black dark:text-white font-medium truncate cursor-pointer"
|
||||||
<div class="w-full">
|
@click="openCart(cart)">{{
|
||||||
<div
|
cart.name }}</p>
|
||||||
class="bg-(--second-light) dark:bg-(--main-dark) rounded-lg border border-(--border-light) dark:border-(--border-dark) overflow-hidden">
|
|
||||||
<h2
|
|
||||||
class="text-lg font-semibold text-black dark:text-white p-4 border-b border-(--border-light) dark:border-(--border-dark)">
|
|
||||||
{{ t('Your Carts') }}
|
|
||||||
</h2>
|
|
||||||
<div v-if="cartStore.carts?.length > 0"
|
|
||||||
class="divide-y divide-(--border-light) dark:divide-(--border-dark)">
|
|
||||||
<div v-for="cart in cartStore.carts" :key="cart.cart_id"
|
|
||||||
@click="cartStore.setActiveCart(cart.cart_id)"
|
|
||||||
class="p-4 cursor-pointer flex gap-2 items-center justify-between" :class="cartStore.activeCartId === cart.cart_id
|
|
||||||
? 'bg-blue-50 dark:bg-blue-900/20'
|
|
||||||
: 'hover:bg-gray-50 dark:hover:bg-gray-800 border-l-4 border-transparent'">
|
|
||||||
<div class="flex-1 min-w-0">
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<p class="text-red-600 font-medium truncate">{{ cart.cart_id }}</p>
|
|
||||||
<p class="text-black dark:text-white font-medium truncate cursor-pointer"
|
|
||||||
@click="openCart(cart)">{{
|
|
||||||
cart.name }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input type="checkbox" :checked="cartStore.activeCartId === cart.cart_id"
|
|
||||||
@change="toggleCart(cart.cart_id)" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else class="p-8 text-center">
|
|
||||||
<UIcon name="mdi:cart-outline"
|
|
||||||
class="text-4xl text-gray-300 dark:text-gray-600 mb-2" />
|
|
||||||
<p class="text-gray-500 dark:text-gray-400">{{ t('No carts yet') }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<input type="checkbox" :checked="cartStore.activeCartId === cart.cart_id"
|
||||||
|
@change="toggleCart(cart.cart_id)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else class="p-8 text-center">
|
||||||
|
<UIcon name="mdi:cart-outline" class="text-4xl text-gray-300 dark:text-gray-600 mb-2" />
|
||||||
|
<p class="text-gray-500 dark:text-gray-400">{{ t('No carts yet') }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<UModal v-model:open="showCreateModal">
|
<UModal v-model:open="showCreateModal">
|
||||||
<template #header>
|
<template #header>
|
||||||
<h3 class="text-lg font-semibold text-black dark:text-white">{{ t('Create New Cart') }}</h3>
|
<h3 class="text-lg font-semibold text-black dark:text-white">{{ t('Create New Cart') }}</h3>
|
||||||
</template>
|
</template>
|
||||||
<template #body>
|
<template #body>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<UInput v-model="newCartName" :placeholder="t('Cart name')"
|
<UInput v-model="newCartName" :placeholder="t('Cart name')"
|
||||||
class="w-full bg-white dark:bg-gray-800 text-black dark:text-white" />
|
class="w-full bg-white dark:bg-gray-800 text-black dark:text-white" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="flex justify-end gap-2">
|
<div class="flex justify-end gap-2">
|
||||||
<UButton variant="outline" color="neutral" @click="showCreateModal = false">
|
<UButton variant="outline" color="neutral" @click="showCreateModal = false">
|
||||||
{{ t('Cancel') }}
|
{{ t('Cancel') }}
|
||||||
</UButton>
|
</UButton>
|
||||||
<UButton color="primary" @click="createCart" :disabled="!newCartName.trim()"
|
<UButton color="primary" @click="createCart" :disabled="!newCartName.trim()"
|
||||||
class="bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) text-white">
|
class="bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) text-white">
|
||||||
{{ t('Create') }}
|
{{ t('Create') }}
|
||||||
</UButton>
|
</UButton>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</UModal>
|
</UModal>
|
||||||
</div>
|
</component>
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #footer>
|
|
||||||
<div class="flex justify-end gap-2">
|
|
||||||
<UButton variant="outline" color="neutral" @click="showCreateModal = false">
|
|
||||||
{{ t('Cancel') }}
|
|
||||||
</UButton>
|
|
||||||
<UButton color="primary" @click="createCart" :disabled="!newCartName.trim()"
|
|
||||||
class="bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) text-white">
|
|
||||||
{{ t('Create') }}
|
|
||||||
</UButton>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { useCartStore } from '@/stores/customer/cart'
|
import { useCartStore } from '@/stores/customer/cart'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import Default from '@/layouts/default.vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useAddressStore } from '@/stores/customer/address'
|
|
||||||
const cartStore = useCartStore()
|
|
||||||
const addressStore = useAddressStore()
|
|
||||||
const { t } = useI18n()
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
const cartStore = useCartStore()
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const showCreateModal = ref(false)
|
const showCreateModal = ref(false)
|
||||||
const newCartName = ref('')
|
const newCartName = ref('')
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<UNavigationMenu orientation="vertical" type="single" :items="items" class="data-[orientation=vertical]:w-72" :ui="{
|
<UNavigationMenu orientation="vertical" type="single" :items="items" class="data-[orientation=vertical]:w-72" :ui="{
|
||||||
root:''
|
root: ''
|
||||||
}"/>
|
}" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -39,9 +39,10 @@ function adaptMenu(menu: NavigationMenuItem[]) {
|
|||||||
if (item.children && item.children.length > 0) {
|
if (item.children && item.children.length > 0) {
|
||||||
item.open = path && path.includes(item.category_id) ? true : openAll.value
|
item.open = path && path.includes(item.category_id) ? true : openAll.value
|
||||||
adaptMenu(item.children);
|
adaptMenu(item.children);
|
||||||
|
|
||||||
item.children.unshift({
|
item.children.unshift({
|
||||||
label: item.label, icon: 'i-lucide-book-open', popover: item.label, to: {
|
label: item.label, icon: 'i-lucide-book-open', popover: item.label, to: {
|
||||||
name: 'admin-products-category', params: {
|
name: item.params.to, params: {
|
||||||
category_id: item.params.category_id,
|
category_id: item.params.category_id,
|
||||||
link_rewrite: item.params.link_rewrite
|
link_rewrite: item.params.link_rewrite
|
||||||
}
|
}
|
||||||
@@ -49,7 +50,7 @@ function adaptMenu(menu: NavigationMenuItem[]) {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
item.to = {
|
item.to = {
|
||||||
name: 'admin-products-category', params: {
|
name: item.params.to, params: {
|
||||||
category_id: item.params.category_id,
|
category_id: item.params.category_id,
|
||||||
link_rewrite: item.params.link_rewrite
|
link_rewrite: item.params.link_rewrite
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import { useFetchJson } from '@/composable/useFetchJson'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
|
import type { AddressTemplate } from './cart'
|
||||||
|
|
||||||
export interface AddressFormData {
|
export interface AddressFormData {
|
||||||
street: string
|
street: string
|
||||||
@@ -17,7 +19,6 @@ export interface Address {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useAddressStore = defineStore('address', () => {
|
export const useAddressStore = defineStore('address', () => {
|
||||||
const addresses = ref<Address[]>([])
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const error = ref<string | null>(null)
|
const error = ref<string | null>(null)
|
||||||
|
|
||||||
@@ -50,11 +51,6 @@ export const useAddressStore = defineStore('address', () => {
|
|||||||
const totalItems = computed(() => filteredAddresses.value.length)
|
const totalItems = computed(() => filteredAddresses.value.length)
|
||||||
const totalPages = computed(() => Math.ceil(totalItems.value / pageSize))
|
const totalPages = computed(() => Math.ceil(totalItems.value / pageSize))
|
||||||
|
|
||||||
const paginatedAddresses = computed(() => {
|
|
||||||
const start = (currentPage.value - 1) * pageSize
|
|
||||||
return filteredAddresses.value.slice(start, start + pageSize)
|
|
||||||
})
|
|
||||||
|
|
||||||
function getAddressById(id: number) {
|
function getAddressById(id: number) {
|
||||||
return addresses.value.find(addr => addr.id === id)
|
return addresses.value.find(addr => addr.id === id)
|
||||||
}
|
}
|
||||||
@@ -72,41 +68,6 @@ export const useAddressStore = defineStore('address', () => {
|
|||||||
return Math.max(0, ...addresses.value.map(a => a.id)) + 1
|
return Math.max(0, ...addresses.value.map(a => a.id)) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAddress(formData: AddressFormData): Address {
|
|
||||||
const newAddress: Address = {
|
|
||||||
id: generateId(),
|
|
||||||
...normalize(formData)
|
|
||||||
}
|
|
||||||
|
|
||||||
addresses.value.unshift(newAddress)
|
|
||||||
resetPagination()
|
|
||||||
|
|
||||||
return newAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateAddress(id: number, formData: AddressFormData): boolean {
|
|
||||||
const index = addresses.value.findIndex(a => a.id === id)
|
|
||||||
if (index === -1) return false
|
|
||||||
|
|
||||||
const existing = addresses.value[index]
|
|
||||||
if (!existing) return false
|
|
||||||
|
|
||||||
addresses.value[index] = {
|
|
||||||
id: existing.id,
|
|
||||||
...normalize(formData)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
function deleteAddress(id: number): boolean {
|
|
||||||
const index = addresses.value.findIndex(a => a.id === id)
|
|
||||||
if (index === -1) return false
|
|
||||||
|
|
||||||
addresses.value.splice(index, 1)
|
|
||||||
resetPagination()
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
function setPage(page: number) {
|
function setPage(page: number) {
|
||||||
currentPage.value = page
|
currentPage.value = page
|
||||||
}
|
}
|
||||||
@@ -122,8 +83,123 @@ export const useAddressStore = defineStore('address', () => {
|
|||||||
|
|
||||||
initMockData()
|
initMockData()
|
||||||
|
|
||||||
|
const addresses = ref<Address[]>([])
|
||||||
|
const addressLoading = ref(false)
|
||||||
|
const addressError = ref<string | null>(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<string, string>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchAddresses() {
|
||||||
|
addressLoading.value = true
|
||||||
|
addressError.value = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
const queryParam = addressSearchQuery.value ? `&query=${encodeURIComponent(addressSearchQuery.value)}` : ''
|
||||||
|
const response = await useFetchJson<Address[]>(`/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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addAddress(countryId: number, formData: AddressTemplate): Promise<Address | null> {
|
||||||
|
addressLoading.value = true
|
||||||
|
addressError.value = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await useFetchJson<any>(`/api/v1/restricted/addresses/add-new-address?country_id=${countryId}`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(formData)
|
||||||
|
})
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAddressTemplate(countryId: number): Promise<AddressTemplate> {
|
||||||
|
const response = await useFetchJson<any>(`/api/v1/restricted/addresses/get-template?country_id=${countryId}`)
|
||||||
|
return response.items ?? {}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateAddress(id: number, countryId: number, formData: AddressTemplate): Promise<boolean> {
|
||||||
|
addressLoading.value = true
|
||||||
|
addressError.value = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
await useFetchJson<any>(`/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<boolean> {
|
||||||
|
addressLoading.value = true
|
||||||
|
addressError.value = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
await useFetchJson<any>(`/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()
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
addresses,
|
addresses,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
currentPage,
|
currentPage,
|
||||||
@@ -139,6 +215,17 @@ export const useAddressStore = defineStore('address', () => {
|
|||||||
deleteAddress,
|
deleteAddress,
|
||||||
setPage,
|
setPage,
|
||||||
setSearchQuery,
|
setSearchQuery,
|
||||||
resetPagination
|
resetPagination,
|
||||||
|
addressLoading,
|
||||||
|
addressError,
|
||||||
|
addressSearchQuery,
|
||||||
|
addressCurrentPage,
|
||||||
|
addressPageSize,
|
||||||
|
totalAddressItems,
|
||||||
|
totalAddressPages,
|
||||||
|
fetchAddresses,
|
||||||
|
setAddressPage,
|
||||||
|
setAddressSearchQuery,
|
||||||
|
getAddressTemplate
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -24,121 +24,18 @@ export const useCartStore = defineStore('cart', () => {
|
|||||||
const activeCartId = ref<number | null>(null)
|
const activeCartId = ref<number | null>(null)
|
||||||
const error = ref<string | null>(null)
|
const error = ref<string | null>(null)
|
||||||
|
|
||||||
const addresses = ref<Address[]>([])
|
async function fetchCarts() {
|
||||||
const addressLoading = ref(false)
|
|
||||||
const addressError = ref<string | null>(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<string, string>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchAddresses() {
|
|
||||||
addressLoading.value = true
|
|
||||||
addressError.value = null
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const queryParam = addressSearchQuery.value ? `&query=${encodeURIComponent(addressSearchQuery.value)}` : ''
|
const res = await useFetchJson<ApiResponse>(
|
||||||
const response = await useFetchJson<Address[]>(`/api/v1/restricted/addresses/retrieve-addresses?page=${addressCurrentPage.value}&elems=${addressPageSize}${queryParam}`)
|
`/api/v1/restricted/carts/retrieve-carts-info`
|
||||||
addresses.value = response.items || []
|
)
|
||||||
addressTotalCount.value = response.count ?? addresses.value.length
|
|
||||||
} catch (error: unknown) {
|
carts.value = res.items
|
||||||
addressError.value = error instanceof Error ? error.message : 'Failed to load addresses'
|
} catch (e: any) {
|
||||||
} finally {
|
error.value = e?.message ?? 'Error loading carts'
|
||||||
addressLoading.value = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addAddress(countryId: number, formData: AddressTemplate): Promise<Address | null> {
|
|
||||||
addressLoading.value = true
|
|
||||||
addressError.value = null
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await useFetchJson<any>(`/api/v1/restricted/addresses/add-new-address?country_id=${countryId}`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(formData)
|
|
||||||
})
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getAddressTemplate(countryId: number): Promise<AddressTemplate> {
|
|
||||||
const response = await useFetchJson<any>(`/api/v1/restricted/addresses/get-template?country_id=${countryId}`)
|
|
||||||
return response.items ?? {}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateAddress(id: number, countryId: number, formData: AddressTemplate): Promise<boolean> {
|
|
||||||
addressLoading.value = true
|
|
||||||
addressError.value = null
|
|
||||||
|
|
||||||
try {
|
|
||||||
await useFetchJson<any>(`/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<boolean> {
|
|
||||||
addressLoading.value = true
|
|
||||||
addressError.value = null
|
|
||||||
|
|
||||||
try {
|
|
||||||
await useFetchJson<any>(`/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()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function addNewCart(name: string) {
|
async function addNewCart(name: string) {
|
||||||
try {
|
try {
|
||||||
error.value = null
|
error.value = null
|
||||||
@@ -205,22 +102,15 @@ export const useCartStore = defineStore('cart', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
addresses,
|
carts,
|
||||||
addressLoading,
|
activeCartId,
|
||||||
addressError,
|
error,
|
||||||
addressSearchQuery,
|
errorMessage,
|
||||||
addressCurrentPage,
|
activeCart,
|
||||||
addressPageSize,
|
setActiveCart,
|
||||||
paginatedAddresses,
|
addProduct,
|
||||||
totalAddressItems,
|
fetchCarts,
|
||||||
totalAddressPages,
|
addNewCart,
|
||||||
fetchAddresses,
|
initCart,
|
||||||
addAddress,
|
|
||||||
updateAddress,
|
|
||||||
deleteAddress,
|
|
||||||
setAddressPage,
|
|
||||||
setAddressSearchQuery,
|
|
||||||
getAddressTemplate,
|
|
||||||
initCart
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user