fix: styles and translations.
This commit is contained in:
@@ -27,13 +27,12 @@ export const useProductStore = defineStore('product', () => {
|
||||
const loading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
// Fetch all products
|
||||
async function getProductDescription() {
|
||||
async function getProductDescription(langId: number = 1) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await useFetchJson('/api/v1/restricted/product-description/get-product-description?productID=51&productShopID=1&productLangID=1')
|
||||
const response = await useFetchJson(`/api/v1/restricted/product-description/get-product-description?productID=51&productShopID=1&productLangID=${langId}`)
|
||||
productDescription.value = response
|
||||
} catch (e: any) {
|
||||
error.value = e?.message || 'Failed to load product description'
|
||||
@@ -43,60 +42,20 @@ export const useProductStore = defineStore('product', () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function getProductDescriptionTranslations() {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await useFetchJson('api/v1/restricted/product-description/translate-product-description?productID=51&productShopID=1&productFromLangID=1&productToLangID=2')
|
||||
productDescription.value = response
|
||||
} catch (e: any) {
|
||||
error.value = e?.message || 'Failed to load product description'
|
||||
console.error('Failed to fetch product description:', e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch single product by ID
|
||||
async function fetchProductById(id: number) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
currentProduct.value = null
|
||||
|
||||
try {
|
||||
const data = await useFetchJson<{ items: Product }>(`/api/v1/restricted/product-description?id=${id}`)
|
||||
|
||||
const response = (data as any).items || data
|
||||
currentProduct.value = response.items?.[0] || response
|
||||
} catch (e: any) {
|
||||
error.value = e?.message || 'Failed to load product'
|
||||
console.error('Failed to fetch product:', e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function saveProductDescription(description: string) {
|
||||
async function saveProductDescription() {
|
||||
try {
|
||||
const data = await useFetchJson(
|
||||
`/api/v1/restricted/product-description/save-product-description?productID=1&productShopID=1&productLangID=1`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
description: description,
|
||||
description_short: "<p>Test short</p>",
|
||||
meta_description: "This is a test",
|
||||
meta_title: "...",
|
||||
name: "...",
|
||||
available_now: "Test",
|
||||
available_later: "...",
|
||||
usage: "<p>test</p>"
|
||||
})
|
||||
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
|
||||
@@ -105,7 +64,22 @@ export const useProductStore = defineStore('product', () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Clear current product
|
||||
async function translateProductDescription(fromLangId: number, toLangId: number) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const response = await useFetchJson(`/api/v1/restricted/product-description/translate-product-description?productID=51&productShopID=1&productFromLangID=${fromLangId}&productToLangID=${toLangId}&model=OpenAI`)
|
||||
productDescription.value = response
|
||||
return response
|
||||
} catch (e: any) {
|
||||
error.value = e?.message || 'Failed to translate product description'
|
||||
console.error('Failed to translate product description:', e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function clearCurrentProduct() {
|
||||
currentProduct.value = null
|
||||
}
|
||||
@@ -116,9 +90,8 @@ export const useProductStore = defineStore('product', () => {
|
||||
loading,
|
||||
error,
|
||||
getProductDescription,
|
||||
fetchProductById,
|
||||
clearCurrentProduct,
|
||||
saveProductDescription,
|
||||
getProductDescriptionTranslations
|
||||
translateProductDescription
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,24 +1,45 @@
|
||||
<template>
|
||||
<div class="container my-10 ">
|
||||
|
||||
<UButton>Translations</UButton>
|
||||
<div class="flex items-end justify-between gap-4 mb-6 bg-(--second-light) dark:bg-(--main-dark) border border-(--border-light) dark:border-(--border-dark) p-4 rounded-md">
|
||||
<div class="flex items-end gap-3">
|
||||
<USelect v-model="selectedLanguage" :items="availableLangs" variant="outline" class="w-40!"
|
||||
valueKey="iso_code">
|
||||
<template #default="{ modelValue }">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-md">{{ availableLangs.find(x => x.iso_code == modelValue)?.flag }}</span>
|
||||
<span class="font-medium dark:text-white text-black">{{ availableLangs.find(x => x.iso_code == modelValue)?.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #item-leading="{ item }">
|
||||
<div class="flex items-center rounded-md cursor-pointer transition-colors">
|
||||
<span class="text-md">{{ item.flag }}</span>
|
||||
<span class="ml-2 dark:text-white text-black font-medium">{{ item.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</USelect>
|
||||
</div>
|
||||
<UButton @click="translateToSelectedLanguage" color="primary" :loading="translating" class="text-white bg-(--accent-blue-light) dark:bg-(--accent-blue-dark) px-12!">
|
||||
Translate
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div v-if="translating" class="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
|
||||
<div class="flex flex-col items-center gap-4 p-8 bg-(--main-light) dark:bg-(--main-dark) rounded-lg shadow-xl">
|
||||
<UIcon name="svg-spinners:ring-resize" class="text-4xl text-primary" />
|
||||
<p class="text-lg font-medium dark:text-white text-black">Translating...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-start gap-30">
|
||||
<div class="flex flex-col gap-10">
|
||||
<p class="p-60 bg-yellow-300">img</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="text-[25px] font-bold">{{ productStore.productDescription.name }}</p>
|
||||
<p v-html="productStore.productDescription.description_short"></p>
|
||||
<p class="text-[25px] font-bold dark:text-white text-black">{{ productStore.productDescription.name }}</p>
|
||||
<p v-html="productStore.productDescription.description_short" class="dark:text-white text-black"></p>
|
||||
|
||||
<div>
|
||||
<p>Ilość:</p>
|
||||
<div
|
||||
class="flex items-center w-[15%] border border-(--border-light) dark:border-(--border-dark) rounded bg-gray-200">
|
||||
<button @click="decrement" class="px-3 py-1 cursor-pointer">-</button>
|
||||
<span class="px-6">{{ quantity }}</span>
|
||||
<button @click="increment" class="px-3 py-1 cursor-pointer">+</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-[10px]">
|
||||
<div class="flex gap-1 items-center">
|
||||
@@ -28,58 +49,54 @@
|
||||
</div>
|
||||
<div class="flex gap-1 items-center">
|
||||
<UIcon name="marketeq:car-shipping" class="text-[25px] text-green-600" />
|
||||
<p class="text-[18px] font-bold">{{ productStore.productDescription.delivery_in_stock }}</p>
|
||||
<p class="text-[18px] font-bold dark:text-white text-black">{{ productStore.productDescription.delivery_in_stock }}</p>
|
||||
</div>
|
||||
<UButton class="cursor-pointer">
|
||||
<UIcon name="tdesign:cart-filled" class="text-[20px]" />
|
||||
<p> Dodaj do koszyka </p>
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-16">
|
||||
<div class="flex gap-4 m-2">
|
||||
<div class="flex gap-4 my-6">
|
||||
<UButton @click="activeTab = 'description'"
|
||||
:class="['cursor-pointer', activeTab === 'description' ? 'bg-blue-500 text-white' : '']" color="neutral"
|
||||
variant="outline">
|
||||
<p>Description</p>
|
||||
<p class="dark:text-white">Description</p>
|
||||
</UButton>
|
||||
|
||||
<UButton @click="activeTab = 'usage'"
|
||||
:class="['cursor-pointer', activeTab === 'usage' ? 'bg-blue-500 text-white' : '']" color="neutral"
|
||||
variant="outline">
|
||||
<p>Usage</p>
|
||||
<p class="dark:text-white">Usage</p>
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
<div v-if="activeTab === 'usage'">
|
||||
<div class="flex items-center gap-3 mb-3">
|
||||
<UButton @click="usageEdit.enableEdit()" class="flex items-center gap-2 m-2 cursor-pointer">
|
||||
<p>Create Text</p>
|
||||
<UIcon name="material-symbols-light:stylus-note-sharp" class="text-[30px]" />
|
||||
<div v-if="activeTab === 'usage'" class="px-8 py-4 border border-(--border-light) dark:border-(--border-dark) rounded-md bg-(--second-light) dark:bg-(--main-dark)">
|
||||
<div class="flex justify-end items-center gap-3 mb-4">
|
||||
<UButton @click="usageEdit.enableEdit()" class="flex items-center gap-2 m-2 cursor-pointer bg-(--accent-blue-light)! dark:bg-(--accent-blue-dark)!">
|
||||
<p class="text-white ">Change Text</p>
|
||||
<UIcon name="material-symbols-light:stylus-note-sharp" class="text-[30px] text-white!" />
|
||||
</UButton>
|
||||
<UButton @click="save" color="neutral" variant="outline" class="p-2.5 cursor-pointer">
|
||||
<p>Save the edited text</p>
|
||||
<p class="dark:text-white text-black ">Save the edited text</p>
|
||||
</UButton>
|
||||
</div>
|
||||
<p ref="usageRef" v-html="productStore.productDescription.usage"
|
||||
class="p-8 flex flex-col justify-center w-full text-start border border-(--border-light) dark:border-(--border-dark) rounded-md bg-(--second-light) dark:bg-(--main-dark) dark:text-white text-black">
|
||||
class="flex flex-col justify-center w-full text-start dark:text-white text-black">
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="activeTab === 'description'">
|
||||
<div class="flex items-center gap-3 mb-3">
|
||||
<UButton @click="descriptionEdit.enableEdit()" class="flex items-center gap-2 m-2 cursor-pointer">
|
||||
<p>Create Text</p>
|
||||
<UIcon name="material-symbols-light:stylus-note-sharp" class="text-[30px]" />
|
||||
<div v-if="activeTab === 'description'" class="px-8 py-4 border border-(--border-light) dark:border-(--border-dark) rounded-md bg-(--second-light) dark:bg-(--main-dark)">
|
||||
<div class="flex items-center justify-end gap-3 mb-4">
|
||||
<UButton @click="descriptionEdit.enableEdit()" class="flex items-center gap-2 m-2 cursor-pointer bg-(--accent-blue-light)! dark:bg-(--accent-blue-dark)!">
|
||||
<p class="text-white">Change Text</p>
|
||||
<UIcon name="material-symbols-light:stylus-note-sharp" class="text-[30px] text-white!" />
|
||||
</UButton>
|
||||
<UButton @click="save" color="neutral" variant="outline" class="p-2.5 cursor-pointer">
|
||||
<p>Save the edited text</p>
|
||||
<p class="dark:text-white text-black ">Save the edited text</p>
|
||||
</UButton>
|
||||
</div>
|
||||
<div ref="descriptionRef" v-html="productStore.productDescription.description"
|
||||
class="p-8 flex flex-col justify-center border border-(--border-light) dark:border-(--border-dark) rounded-md bg-(--second-light) dark:bg-(--main-dark) dark:text-white text-black">
|
||||
class="flex flex-col justify-center dark:text-white text-black">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,23 +104,48 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
import { useProductStore } from '@/stores/product'
|
||||
import { useEditable } from '@/composable/useConteditable'
|
||||
import { langs } from '@/router/langs'
|
||||
import type { Language } from '@/types'
|
||||
|
||||
const activeTab = ref('description')
|
||||
const productStore = useProductStore()
|
||||
await productStore.getProductDescription()
|
||||
await productStore.getProductDescriptionTranslations()
|
||||
const translating = ref(false)
|
||||
|
||||
const quantity = ref(1)
|
||||
// const availableLangs = computed(() => {
|
||||
// return langs.filter((l: Language) => ['cs', 'pl', 'der'].includes(l.iso_code))
|
||||
// })
|
||||
|
||||
const increment = () => {
|
||||
quantity.value += 1
|
||||
const availableLangs = computed(() => langs)
|
||||
|
||||
const selectedLanguage = ref('pl')
|
||||
|
||||
const currentLangId = ref(2)
|
||||
|
||||
const fetchForLanguage = async (langCode: string) => {
|
||||
const lang = langs.find((l: Language) => l.iso_code === langCode)
|
||||
if (lang) {
|
||||
await productStore.getProductDescription(lang.id)
|
||||
currentLangId.value = lang.id
|
||||
}
|
||||
}
|
||||
const decrement = () => {
|
||||
if (quantity.value > 1) quantity.value -= 1
|
||||
|
||||
const translateToSelectedLanguage = async () => {
|
||||
const targetLang = langs.find((l: Language) => l.iso_code === selectedLanguage.value)
|
||||
if (targetLang && currentLangId.value) {
|
||||
translating.value = true
|
||||
try {
|
||||
await productStore.translateProductDescription(currentLangId.value, targetLang.id)
|
||||
currentLangId.value = targetLang.id
|
||||
} finally {
|
||||
translating.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await fetchForLanguage(selectedLanguage.value)
|
||||
const descriptionRef = ref<HTMLElement | null>(null)
|
||||
const usageRef = ref<HTMLElement | null>(null)
|
||||
|
||||
@@ -111,15 +153,9 @@ const descriptionEdit = useEditable(descriptionRef)
|
||||
const usageEdit = useEditable(usageRef)
|
||||
|
||||
const save = async () => {
|
||||
const description = descriptionEdit.getCleanHtml()
|
||||
const usage = usageEdit.getCleanHtml()
|
||||
|
||||
descriptionEdit.disableEdit()
|
||||
usageEdit.disableEdit()
|
||||
// await productStore.saveProductDescription({
|
||||
// description,
|
||||
// usage
|
||||
// })
|
||||
await productStore.saveProductDescription()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -155,7 +155,9 @@ function clearFilters() {
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="p-6 bg-white dark:bg-(--black) min-h-screen font-sans">
|
||||
<div v-html="productStore.products"></div>
|
||||
<div >
|
||||
<!-- v-html="productStore.products" -->
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold mb-6 text-black dark:text-white">{{ t('products.title') }}</h1>
|
||||
|
||||
<div v-if="!authStore.isAuthenticated" class="mb-4 p-3 bg-yellow-100 text-yellow-700 rounded">
|
||||
|
||||
Reference in New Issue
Block a user