-
-
-
-
- {{availableLangs.find(x => x.iso_code == modelValue)?.flag}}
- {{availableLangs.find(x => x.iso_code ==
- modelValue)?.name}}
-
-
-
-
- {{ item.flag }}
- {{ item.name }}
-
-
-
+
+
+
+
+
+
+
+
+ {{ langOptions.find(l => l.id === modelValue)?.name }}
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+ Translate
+
+
+
+
+
+
+
+ Back to Polish
+
+
-
- Translate
-
+
+ No translation available
+
+
@@ -38,18 +66,23 @@
+
+
Product Image
+
- {{ productStore.productDescription.name || 'Product Name' }}
+ {{ productName || 'Product Name' }}
-
+
+
+
@@ -57,6 +90,7 @@
{{ productStore.productDescription.available_now }}
+
+
-
- Description
+
+ Description
-
- Usage
+
+ Usage
-
-
-
-
- Change Text
-
-
-
- Save the edited text
-
-
- Cancel
+
+
+
+
+ Edit Usage
+ Save
+ Cancel
-
-
+
-
-
-
- Change Text
-
+
+
+
+
+ Edit Description
-
- Save the edited text
-
-
Cancel
-
-
+ Save
+ Cancel
+
+
@@ -132,118 +146,175 @@
import { ref, computed, onMounted, watch } from 'vue'
import { useRoute } from 'vue-router'
import { useProductStore } from '@/stores/product'
-import { useEditable } from '@/composable/useConteditable'
+import { useSettingsStore } from '@/stores/settings'
import { langs } from '@/router/langs'
-import type { Language } from '@/types'
+import { useEditable } from '@/composable/useConteditable'
import Default from '@/layouts/default.vue'
const route = useRoute()
-const activeTab = ref('description')
const productStore = useProductStore()
+const settingsStore = useSettingsStore()
+
+const activeTab = ref('description')
const translating = ref(false)
+const noTranslation = ref(false)
-const isEditing = ref(false)
-
-const availableLangs = computed(() => langs)
-
-const selectedLanguage = ref('en')
-
-const currentLangId = ref(2)
-const productID = ref(0)
-
-// Watch for language changes and refetch product description
-watch(selectedLanguage, async (newLang: string) => {
- if (productID.value) {
- await fetchForLanguage(newLang)
- }
-})
-
-const fetchForLanguage = async (langCode: string) => {
- const lang = langs.find((l: Language) => l.iso_code === langCode)
- if (lang && productID.value) {
- await productStore.getProductDescription(lang.id, productID.value)
- currentLangId.value = lang.id
- }
-}
-
-const translateToSelectedLanguage = async () => {
- const targetLang = langs.find((l: Language) => l.iso_code === selectedLanguage.value)
- if (targetLang && currentLangId.value && productID.value) {
- translating.value = true
- try {
- await productStore.translateProductDescription(productID.value, currentLangId.value, targetLang.id)
- currentLangId.value = targetLang.id
- } finally {
- translating.value = false
- }
- }
-}
-
-onMounted(async () => {
- const id = route.params.product_id
- if (id) {
- productID.value = Number(id)
- await fetchForLanguage(selectedLanguage.value)
- }
-})
+const defaultLangId = ref(0)
+const selectedLangId = ref(0)
+const activeLangId = ref(0)
+const productID = ref(0)
const descriptionRef = ref(null)
const usageRef = ref(null)
const descriptionEdit = useEditable(descriptionRef)
const usageEdit = useEditable(usageRef)
+const isEditing = ref(false)
-const originalDescription = ref('')
const originalUsage = ref('')
+const originalDescription = ref('')
-const saveDescription = async () => {
- descriptionEdit.disableEdit()
- await productStore.saveProductDescription(productID.value)
-}
+const langOptions = computed(() => langs.filter(l => l.active !== false))
-const cancelDescriptionEdit = () => {
- if (descriptionRef.value) {
- descriptionRef.value.innerHTML = originalDescription.value
+watch(selectedLangId, async (newLang) => {
+ if (!productID.value) return
+
+ if (newLang === defaultLangId.value) {
+ noTranslation.value = false
+ activeLangId.value = defaultLangId.value
+ await productStore.getProductDescription(defaultLangId.value, productID.value)
+ await productStore.getDefaultProductDescription(defaultLangId.value, productID.value)
+ return
}
- descriptionEdit.disableEdit()
+
+ await productStore.getProductDescription(newLang, productID.value)
+
+ const desc = productStore.productDescription
+
+ if (!desc || (!desc.description && !desc.description_short && !desc.usage)) {
+ noTranslation.value = true
+ activeLangId.value = defaultLangId.value
+ await productStore.getDefaultProductDescription(defaultLangId.value, productID.value)
+ } else {
+ noTranslation.value = false
+ activeLangId.value = newLang
+ }
+})
+
+const isViewingExistingTranslation = computed(() => activeLangId.value !== defaultLangId.value && !noTranslation.value)
+
+const productName = computed(() => {
+ if (activeLangId.value !== defaultLangId.value && !noTranslation.value) {
+ return productStore.productDescription?.name || ''
+ }
+ return productStore.defaultProductDescription?.name || productStore.productDescription?.name || ''
+})
+
+const displayedDescription = computed(() => {
+ if (activeLangId.value !== defaultLangId.value && !noTranslation.value) {
+ return productStore.productDescription?.description || ''
+ }
+ return productStore.defaultProductDescription?.description || ''
+})
+
+const displayedShortDescription = computed(() => {
+ if (activeLangId.value !== defaultLangId.value && !noTranslation.value) {
+ return productStore.productDescription?.description_short || ''
+ }
+ return productStore.defaultProductDescription?.description_short || ''
+})
+
+const displayedUsage = computed(() => {
+ if (activeLangId.value !== defaultLangId.value && !noTranslation.value) {
+ return productStore.productDescription?.usage || ''
+ }
+ return productStore.defaultProductDescription?.usage || ''
+})
+
+const goBackToDefault = async () => {
+ selectedLangId.value = defaultLangId.value
+ activeLangId.value = defaultLangId.value
+ noTranslation.value = false
+ await productStore.getProductDescription(defaultLangId.value, productID.value)
+ await productStore.getDefaultProductDescription(defaultLangId.value, productID.value)
}
+const translateOrSave = async () => {
+ if (!productID.value || selectedLangId.value === defaultLangId.value) return
+
+ translating.value = true
+ try {
+ const res = await productStore.translateProductDescription(productID.value, defaultLangId.value, selectedLangId.value)
+ if (res) {
+ activeLangId.value = selectedLangId.value
+ noTranslation.value = false
+ }
+ } finally {
+ translating.value = false
+ }
+}
+
+const btnClass = (tab: string) => ['cursor-pointer px-4 py-2', activeTab.value === tab ? 'bg-blue-500 text-white' : '']
+
+/* USAGE EDIT */
+const enableUsageEdit = () => {
+ originalUsage.value = displayedUsage.value
+ usageEdit.enableEdit()
+ isEditing.value = true
+}
+const saveUsage = async () => {
+ if (usageRef.value && productStore.productDescription) {
+ productStore.productDescription.usage = usageRef.value.innerHTML
+ }
+ usageEdit.disableEdit()
+ isEditing.value = false
+ await productStore.saveProductDescription(productID.value, activeLangId.value, 1)
+}
+const cancelUsageEdit = () => {
+ if (usageRef.value) usageRef.value.innerHTML = originalUsage.value
+ if (productStore.productDescription) productStore.productDescription.usage = originalUsage.value
+ usageEdit.disableEdit()
+ isEditing.value = false
+}
+
+/* DESCRIPTION EDIT */
const enableDescriptionEdit = () => {
- if (descriptionRef.value) {
- originalDescription.value = descriptionRef.value.innerHTML
- }
+ originalDescription.value = displayedDescription.value
descriptionEdit.enableEdit()
}
-
-const enableEdit = () => {
- if (usageRef.value) {
- originalUsage.value = usageRef.value.innerHTML
+const saveDescription = async () => {
+ if (descriptionRef.value && productStore.productDescription) {
+ productStore.productDescription.description = descriptionRef.value.innerHTML
}
- isEditing.value = true
- usageEdit.enableEdit()
+ descriptionEdit.disableEdit()
+ await productStore.saveProductDescription(productID.value, activeLangId.value, 1)
+}
+const cancelDescriptionEdit = () => {
+ if (descriptionRef.value) descriptionRef.value.innerHTML = originalDescription.value
+ if (productStore.productDescription) productStore.productDescription.description = originalDescription.value
+ descriptionEdit.disableEdit()
}
-const saveText = () => {
- usageEdit.disableEdit()
- isEditing.value = false
- productStore.saveProductDescription(productID.value)
-}
-
-const cancelEdit = () => {
- if (usageRef.value) {
- usageRef.value.innerHTML = originalUsage.value
+onMounted(async () => {
+ const settings = await settingsStore.getSettings()
+ if (settings) {
+ defaultLangId.value = settings.app.shop_default_language
+ selectedLangId.value = defaultLangId.value
+ activeLangId.value = defaultLangId.value
}
- usageEdit.disableEdit()
- isEditing.value = false
-}
-
+ const id = route.params.product_id
+ if (id) {
+ productID.value = Number(id)
+ await productStore.getProductDescription(defaultLangId.value, productID.value)
+ await productStore.getDefaultProductDescription(defaultLangId.value, productID.value)
+ }
+})
\ No newline at end of file
diff --git a/bo/src/stores/product.ts b/bo/src/stores/product.ts
index fe533db..9380645 100644
--- a/bo/src/stores/product.ts
+++ b/bo/src/stores/product.ts
@@ -23,7 +23,8 @@ export interface ProductResponse {
}
export const useProductStore = defineStore('product', () => {
- const productDescription = ref()
+ const productDescription = ref(null)
+ const defaultProductDescription = ref(null)
const currentProduct = ref(null)
const loading = ref(false)
const error = ref(null)
@@ -36,9 +37,7 @@ export const useProductStore = defineStore('product', () => {
const response = await useFetchJson(
`/api/v1/restricted/product-translation/get-product-description?productID=${productID}&productLangID=${langId}`
)
- console.log(response, 'dfsfsdf');
productDescription.value = response.items
-
} catch (e: unknown) {
error.value = e instanceof Error ? e.message : 'Failed to load product description'
} finally {
@@ -46,21 +45,31 @@ export const useProductStore = defineStore('product', () => {
}
}
- async function saveProductDescription(productID?: number) {
+ async function getDefaultProductDescription(langId: number, productID: number) {
+ try {
+ const response = await useFetchJson(
+ `/api/v1/restricted/product-translation/get-product-description?productID=${productID}&productLangID=${langId}`
+ )
+ defaultProductDescription.value = response.items
+ } catch (e: unknown) {
+ console.error('Failed to load default product description:', e)
+ }
+ }
+
+ async function saveProductDescription(productID?: number, langId?: number, shopId = 1) {
const id = productID || 1
try {
const data = await useFetchJson(
- `/api/v1/restricted/product-description/save-product-description?productID=${id}&productShopID=1&productLangID=1`,
+ `/api/v1/restricted/product-description/save-product-description?productID=${id}&productShopID=${shopId}&productLangID=${langId ?? 1}`,
{
method: 'POST',
- body: JSON.stringify(
- {
- description: productDescription.value.description,
- description_short: productDescription.value.description_short,
- meta_description: productDescription.value.meta_description,
- available_now: productDescription.value.available_now,
- usage: productDescription.value.usage
- })
+ body: JSON.stringify({
+ description: productDescription.value?.description,
+ description_short: productDescription.value?.description_short,
+ meta_description: productDescription.value?.meta_description,
+ available_now: productDescription.value?.available_now,
+ usage: productDescription.value?.usage
+ })
}
)
return data
@@ -91,10 +100,12 @@ export const useProductStore = defineStore('product', () => {
return {
productDescription,
+ defaultProductDescription,
currentProduct,
loading,
error,
getProductDescription,
+ getDefaultProductDescription,
clearCurrentProduct,
saveProductDescription,
translateProductDescription,
diff --git a/bo/src/stores/settings.ts b/bo/src/stores/settings.ts
index da907cb..5fff967 100644
--- a/bo/src/stores/settings.ts
+++ b/bo/src/stores/settings.ts
@@ -2,13 +2,19 @@ import { useFetchJson } from '@/composable/useFetchJson'
import type { Resp } from '@/types'
import type { Settings } from '@/types/settings'
import { defineStore } from 'pinia'
+import { ref } from 'vue'
export const useSettingsStore = defineStore('settings', () => {
- async function getSettings() {
- const { items } = await useFetchJson>('/api/v1/settings',)
- console.log(items);
+ const settings = ref(null)
+ const loaded = ref(false)
+
+ async function getSettings(): Promise {
+ if (loaded.value && settings.value) return settings.value
+ const resp = await useFetchJson('/api/v1/settings')
+ settings.value = resp.items
+ loaded.value = true
+ return resp.items
}
- getSettings()
- return {}
+ return { settings, loaded, getSettings }
})
diff --git a/bo/src/types/product.d.ts b/bo/src/types/product.d.ts
index 80d2e85..bfc9787 100644
--- a/bo/src/types/product.d.ts
+++ b/bo/src/types/product.d.ts
@@ -5,5 +5,6 @@
description_short: string
meta_description: string
available_now: string
+ delivery_in_stock?: string
usage: string
}
\ No newline at end of file
diff --git a/bo/src/types/settings.d.ts b/bo/src/types/settings.d.ts
index 79069a2..4466473 100644
--- a/bo/src/types/settings.d.ts
+++ b/bo/src/types/settings.d.ts
@@ -12,6 +12,7 @@ export interface App {
environment: string
base_url: string
password_regex: string
+ shop_default_language: number
}
export interface Server {