diff --git a/bo/components.d.ts b/bo/components.d.ts
index 655bc41..d6733d5 100644
--- a/bo/components.d.ts
+++ b/bo/components.d.ts
@@ -16,8 +16,16 @@ declare module 'vue' {
En_PrivacyPolicyView: typeof import('./src/components/terms/en_PrivacyPolicyView.vue')['default']
En_TermsAndConditionsView: typeof import('./src/components/terms/en_TermsAndConditionsView.vue')['default']
LangSwitch: typeof import('./src/components/inner/langSwitch.vue')['default']
+ PageAddresses: typeof import('./src/components/customer/PageAddresses.vue')['default']
+ PageProductCardFull: typeof import('./src/components/customer/PageProductCardFull.vue')['default']
Pl_PrivacyPolicyView: typeof import('./src/components/terms/pl_PrivacyPolicyView.vue')['default']
Pl_TermsAndConditionsView: typeof import('./src/components/terms/pl_TermsAndConditionsView.vue')['default']
+ ProductCardFull: typeof import('./src/components/customer/ProductCardFull.vue')['default']
+ ProductCustomization: typeof import('./src/components/customer/components/ProductCustomization.vue')['default']
+ ProductDetailView: typeof import('./src/components/admin/ProductDetailView.vue')['default']
+ ProductsView: typeof import('./src/components/admin/ProductsView.vue')['default']
+ ProductVariants: typeof import('./src/components/customer/components/ProductVariants.vue')['default']
+ 'ProductСustomization': typeof import('./src/components/customer/components/ProductСustomization.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
ThemeSwitch: typeof import('./src/components/inner/themeSwitch.vue')['default']
@@ -32,6 +40,8 @@ declare module 'vue' {
UFormField: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/FormField.vue')['default']
UIcon: typeof import('./node_modules/@nuxt/ui/dist/runtime/vue/components/Icon.vue')['default']
UInput: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Input.vue')['default']
+ UInputNumber: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/InputNumber.vue')['default']
+ UModal: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Modal.vue')['default']
UPagination: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Pagination.vue')['default']
USelect: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Select.vue')['default']
USelectMenu: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/SelectMenu.vue')['default']
diff --git a/bo/src/app.config.ts b/bo/src/app.config.ts
index b9baa6c..6bcbbf3 100644
--- a/bo/src/app.config.ts
+++ b/bo/src/app.config.ts
@@ -22,6 +22,13 @@ export const uiOptions: NuxtUIOptions = {
error: 'text-red-600!'
},
},
+ inputNumber: {
+ slots: {
+ base: 'text-(--black) dark:text-white border! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0! pt-2 px-1! w-auto!',
+ increment: 'border-0! pe-0! ps-0!',
+ decrement: 'border-0! pe-0! ps-0!'
+ },
+ },
select: {
slots: {
base: 'w-full! cursor-pointer border! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0!',
@@ -43,7 +50,7 @@ export const uiOptions: NuxtUIOptions = {
}
},
- table: {
+ table: {
slots: {
base: 'border! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0! bg-(--second-light) dark:bg-(--main-dark)',
tr: 'border-b! border-(--border-light)! dark:border-(--border-dark)! outline-0! ring-0! text-(--black)! dark:text-white!',
diff --git a/bo/src/components/TopBar.vue b/bo/src/components/TopBar.vue
index eb632f7..10917ba 100644
--- a/bo/src/components/TopBar.vue
+++ b/bo/src/components/TopBar.vue
@@ -22,6 +22,12 @@ const authStore = useAuthStore()
product detail
+
+ ProductCardFull
+
+
+ Addresses
+
diff --git a/bo/src/views/TranslateProduct/ProductDetailView.vue b/bo/src/components/admin/ProductDetailView.vue
similarity index 100%
rename from bo/src/views/TranslateProduct/ProductDetailView.vue
rename to bo/src/components/admin/ProductDetailView.vue
diff --git a/bo/src/views/TranslateProduct/ProductsView.vue b/bo/src/components/admin/ProductsView.vue
similarity index 100%
rename from bo/src/views/TranslateProduct/ProductsView.vue
rename to bo/src/components/admin/ProductsView.vue
diff --git a/bo/src/components/customer/PageAddresses.vue b/bo/src/components/customer/PageAddresses.vue
new file mode 100644
index 0000000..02c6f92
--- /dev/null
+++ b/bo/src/components/customer/PageAddresses.vue
@@ -0,0 +1,154 @@
+
+
+
+
+
+ {{ t('addresses.title') }}
+
+
+
+ {{ t('addresses.addNew') }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ address.street }}
+
+
+ {{ address.zipCode }}, {{ address.city }}
+
+
{{ address.country }}
+
+
+
+
+
+
+
{{ t('addresses.noAddresses') }}
+
+ {{ t('addresses.addFirst') }}
+
+
+
+
+
+
+
+
diff --git a/bo/src/components/customer/PageProductCardFull.vue b/bo/src/components/customer/PageProductCardFull.vue
new file mode 100644
index 0000000..3341aca
--- /dev/null
+++ b/bo/src/components/customer/PageProductCardFull.vue
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+ {{ productData.name }}
+
+
+ {{ productData.description }}
+
+
+ {{ productData.price }}
+
+
+
+
Dimensions:
+
{{ productData.dimensions }}
+
+
+
Seat Height:
+
{{ productData.seatHeight }}
+
+
+
+
+
+
+
+
+
+ Add to Cart
+
+
+
+
+
+
+
+
+ {{ tab.label }}
+
+
+
+
+ {{ activeTabContent }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bo/src/components/customer/components/ProductCustomization.vue b/bo/src/components/customer/components/ProductCustomization.vue
new file mode 100644
index 0000000..4470502
--- /dev/null
+++ b/bo/src/components/customer/components/ProductCustomization.vue
@@ -0,0 +1,16 @@
+
+
+
+
Product customization
+
Don't forget to save your customization to be able to add to cart
+
+
+
+
+
+
+
+ Save
+
+
+
\ No newline at end of file
diff --git a/bo/src/components/customer/components/ProductVariants.vue b/bo/src/components/customer/components/ProductVariants.vue
new file mode 100644
index 0000000..feb1895
--- /dev/null
+++ b/bo/src/components/customer/components/ProductVariants.vue
@@ -0,0 +1,57 @@
+
+
+
Product Variants:
+
+
+
+
+
{{ variant.name }}
+
{{ variant.productNumber }}
+
{{ variant.value }}
+
{{ variant.price }}
+
{{ variant.quantity }}
+
+ Add to Cart
+
+
+
+
+
+
+
+
diff --git a/bo/src/router/index.ts b/bo/src/router/index.ts
index a0fe04e..eed2bb9 100644
--- a/bo/src/router/index.ts
+++ b/bo/src/router/index.ts
@@ -5,8 +5,6 @@ import { getSettings } from './settings'
import { useAuthStore } from '@/stores/auth'
import Default from '@/layouts/default.vue'
-// Helper: read the non-HTTPOnly is_authenticated cookie set by the backend.
-// The backend sets it to "1" on login and removes it on logout.
function isAuthenticated(): boolean {
if (typeof document === 'undefined') return false
return document.cookie.split('; ').some((c) => c === 'is_authenticated=1')
@@ -31,8 +29,10 @@ const router = createRouter({
component: Default,
children: [
{ path: '', component: () => import('../views/RepoChartView.vue'), name: 'home' },
- { path: 'products', component: () => import('../views/customer/ProductsView.vue'), name: 'products' },
- { path: 'products-datail/', component: () => import('../views/customer/ProductDetailView.vue'), name: 'product-detail' },
+ { path: 'products', component: () => import('../components/admin/ProductsView.vue'), name: 'products' },
+ { path: 'products-datail/', component: () => import('../components/admin/ProductDetailView.vue'), name: 'product-detail' },
+ { path: 'product-card-full/', component: () => import('../components/customer/PageProductCardFull.vue'), name: 'product-card-full' },
+ { path: 'addresses', component: () => import('../components/customer/PageAddresses.vue'), name: 'addresses' },
],
},
{
@@ -51,34 +51,28 @@ const router = createRouter({
],
})
-// Navigation guard: language handling + auth protection
router.beforeEach((to, from, next) => {
const locale = to.params.locale as string
const localeLang = langs.find((x) => x.iso_code == locale)
- // Check if the locale is valid
if (locale && langs.length > 0) {
const authStore = useAuthStore()
- console.log(authStore.isAuthenticated,to, from)
+ console.log(authStore.isAuthenticated, to, from)
// if()
const validLocale = langs.find((l) => l.lang_code === locale)
if (validLocale) {
currentLang.value = localeLang
-
- // Auth guard: if the route does NOT have meta.guest = true, require authentication
if (!to.meta?.guest && !isAuthenticated()) {
return next({ name: 'login', params: { locale } })
}
return next()
} else if (locale) {
- // Invalid locale - redirect to default language
return next(`/${currentLang.value?.iso_code}${to.path.replace(`/${locale}`, '') || '/'}`)
}
}
- // No locale in URL - redirect to default language
if (!locale && to.path !== '/') {
return next(`/${currentLang.value?.iso_code}${to.path}`)
}
diff --git a/bo/src/stores/address.ts b/bo/src/stores/address.ts
new file mode 100644
index 0000000..d76c713
--- /dev/null
+++ b/bo/src/stores/address.ts
@@ -0,0 +1,136 @@
+import { defineStore } from 'pinia'
+import { ref, computed } from 'vue'
+
+export interface AddressFormData {
+ street: string
+ zipCode: string
+ city: string
+ country: string
+}
+
+export interface Address {
+ id: number
+ street: string
+ zipCode: string
+ city: string
+ country: string
+}
+
+export const useAddressStore = defineStore('address', () => {
+ const addresses = ref
([])
+ const loading = ref(false)
+ const error = ref(null)
+
+ const currentPage = ref(1)
+ const pageSize = 10
+ const totalItems = computed(() => filteredAddresses.value.length)
+ const totalPages = computed(() => Math.ceil(totalItems.value / pageSize))
+
+ const searchQuery = ref('')
+
+ function initMockData() {
+ addresses.value = [
+ {
+ id: 1,
+ street: 'Main Street 123',
+ zipCode: '10-001',
+ city: 'New York',
+ country: 'United States'
+ },
+ {
+ id: 2,
+ street: 'Oak Avenue 123',
+ zipCode: '90-001',
+ city: 'Los Angeles',
+ country: 'United States'
+ },
+ {
+ id: 3,
+ street: 'Pine Road 123 ',
+ zipCode: '60-601',
+ city: 'Chicago',
+ country: 'United States'
+ }
+ ]
+ }
+
+ const filteredAddresses = computed(() => {
+ if (!searchQuery.value) {
+ return addresses.value
+ }
+
+ const query = searchQuery.value.toLowerCase()
+
+ return addresses.value.filter(addr =>
+ addr.street.toLowerCase().includes(query) ||
+ addr.city.toLowerCase().includes(query) ||
+ addr.country.toLowerCase().includes(query) ||
+ addr.zipCode.toLowerCase().includes(query)
+ )
+ })
+ const paginatedAddresses = computed(() => {
+ const start = (currentPage.value - 1) * pageSize
+ const end = start + pageSize
+ return filteredAddresses.value.slice(start, end)
+ })
+
+ function getAddressById(id: number): Address | undefined {
+ return addresses.value.find(addr => addr.id === id)
+ }
+
+ function addAddress(formData: AddressFormData): Address {
+ const now = new Date().toISOString()
+
+ const newAddress: Address = {
+ id: Date.now(),
+ ...formData,
+ }
+
+ addresses.value.push(newAddress)
+
+ return newAddress
+ }
+
+ function deleteAddress(id: number): boolean {
+ const index = addresses.value.findIndex(addr => addr.id === id)
+ if (index === -1) return false
+
+ addresses.value.splice(index, 1)
+
+ return true
+ }
+
+ function setPage(page: number) {
+ currentPage.value = page
+ }
+
+ function setSearchQuery(query: string) {
+ searchQuery.value = query
+ currentPage.value = 1
+ }
+
+ function resetPagination() {
+ currentPage.value = 1
+ }
+
+ initMockData()
+
+ return {
+ addresses,
+ loading,
+ error,
+ currentPage,
+ pageSize,
+ totalItems,
+ totalPages,
+ searchQuery,
+ filteredAddresses,
+ paginatedAddresses,
+ getAddressById,
+ addAddress,
+ deleteAddress,
+ setPage,
+ setSearchQuery,
+ resetPagination
+ }
+})