fix: currency/county
This commit is contained in:
7
bo/components.d.ts
vendored
7
bo/components.d.ts
vendored
@@ -12,13 +12,14 @@ export {}
|
|||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
CartDetails: typeof import('./src/components/customer/CartDetails.vue')['default']
|
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']
|
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_PrivacyPolicyView: typeof import('./src/components/terms/cs_PrivacyPolicyView.vue')['default']
|
||||||
Cs_TermsAndConditionsView: typeof import('./src/components/terms/cs_TermsAndConditionsView.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_PrivacyPolicyView: typeof import('./src/components/terms/en_PrivacyPolicyView.vue')['default']
|
||||||
En_TermsAndConditionsView: typeof import('./src/components/terms/en_TermsAndConditionsView.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']
|
PageAddresses: typeof import('./src/components/customer/PageAddresses.vue')['default']
|
||||||
PageCarts: typeof import('./src/components/customer/PageCarts.vue')['default']
|
PageCarts: typeof import('./src/components/customer/PageCarts.vue')['default']
|
||||||
PageOrders: typeof import('./src/components/customer/PageOrders.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']
|
ProductVariants: typeof import('./src/components/customer/components/ProductVariants.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
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']
|
TopBar: typeof import('./src/components/TopBar.vue')['default']
|
||||||
TopBarLogin: typeof import('./src/components/TopBarLogin.vue')['default']
|
TopBarLogin: typeof import('./src/components/TopBarLogin.vue')['default']
|
||||||
UAlert: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Alert.vue')['default']
|
UAlert: typeof import('./node_modules/@nuxt/ui/dist/runtime/components/Alert.vue')['default']
|
||||||
|
|||||||
@@ -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">
|
<script setup lang="ts">
|
||||||
import { useFetchJson } from '@/composable/useFetchJson'
|
import { useFetchJson } from '@/composable/useFetchJson'
|
||||||
import LangSwitch from './inner/langSwitch.vue'
|
import LangSwitch from './inner/LangSwitch.vue'
|
||||||
import ThemeSwitch from './inner/themeSwitch.vue'
|
import ThemeSwitch from './inner/ThemeSwitch.vue'
|
||||||
import { useAuthStore } from '@/stores/auth'
|
import { useAuthStore } from '@/stores/auth'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { currentLang } from '@/router/langs'
|
import { currentLang } from '@/router/langs'
|
||||||
import type { LabelTrans, TopMenuItem } from '@/types'
|
import type { LabelTrans, TopMenuItem } from '@/types'
|
||||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
import type { NavigationMenuItem } from '@nuxt/ui'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import CountryCurrencySwitch from './inner/CountryCurrencySwitch.vue'
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
let menu = ref()
|
let menu = ref()
|
||||||
@@ -51,37 +87,3 @@ function transformMenu(items: TopMenuItem[], locale: string | undefined): Naviga
|
|||||||
}
|
}
|
||||||
await getTopMenu()
|
await getTopMenu()
|
||||||
</script>
|
</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>
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import LangSwitch from './inner/langSwitch.vue'
|
import LangSwitch from './inner/LangSwitch.vue'
|
||||||
import ThemeSwitch from './inner/themeSwitch.vue'
|
import ThemeSwitch from './inner/ThemeSwitch.vue'
|
||||||
import { useAuthStore } from '@/stores/auth'
|
import { useAuthStore } from '@/stores/auth'
|
||||||
|
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { useFetchJson } from '@/composable/useFetchJson'
|
|||||||
import Default from '@/layouts/default.vue'
|
import Default from '@/layouts/default.vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import type { TableColumn } from '@nuxt/ui'
|
import type { TableColumn } from '@nuxt/ui'
|
||||||
import CategoryMenu from '../inner/categoryMenu.vue'
|
import CategoryMenu from '../inner/CategoryMenu.vue'
|
||||||
import type { Product } from '@/types/product'
|
import type { Product } from '@/types/product'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ import { useFetchJson } from '@/composable/useFetchJson'
|
|||||||
import Default from '@/layouts/default.vue'
|
import Default from '@/layouts/default.vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import type { TableColumn } from '@nuxt/ui'
|
import type { TableColumn } from '@nuxt/ui'
|
||||||
import CategoryMenu from '../inner/categoryMenu.vue'
|
import CategoryMenu from '../inner/CategoryMenu.vue'
|
||||||
|
|
||||||
interface Product {
|
interface Product {
|
||||||
reference: number
|
reference: number
|
||||||
|
|||||||
68
bo/src/components/inner/CountryCurrencySwitch.vue
Normal file
68
bo/src/components/inner/CountryCurrencySwitch.vue
Normal 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>
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
|
|
||||||
import { useFetchJson } from '@/composable/useFetchJson'
|
import { useFetchJson } from '@/composable/useFetchJson'
|
||||||
import { initLangs, langs } from '@/router/langs'
|
import { initCountryCurrency, initLangs, langs } from '@/router/langs'
|
||||||
import { watch } from 'vue'
|
import { watch } from 'vue'
|
||||||
import { createI18n, type PathValue } from 'vue-i18n'
|
import { createI18n, type PathValue } from 'vue-i18n'
|
||||||
|
|
||||||
// const x =
|
// const x =
|
||||||
await initLangs()
|
await initLangs()
|
||||||
|
await initCountryCurrency()
|
||||||
export const i18ninstall = createI18n({
|
export const i18ninstall = createI18n({
|
||||||
legacy: false, // you must set `false`, to use Composition API
|
legacy: false, // you must set `false`, to use Composition API
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import { useCookie } from "@/composable/useCookie"
|
import { useCookie } from "@/composable/useCookie"
|
||||||
import { useFetchJson } from "@/composable/useFetchJson"
|
import { useFetchJson } from "@/composable/useFetchJson"
|
||||||
import type { Language } from "@/types"
|
import type { Country, Language } from "@/types"
|
||||||
import { reactive, ref } from "vue"
|
import { reactive, ref } from "vue"
|
||||||
|
|
||||||
export const langs = reactive([] as Language[])
|
export const langs = reactive([] as Language[])
|
||||||
export const currentLang = ref<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()
|
const cookie = useCookie()
|
||||||
// Get available language codes for route matching
|
// Get available language codes for route matching
|
||||||
// export const availableLocales = computed(() => langs.map((l) => l.lang_code))
|
// export const availableLocales = computed(() => langs.map((l) => l.lang_code))
|
||||||
@@ -22,8 +26,27 @@ export async function initLangs() {
|
|||||||
if (cc) {
|
if (cc) {
|
||||||
idfromcookie = langs.find((x) => x.id == parseInt(cc))
|
idfromcookie = langs.find((x) => x.id == parseInt(cc))
|
||||||
}
|
}
|
||||||
deflang.value = items.find((x) => x.is_default == true)
|
defLang.value = items.find((x) => x.is_default == true)
|
||||||
currentLang.value = idfromcookie ?? deflang.value
|
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) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch languages:', error)
|
console.error('Failed to fetch languages:', error)
|
||||||
}
|
}
|
||||||
|
|||||||
17
bo/src/types/lang.d.ts
vendored
17
bo/src/types/lang.d.ts
vendored
@@ -12,3 +12,20 @@ export interface Language {
|
|||||||
active: boolean
|
active: boolean
|
||||||
flag: string
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user