fix: styles and translations.

This commit is contained in:
2026-03-16 16:28:41 +01:00
parent 0da596826e
commit e30088209e
4 changed files with 835 additions and 105 deletions

View File

@@ -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
}
})

View File

@@ -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>

View File

@@ -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">