Catalog view #87

Merged
jsegarra merged 14 commits from wbuezas/hedera-web-mindshore:feature/Catalog into 4922-vueMigration 2024-10-01 19:27:15 +00:00
7 changed files with 205 additions and 145 deletions
Showing only changes of commit ff0d2db8fe - Show all commits

View File

@ -104,6 +104,7 @@ export default {
password: 'Contrasenya', password: 'Contrasenya',
modify: 'Modificar', modify: 'Modificar',
shoppingCart: 'Cistella de la compra', shoppingCart: 'Cistella de la compra',
available: 'Disponible',
// Image related translations // Image related translations
'Cant lock cache': 'No es pot bloquejar la memòria cau', 'Cant lock cache': 'No es pot bloquejar la memòria cau',
'Bad file format': 'Format de fitxer no reconegut', 'Bad file format': 'Format de fitxer no reconegut',

View File

@ -137,6 +137,7 @@ export default {
password: 'Password', password: 'Password',
modify: 'Modify', modify: 'Modify',
shoppingCart: 'Shopping cart', shoppingCart: 'Shopping cart',
available: 'Available',
// Image related translations // Image related translations
'Cant lock cache': 'The cache could not be blocked', 'Cant lock cache': 'The cache could not be blocked',
'Bad file format': 'Unrecognized file format', 'Bad file format': 'Unrecognized file format',

View File

@ -136,6 +136,7 @@ export default {
of: 'de', of: 'de',
modify: 'Modificar', modify: 'Modificar',
shoppingCart: 'Cesta de la compra', shoppingCart: 'Cesta de la compra',
available: 'Disponible',
// Image related translations // Image related translations
'Cant lock cache': 'La caché no pudo ser bloqueada', 'Cant lock cache': 'La caché no pudo ser bloqueada',
'Bad file format': 'Formato de archivo no reconocido', 'Bad file format': 'Formato de archivo no reconocido',

View File

@ -104,6 +104,7 @@ export default {
password: 'Mot de passe', password: 'Mot de passe',
modify: 'Modifier', modify: 'Modifier',
shoppingCart: 'Panier', shoppingCart: 'Panier',
available: 'Disponible',
// Image related translations // Image related translations
'Cant lock cache': "Le cache n'a pas pu être verrouillé", 'Cant lock cache': "Le cache n'a pas pu être verrouillé",
'Bad file format': 'Format de fichier non reconnu', 'Bad file format': 'Format de fichier non reconnu',

View File

@ -102,6 +102,7 @@ export default {
password: 'Senha', password: 'Senha',
modify: 'Modificar', modify: 'Modificar',
shoppingCart: 'Cesta da compra', shoppingCart: 'Cesta da compra',
available: 'Disponível',
// Image related translations // Image related translations
'Cant lock cache': 'O cache não pôde ser bloqueado', 'Cant lock cache': 'O cache não pôde ser bloqueado',
'Bad file format': 'Formato de arquivo inválido', 'Bad file format': 'Formato de arquivo inválido',

View File

@ -0,0 +1,129 @@
<script setup>
import { onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import VnImg from 'src/components/ui/VnImg.vue';
import { currency } from 'src/lib/filters.js';
defineProps({
item: { type: Object, default: () => {} }
});
const { t } = useI18n();
onMounted(async () => {});
</script>
<template>
<QCard v-ripple class="catalog-card">
<div style="height: 210px">
<VnImg
storage="catalog"
size="200x200"
:id="item.image"
width="80px"
height="80px"
rounded="bottom"
class="full-height full-width"
/>
</div>
<div class="column" style="height: 205px; padding: 10px">
<div class="column" style="margin-bottom: auto">
<div class="text-subtitle2">
{{ item.item }}
</div>
<div
class="row justify-between sub-name text-uppercase text-subtitle1 text-grey-7"
>
<span class="text-subtitle2">
{{ item.subName }}
</span>

Echo en falta el carro en rojo que representa la cantidad mínima
x1, representa el empaquetado mínimo. Esta traducción no está presente en el componente vue

Echo en falta el carro en rojo que representa la cantidad mínima x1, representa el empaquetado mínimo. Esta traducción no está presente en el componente vue

minQuantity handleado.

Commit: 0f5014088d

minQuantity handleado. Commit: https://gitea.verdnatura.es/verdnatura/hedera-web/commit/0f5014088d670c3e5cdbf63913672f14c6c3a4bf
<span> #{{ item.id }}</span>
</div>
<div class="tags q-pt-xs text-caption">
<div class="full-width row">
<span class="text-grey-7 col">
{{ item.tag5 }}
</span>
<span class="col">{{ item.value5 }}</span>
</div>
<div class="full-width row">
<span class="text-grey-7 col">
{{ item.tag6 }}
</span>
<span class="col">{{ item.value6 }}</span>
</div>
<div class="full-width row">
<span class="text-grey-7 col">
{{ item.tag7 }}
</span>
<span class="col">{{ item.value7 }}</span>
</div>
<div class="full-width row">
<span class="text-grey-7 col">
{{ item.tag8 }}
</span>
<span class="col">{{ item.value8 }}</span>
</div>
</div>
</div>
<div class="row justify-between items-cente q-gutter-x-xs">
<QBadge
:label="`x${item.grouping}`"
color="grey"
class="col-2 justify-end text-body2"
>
<QTooltip>
{{ t('minGrouping') }}
</QTooltip>
</QBadge>
<QBadge
outline
:label="item.available"
color="accent"
text-color="black"
class="col justify-end text-body2"
>
<QTooltip>
{{ t('available') }}
</QTooltip>
</QBadge>
<QBadge
outline
:label="currency(item.price)"
color="accent"
text-color="black"
class="col justify-end text-body2"
>
<QTooltip>
{{ t('groupingPrice') }}
</QTooltip>
</QBadge>
</div>
</div>
</QCard>
</template>
<style lang="scss" scoped>
.catalog-card {
display: flex;
flex-direction: column;
width: 210px;
overflow: hidden;
cursor: pointer;
}
</style>
<i18n lang="yaml">
en-US:
groupingPrice: Price per group
es-ES:
groupingPrice: Precio por grupo
ca-ES:
groupingPrice: Preu per grup
fr-FR:
groupingPrice: Prix par groupe
pt-PT:
groupingPrice: Preço por grupo
</i18n>

View File

@ -222,110 +222,20 @@
:thickness="2" :thickness="2"
/> />
<div <div
v-else-if="!items || !items.length || !type" v-else-if="!items || !items.length || !isSomeFilterSelected"
class="text-subtitle1 text-grey-7 q-pa-md" class="text-subtitle1 text-grey-7 q-pa-md"
> >
<QIcon name="refresh" size="sm" class="q-mr-sm"></QIcon> <QIcon name="refresh" size="sm" class="q-mr-sm"></QIcon>
<span>{{ t('pleaseSetFilter') }}</span> <span>{{ t('pleaseSetFilter') }}</span>
</div> </div>
<CatalogCard
<QCard
v-else v-else
v-for="_item in items" v-for="_item in items"
:key="_item.id" :key="_item.id"
v-ripple :item="_item"
class="my-card"
@click="showItem(_item)" @click="showItem(_item)"
>
<div style="height: 210px">
<VnImg
storage="catalog"
size="200x200"
:id="_item.image"
width="80px"
height="80px"
rounded="bottom"
class="full-height full-width"
/> />
</div> </div>
<div class="column" style="height: 205px; padding: 10px">
<div class="column" style="margin-bottom: auto">
<div class="text-subtitle2">
{{ _item.item }}
</div>
<div
class="row justify-between sub-name text-uppercase text-subtitle1 text-grey-7"
>
<span class="text-subtitle2">
{{ _item.subName }}
</span>
<span> #{{ _item.id }}</span>
</div>
<div class="tags q-pt-xs text-caption">
<div class="full-width row">
<span class="text-grey-7 col">
{{ _item.tag5 }}
</span>
<span class="col">{{ _item.value5 }}</span>
</div>
<div class="full-width row">
<span class="text-grey-7 col">
{{ _item.tag6 }}
</span>
<span class="col">{{ _item.value6 }}</span>
</div>
<div class="full-width row">
<span class="text-grey-7 col">
{{ _item.tag7 }}
</span>
<span class="col">{{ _item.value7 }}</span>
</div>
<div class="full-width row">
<span class="text-grey-7 col">
{{ _item.tag8 }}
</span>
<span class="col">{{ _item.value8 }}</span>
</div>
</div>
</div>
<div
class="row justify-between items-cente q-gutter-x-xs"
>
<QBadge
:label="`x${_item.grouping}`"
color="grey"
class="col-2 justify-end text-body2"
>
<QTooltip>
{{ t('minGrouping') }}
</QTooltip>
</QBadge>
<QBadge
outline
:label="_item.available"
color="accent"
text-color="black"
class="col justify-end text-body2"
>
<QTooltip>
{{ t('available') }}
</QTooltip>
</QBadge>
<QBadge
outline
:label="currency(_item.price)"
color="accent"
text-color="black"
class="col justify-end text-body2"
>
<QTooltip>
{{ t('groupingPrice') }}
</QTooltip>
</QBadge>
</div>
</div>
</QCard>
</div>
</QInfiniteScroll> </QInfiniteScroll>
<QDialog v-model="showItemDialog"> <QDialog v-model="showItemDialog">
<QCard style="width: 25em" class="column"> <QCard style="width: 25em" class="column">
@ -417,11 +327,12 @@
<script setup> <script setup>
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { inject, onMounted, onBeforeMount, ref, computed } from 'vue'; import { inject, onBeforeMount, ref, computed } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import VnImg from 'src/components/ui/VnImg.vue'; import VnImg from 'src/components/ui/VnImg.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import CatalogCard from 'src/pages/Ecomerce/CatalogCard.vue';
import { useAppStore } from 'stores/app'; import { useAppStore } from 'stores/app';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@ -511,7 +422,8 @@ const selectedCategory = computed({
async set(value) { async set(value) {
category.value = value; category.value = value;
router.push({ params: { category: category.value, type: null } }); router.push({ params: { category: category.value, type: null } });
console.log('category', category.value); onCategoryChange();
refreshTitle();
if (!value) return; if (!value) return;
getFilters(); getFilters();
getItems(); getItems();
@ -525,9 +437,10 @@ const selectedType = computed({
set(value) { set(value) {
type.value = value; type.value = value;
router.push({ params: { category: category.value, type: type.value } }); router.push({ params: { category: category.value, type: type.value } });
console.log('type', type.value); if (!selectedCategory.value) return;
getFilters(); getFilters();
getItems(); getItems();
refreshTitle();
} }
}); });
@ -537,6 +450,7 @@ const selectedColor = computed({
}, },
set(value) { set(value) {
color.value = value; color.value = value;
if (!selectedCategory.value) return;
getFilters(); getFilters();
getItems(); getItems();
} }
@ -548,7 +462,7 @@ const selectedProducer = computed({
}, },
set(value) { set(value) {
producer.value = value; producer.value = value;
if (!value) return; if (!value || !selectedCategory.value) return;
getFilters(); getFilters();
getItems(); getItems();
} }
@ -560,7 +474,7 @@ const selectedOrigin = computed({
}, },
set(value) { set(value) {
origin.value = value; origin.value = value;
if (!value) return; if (!value || !selectedCategory.value) return;
getFilters(); getFilters();
getItems(); getItems();
} }
@ -572,7 +486,7 @@ const selectedSubcategory = computed({
}, },
set(value) { set(value) {
subcategory.value = value; subcategory.value = value;
if (!value) return; if (!value && !selectedCategory.value) return;
getFilters(); getFilters();
getItems(); getItems();
} }
@ -593,20 +507,29 @@ const selectedOrderBy = computed({
}); });
const queryFilter = computed(() => { const queryFilter = computed(() => {
let filter = ''; const filters = [];
// Filtro principal
if (selectedCategory.value) { if (selectedCategory.value) {
filter = `(t.categoryFk = ${selectedCategory.value})`; filters.push(`t.categoryFk = ${selectedCategory.value}`);
}
if (selectedType.value) {
if (filter) filter += ' AND ';
filter += `(i.typeFk = ${selectedType.value})`;
}
if (selectedColor.value) {
if (filter) filter += ' AND ';
filter += `(i.inkFk = '${selectedColor?.value}')`;
} }
return filter; const otherFilters = {
'i.typeFk': selectedType.value,
'i.inkFk': selectedColor?.value ? `'${selectedColor.value}'` : null,
'i.producerFk': selectedProducer.value,
'i.originFk': selectedOrigin.value
};
// Añadir solo aquellos filtros que tengan valor
Object.entries(otherFilters).forEach(([key, value]) => {
if (value) {
filters.push(`${key} = ${value}`);
}
});
// Concatenar todos los filtros
return filters.join(' AND ');
}); });
const isSomeFilterSelected = computed(() => { const isSomeFilterSelected = computed(() => {
@ -629,7 +552,6 @@ const getOrder = async () => {
{ orderId: basketOrderId.value } { orderId: basketOrderId.value }
); );
order.value = data; order.value = data;
console.log('order', order.value);
} catch (error) { } catch (error) {
console.error('Error getting order:', error); console.error('Error getting order:', error);
} }
@ -700,12 +622,7 @@ const getItemColors = async () => {
const getItems = async () => { const getItems = async () => {
try { try {
loading.value = true; loading.value = true;
if ( if (!selectedCategory.value || !basketOrderId.value) return;
!selectedCategory.value ||
!basketOrderId.value ||
!selectedType.value
)
return;
const res = await jApi.execQuery( const res = await jApi.execQuery(
`DROP TEMPORARY TABLE IF EXISTS tmp.item; `DROP TEMPORARY TABLE IF EXISTS tmp.item;
@ -762,7 +679,6 @@ const getProducers = async () => {
{ orderId: basketOrderId.value } { orderId: basketOrderId.value }
); );
itemProducers.value = res.results[1].data; itemProducers.value = res.results[1].data;
console.log('Producers:', itemProducers.value);
} catch (error) { } catch (error) {
console.error('Error getting productors:', error); console.error('Error getting productors:', error);
} }
@ -784,7 +700,6 @@ const getOrigins = async () => {
{ orderId: basketOrderId.value } { orderId: basketOrderId.value }
); );
itemOrigins.value = res.results[1].data; itemOrigins.value = res.results[1].data;
console.log('Producers:', itemOrigins.value);
} catch (error) { } catch (error) {
console.error('Error getting productors:', error); console.error('Error getting productors:', error);
} }
@ -834,6 +749,10 @@ const showItem = async item => {
const removeCategory = () => { const removeCategory = () => {
selectedCategory.value = null; selectedCategory.value = null;
onCategoryChange();
};
const onCategoryChange = () => {
selectedType.value = null; selectedType.value = null;
selectedColor.value = null; selectedColor.value = null;
selectedProducer.value = null; selectedProducer.value = null;
@ -963,7 +882,34 @@ const onConfirmClick = async params => {
} }
}; };
// const refreshTitle = () => {}; const refreshTitle = () => {
const { meta } = route;
let title = t(meta.title);
let subtitle;
if (selectedCategory.value) {
const _category = categories.value.find(
i => i.id === selectedCategory.value
);
if (_category) {
title = _category.name;
if (selectedType.value) {
const _type = itemFamilies.value.find(
i => i.id === selectedType.value
);
if (_type) {
subtitle = title;
title = _type.name;
}
}
}
}
appStore.$patch({ title, subtitle });
};
onBeforeMount(async () => { onBeforeMount(async () => {
if (!isGuest.value) { if (!isGuest.value) {
@ -975,13 +921,11 @@ onBeforeMount(async () => {
// resultSet.fetchResult(); // resultSet.fetchResult();
// this.orderId = resultSet.fetchValue(); // this.orderId = resultSet.fetchValue();
} }
getOrder(); await getOrder();
getCategories(); await getCategories();
});
onMounted(async () => { if (route.params.category) selectedCategory.value = route.params.category;
selectedCategory.value = route.params.category; if (route.params.type) selectedType.value = route.params.type;
selectedType.value = route.params.type;
}); });
</script> </script>
@ -1015,14 +959,6 @@ onMounted(async () => {
} }
} }
} }
.my-card {
display: flex;
flex-direction: column;
width: 210px;
overflow: hidden;
cursor: pointer;
}
</style> </style>
<i18n lang="yaml"> <i18n lang="yaml">
@ -1041,9 +977,7 @@ en-US:
higherSize: Higher size higherSize: Higher size
lowerPrice: Lower price lowerPrice: Lower price
higherPrice: Higher price higherPrice: Higher price
available: Available
minGrouping: Minimum packing minGrouping: Minimum packing
groupingPrice: Price per group
add: Add add: Add
added: Added added: Added
es-ES: es-ES:
@ -1068,9 +1002,7 @@ es-ES:
higherSize: Medida más grande higherSize: Medida más grande
lowerPrice: Precio más bajo lowerPrice: Precio más bajo
higherPrice: Precio más alto higherPrice: Precio más alto
available: Disponible
minGrouping: Cantidad mínima minGrouping: Cantidad mínima
groupingPrice: Precio por grupo
add: Añadir add: Añadir
added: Añadido added: Añadido
ca-ES: ca-ES:
@ -1088,9 +1020,7 @@ ca-ES:
higherSize: Mida més gran higherSize: Mida més gran
lowerPrice: Preu més baix lowerPrice: Preu més baix
higherPrice: Preu més alt higherPrice: Preu més alt
available: Disponible
minGrouping: Empaquetament mínim minGrouping: Empaquetament mínim
groupingPrice: Preu per grup
add: Afegir add: Afegir
fr-FR: fr-FR:
category: Catégorie category: Catégorie
@ -1107,9 +1037,7 @@ fr-FR:
higherSize: Taille le plus élevé higherSize: Taille le plus élevé
lowerPrice: Prix le plus bas lowerPrice: Prix le plus bas
higherPrice: Prix le plus élevé higherPrice: Prix le plus élevé
available: Disponible
minGrouping: Emballage minimum minGrouping: Emballage minimum
groupingPrice: Prix par groupe
add: Ajouter add: Ajouter
pt-PT: pt-PT:
category: Categoria category: Categoria
@ -1126,8 +1054,6 @@ pt-PT:
higherSize: Tamanho maior higherSize: Tamanho maior
lowerPrice: Preço mais baixo lowerPrice: Preço mais baixo
higherPrice: Preço mais alto higherPrice: Preço mais alto
available: Disponível
minGrouping: Embalagem mínima minGrouping: Embalagem mínima
groupingPrice: Preço por grupo
add: Adicionar add: Adicionar
</i18n> </i18n>