Merge branch 'front-styles' of ssh://git.ma-al.com:8822/goc_daniel/b2b into translate

This commit is contained in:
2026-04-01 10:53:49 +02:00
12 changed files with 161 additions and 49 deletions

7
bo/components.d.ts vendored
View File

@@ -12,13 +12,14 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
CartDetails: typeof import('./src/components/customer/CartDetails.vue')['default']
CategoryMenu: typeof import('./src/components/inner/categoryMenu.vue')['default']
CategoryMenu: typeof import('./src/components/inner/CategoryMenu.vue')['default']
CategoryMenuListing: typeof import('./src/components/inner/categoryMenuListing.vue')['default']
CountryCurrencySwitch: typeof import('./src/components/inner/CountryCurrencySwitch.vue')['default']
Cs_PrivacyPolicyView: typeof import('./src/components/terms/cs_PrivacyPolicyView.vue')['default']
Cs_TermsAndConditionsView: typeof import('./src/components/terms/cs_TermsAndConditionsView.vue')['default']
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']
LangSwitch: typeof import('./src/components/inner/LangSwitch.vue')['default']
PageAddresses: typeof import('./src/components/customer/PageAddresses.vue')['default']
PageCarts: typeof import('./src/components/customer/PageCarts.vue')['default']
PageOrders: typeof import('./src/components/customer/PageOrders.vue')['default']
@@ -34,7 +35,7 @@ declare module 'vue' {
ProductVariants: typeof import('./src/components/customer/components/ProductVariants.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
ThemeSwitch: typeof import('./src/components/inner/themeSwitch.vue')['default']
ThemeSwitch: typeof import('./src/components/inner/ThemeSwitch.vue')['default']
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']

View File

@@ -1,13 +1,49 @@
<template>
<header
class="fixed top-0 left-0 right-0 z-50 bg-white/80 dark:bg-(--black) backdrop-blur-md border-b border-(--border-light) dark:border-(--border-dark)">
<!-- px-4 sm:px-6 lg:px-8 -->
<div class="container mx-auto px-4">
<div class="flex items-center justify-between h-14">
<!-- Logo -->
<RouterLink :to="{ name: 'home' }" class="flex items-center gap-2">
<div class="w-8 h-8 rounded-lg bg-primary text-white flex items-center justify-center">
<UIcon name="i-heroicons-clock" class="w-5 h-5" />
</div>
<span class="font-semibold text-gray-900 dark:text-white">TimeTracker</span>
</RouterLink>
<UNavigationMenu :type="'trigger'" :ui="{
root: 'justify-center',
list: 'gap-4'
}" :items="menuItems" class="w-full"></UNavigationMenu>
<div class="flex items-center gap-2">
<CountryCurrencySwitch />
<!-- Language Switcher -->
<LangSwitch />
<!-- Theme Switcher -->
<ThemeSwitch />
<!-- Logout Button (only when authenticated) -->
<button v-if="authStore.isAuthenticated" @click="authStore.logout()"
class="px-3 py-1.5 text-sm font-medium text-black dark:text-white hover:text-black dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-600 rounded-lg transition-colors border border-(--border-light) dark:border-(--border-dark)">
{{ $t('general.logout') }}
</button>
</div>
</div>
</div>
</header>
</template>
<script setup lang="ts">
import { useFetchJson } from '@/composable/useFetchJson'
import LangSwitch from './inner/langSwitch.vue'
import ThemeSwitch from './inner/themeSwitch.vue'
import LangSwitch from './inner/LangSwitch.vue'
import ThemeSwitch from './inner/ThemeSwitch.vue'
import { useAuthStore } from '@/stores/auth'
import { computed, onMounted, ref } from 'vue'
import { computed, ref } from 'vue'
import { currentLang } from '@/router/langs'
import type { LabelTrans, TopMenuItem } from '@/types'
import type { NavigationMenuItem } from '@nuxt/ui'
import { useRoute, useRouter } from 'vue-router'
import CountryCurrencySwitch from './inner/CountryCurrencySwitch.vue'
const authStore = useAuthStore()
let menu = ref()
@@ -51,37 +87,3 @@ function transformMenu(items: TopMenuItem[], locale: string | undefined): Naviga
}
await getTopMenu()
</script>
<template>
<header
class="fixed top-0 left-0 right-0 z-50 bg-white/80 dark:bg-(--black) backdrop-blur-md border-b border-(--border-light) dark:border-(--border-dark)">
<!-- px-4 sm:px-6 lg:px-8 -->
<div class="container mx-auto px-4">
<div class="flex items-center justify-between h-14">
<!-- Logo -->
<RouterLink :to="{ name: 'home' }" class="flex items-center gap-2">
<div class="w-8 h-8 rounded-lg bg-primary text-white flex items-center justify-center">
<UIcon name="i-heroicons-clock" class="w-5 h-5" />
</div>
<span class="font-semibold text-gray-900 dark:text-white">TimeTracker</span>
</RouterLink>
<UNavigationMenu :type="'trigger'" :ui="{
root: 'justify-center',
list: 'gap-4'
}" :items="menuItems" class="w-full"></UNavigationMenu>
<div class="flex items-center gap-2">
<!-- Language Switcher -->
<LangSwitch />
<!-- Theme Switcher -->
<ThemeSwitch />
<!-- Logout Button (only when authenticated) -->
<button v-if="authStore.isAuthenticated" @click="authStore.logout()"
class="px-3 py-1.5 text-sm font-medium text-black dark:text-white hover:text-black dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-600 rounded-lg transition-colors border border-(--border-light) dark:border-(--border-dark)">
{{ $t('general.logout') }}
</button>
</div>
</div>
</div>
</header>
</template>

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import LangSwitch from './inner/langSwitch.vue'
import ThemeSwitch from './inner/themeSwitch.vue'
import LangSwitch from './inner/LangSwitch.vue'
import ThemeSwitch from './inner/ThemeSwitch.vue'
import { useAuthStore } from '@/stores/auth'
const authStore = useAuthStore()

View File

@@ -18,7 +18,7 @@ import { useFetchJson } from '@/composable/useFetchJson'
import Default from '@/layouts/default.vue'
import { useRoute, useRouter } from 'vue-router'
import type { TableColumn } from '@nuxt/ui'
import CategoryMenu from '../inner/categoryMenu.vue'
import CategoryMenu from '../inner/CategoryMenu.vue'
import type { Product } from '@/types/product'
const router = useRouter()

View File

@@ -46,7 +46,7 @@ import { useFetchJson } from '@/composable/useFetchJson'
import Default from '@/layouts/default.vue'
import { useRoute, useRouter } from 'vue-router'
import type { TableColumn } from '@nuxt/ui'
import CategoryMenu from '../inner/categoryMenu.vue'
import CategoryMenu from '../inner/CategoryMenu.vue'
interface Product {
reference: number

View File

@@ -0,0 +1,68 @@
<template>
<p>Country: {{ currentCountry?.name }}</p>
<p>Currency: {{ currentCountry?.ps_currency.iso_code }}</p>
<USelectMenu v-model="country" :items="countries"
class="w-40 bg-(--main-light) dark:bg-(--black) rounded-md shadow-sm hover:none!" valueKey="id"
:searchInput="false">
<template #default="{ modelValue }">
<div class="flex items-center gap-1">
<span class="font-medium dark:text-white text-black">{{ modelValue.name }}</span>
</div>
</template>
<template #item-leading="{ item }">
<div class="flex items-center rounded-md cursor-pointer transition-colors">
<span class="ml-2 dark:text-white text-black font-medium">{{ item.name }}</span>
</div>
</template>
</USelectMenu>
</template>
<script setup lang="ts">
import { countries, currentCountry } from '@/router/langs'
import { useRouter, useRoute } from 'vue-router'
import { useCookie } from '@/composable/useCookie'
import { computed, watch } from 'vue'
import { i18n } from '@/plugins/02_i18n'
import { useFetchJson } from '@/composable/useFetchJson'
const router = useRouter()
const route = useRoute()
const cookie = useCookie()
const country = computed({
get() {
return currentCountry.value
},
set(value: string) {
// i18n.locale.value = value
currentCountry.value = countries.find((x) => x.id == Number(value))
cookie.setCookie('country_id', `${countries.find((x) => x.id == Number(value))?.id}`, { days: 60, secure: true, sameSite: 'Lax' })
// changeLang()
},
})
// async function changeLang() {
// try {
// const { items } = await useFetchJson('/api/v1/public/auth/update-choice', {
// method: 'POST'
// })
// } catch (error) {
// console.log(error)
// }
// }
watch(
() => country,
(newCountry) => {
if (newCountry) {
console.log(newCountry.value);
// i18n.locale.value = newLocale
currentCountry.value = countries.find((x) => x.id == Number(newCountry.value?.id))
}
},
{ immediate: true },
)
</script>

View File

@@ -1,11 +1,12 @@
import { useFetchJson } from '@/composable/useFetchJson'
import { initLangs, langs } from '@/router/langs'
import { initCountryCurrency, initLangs, langs } from '@/router/langs'
import { watch } from 'vue'
import { createI18n, type PathValue } from 'vue-i18n'
// const x =
await initLangs()
await initCountryCurrency()
export const i18ninstall = createI18n({
legacy: false, // you must set `false`, to use Composition API
locale: 'en',

View File

@@ -1,12 +1,16 @@
import { useCookie } from "@/composable/useCookie"
import { useFetchJson } from "@/composable/useFetchJson"
import type { Language } from "@/types"
import type { Country, Language } from "@/types"
import { reactive, ref } from "vue"
export const langs = reactive([] as Language[])
export const currentLang = ref<Language>()
const deflang = ref<Language>()
export const countries = reactive([] as Country[])
export const currentCountry = ref<Country>()
const defLang = ref<Language>()
const defCountry = ref<Country>()
const cookie = useCookie()
// Get available language codes for route matching
// export const availableLocales = computed(() => langs.map((l) => l.lang_code))
@@ -22,8 +26,27 @@ export async function initLangs() {
if (cc) {
idfromcookie = langs.find((x) => x.id == parseInt(cc))
}
deflang.value = items.find((x) => x.is_default == true)
currentLang.value = idfromcookie ?? deflang.value
defLang.value = items.find((x) => x.is_default == true)
currentLang.value = idfromcookie ?? defLang.value
} catch (error) {
console.error('Failed to fetch languages:', error)
}
}
// Initialize country/currency from API
export async function initCountryCurrency() {
try {
const { items } = await useFetchJson<Country[]>('/api/v1/restricted/langs-and-countries/get-countries')
countries.push(...items)
let idfromcookie = null
const cc = cookie.getCookie('country_id')
if (cc) {
idfromcookie = langs.find((x) => x.id == parseInt(cc))
}
defCountry.value = items.find((x) => x.id === defLang.value?.id)
currentCountry.value = idfromcookie ?? defCountry.value
} catch (error) {
console.error('Failed to fetch languages:', error)
}

View File

@@ -12,3 +12,20 @@ export interface Language {
active: boolean
flag: string
}
export interface Country {
id: number
name: string
flag: string
currency_id: string
ps_currency: {
id_currency: string
name: string
iso_code: string
numeric_iso_code: string
precision: number
conversion_rate: number
deleted: boolean
active: boolean
}
}