419 lines
10 KiB
Vue
419 lines
10 KiB
Vue
<template>
|
|
<div class="container mt-5">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<ProductFilter
|
|
:filters="filters"
|
|
:current-filters="currentFilters"
|
|
:prices="prices"
|
|
:geo="coordinates"
|
|
@apply-filters="updateData"
|
|
/>
|
|
</div>
|
|
<div v-if="loadingProducts" class="col-md-9 loading-spinner">
|
|
<BSpinner />
|
|
<span>Cargando productos...</span>
|
|
</div>
|
|
<div v-if="!loadingProducts" class="col-md-9">
|
|
<div class="carousel">
|
|
<h2 class="title">Últimos productos</h2>
|
|
<ItemsRow class="items" :type="`product`" :items="carouselProducts.results" />
|
|
</div>
|
|
<div v-if="hasFilterTags" class="applied-filters">
|
|
<h2 class="title">FILTROS APLICADOS</h2>
|
|
<div class="filter-buttons">
|
|
<button
|
|
v-if="appliedFilters.hasOwnProperty('shipping_cost')"
|
|
type="button"
|
|
class="btn-tag"
|
|
@click="removeFilter('shipping_cost')"
|
|
>
|
|
<span>Sin gastos de envío</span>
|
|
<img src="@/assets/img/latienda-close.svg" alt="" />
|
|
</button>
|
|
<button
|
|
v-if="appliedFilters.hasOwnProperty('discount')"
|
|
type="button"
|
|
class="btn-tag"
|
|
@click="removeFilter('discount')"
|
|
>
|
|
<span>Descuentos</span>
|
|
<img src="@/assets/img/latienda-close.svg" alt="" />
|
|
</button>
|
|
<div v-if="appliedFilters.hasOwnProperty('category')">
|
|
<button
|
|
v-for="(cat, key) in appliedFilters.category"
|
|
:key="key"
|
|
type="button"
|
|
class="btn-delete-all"
|
|
@click="removeCategory(cat)"
|
|
>
|
|
<span>{{ cat }}</span>
|
|
<img src="@/assets/img/latienda-close.svg" alt="" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="results">
|
|
<h2 class="title"></h2>
|
|
<p class="count">Hay {{ count }} productos</p>
|
|
</div>
|
|
<div v-if="products.length !== 0">
|
|
<div v-for="product in products" :key="product.id">
|
|
<ProductCard :key="product.key" :product="product" />
|
|
</div>
|
|
<BPagination
|
|
v-model="currentPage"
|
|
class="pagination"
|
|
:total-rows="count"
|
|
:per-page="perPage"
|
|
@change="handlePageChange"
|
|
/>
|
|
</div>
|
|
<div v-else class="no-results">
|
|
<p>
|
|
No hemos encontrado resultados para su búsqueda... pero puede buscar
|
|
otro o consultar estos productos.
|
|
</p>
|
|
<div v-for="product in defaultProducts" :key="product.id">
|
|
<ProductCard :key="product.key" :product="product" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- appliedFilters: {{appliedFilters}} <br>
|
|
filters: {{filters}} <br>
|
|
prices: {{prices}} <br>
|
|
coordinates: {{coordinates}} <br>
|
|
products: {{products}} <br>
|
|
defaultProducts: {{defaultProducts}} <br>
|
|
carouselProducts: {{carouselProducts}} <br>
|
|
count: {{count}} -->
|
|
</template>
|
|
|
|
<script>
|
|
import { useAuthStore } from '@/stores/auth'
|
|
import serverSearch from '~/utils/serverSearch'
|
|
import clientSearch from '~/utils/clientSearch'
|
|
|
|
export default {
|
|
setup(){
|
|
definePageMeta({
|
|
layout: 'mainbanner',
|
|
})
|
|
|
|
const auth = useAuthStore()
|
|
return { auth }
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
searchText: '',
|
|
currentPage: 1,
|
|
perPage: 10,
|
|
filterTags: {
|
|
shipping_cost: undefined,
|
|
},
|
|
previousParams: null,
|
|
currentFilters: null,
|
|
mountedProducts: [],
|
|
appliedFilters: {},
|
|
filters: {},
|
|
prices: { min: null, max: null },
|
|
coordinates: null,
|
|
products: [],
|
|
defaultProducts: [],
|
|
carouselProducts: [],
|
|
count: 0,
|
|
loadingProducts: true
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
hasFilterTags() {
|
|
if (!this.appliedFilters) return false
|
|
return (
|
|
Object.keys(this.appliedFilters).includes('shipping_cost') ||
|
|
Object.keys(this.appliedFilters).includes('discount') ||
|
|
(Array.isArray(this.appliedFilters.category) &&
|
|
this.appliedFilters.category.length > 0)
|
|
)
|
|
},
|
|
},
|
|
|
|
watch: {
|
|
$route() {
|
|
Object.assign(this.$data, this.$options.data())
|
|
},
|
|
},
|
|
|
|
async beforeCreate() {
|
|
const config = useRuntimeConfig()
|
|
const params = import.meta.client ? clientSearch(this.$route.query) : serverSearch(this.$route.query)
|
|
const data = await $fetch(`/search_products/?`, {
|
|
baseURL: config.public.baseURL,
|
|
method: 'GET',
|
|
params: params,
|
|
headers: {
|
|
Authorization: '/',
|
|
},
|
|
})
|
|
//console.log('data', data)
|
|
|
|
const products = data.products
|
|
//console.log('products', products)
|
|
let defaultProducts = []
|
|
if (products.length === 0) {
|
|
//console.log('no products, fetching default')
|
|
const data = await $fetch(`/search_products/?q=${params.q}`, {
|
|
baseURL: config.public.baseURL,
|
|
method: 'GET',
|
|
params: {
|
|
order: 'newest',
|
|
limit: 10,
|
|
offset: 0
|
|
},
|
|
headers: {
|
|
Authorization: '/',
|
|
},
|
|
})
|
|
defaultProducts = data.products
|
|
}
|
|
|
|
const carouselProducts = await $fetch(`/products/`, {
|
|
baseURL: config.public.baseURL,
|
|
method: 'GET',
|
|
params: {
|
|
limit: 10,
|
|
offset: 0
|
|
},
|
|
headers: {
|
|
Authorization: '/',
|
|
},
|
|
})
|
|
//console.log('carouselProducts', carouselProducts)
|
|
|
|
let coordinates
|
|
if (params.latitude && params.longitude) {
|
|
coordinates = {
|
|
lat: Number(params.latitude),
|
|
lng: Number(params.longitude),
|
|
}
|
|
}
|
|
|
|
let prices
|
|
if (params.price_min || params.price_max) {
|
|
prices = { max: params.price_max, min: params.price_min }
|
|
} else if (data.prices.min || data.prices.max) {
|
|
prices = data.prices
|
|
} else {
|
|
prices = { max: null, min: null }
|
|
}
|
|
|
|
this.appliedFilters = params.q
|
|
this.filters = data.filters
|
|
this.prices = prices
|
|
this.coordinates = coordinates
|
|
this.products = products
|
|
this.defaultProducts = defaultProducts
|
|
this.carouselProducts = carouselProducts
|
|
this.count = data.count
|
|
this.loadingProducts = false
|
|
},
|
|
|
|
|
|
mounted() {
|
|
this.currentFilters = this.appliedFilters
|
|
},
|
|
|
|
methods: {
|
|
async handlePageChange(value) {
|
|
const offset = (value - 1) * this.perPage
|
|
this.products = await this.getMoreProducts(offset)
|
|
},
|
|
|
|
async getMoreProducts(offset) {
|
|
const config = useRuntimeConfig()
|
|
const data = await $fetch(`/search_products/`, {
|
|
baseURL: config.public.baseURL,
|
|
method: 'GET',
|
|
params: {
|
|
...this.appliedFilters,
|
|
limit: 10,
|
|
offset: offset
|
|
},
|
|
headers: {
|
|
Authorization: '/',
|
|
},
|
|
})
|
|
return data.products
|
|
},
|
|
|
|
updateData(value) {
|
|
const filters = { q: this.appliedFilters.q }
|
|
|
|
if (Object.keys(value).length === 0) { //Review this condition
|
|
return this.$router.push({
|
|
name: 'busqueda',
|
|
query: { ...filters },
|
|
})
|
|
} else {
|
|
return this.$router.push({
|
|
name: 'busqueda',
|
|
query: { ...value, ...filters },
|
|
})
|
|
}
|
|
},
|
|
|
|
removeCategory(cat) {
|
|
this.currentFilters = this.appliedFilters
|
|
const categoryArray = this.currentFilters.category
|
|
const newCats = []
|
|
categoryArray.forEach((element) => {
|
|
if (element !== cat) {
|
|
newCats.push(element)
|
|
}
|
|
})
|
|
this.currentFilters.category = newCats
|
|
const noCategory = {}
|
|
Object.entries(this.currentFilters).forEach(([key, value]) => {
|
|
if (key !== 'category') {
|
|
noCategory[key] = value
|
|
}
|
|
})
|
|
if (newCats.length === 0) {
|
|
return this.$router.push({
|
|
path: this.$route.path,
|
|
query: { ...noCategory },
|
|
})
|
|
} else {
|
|
return this.$router.push({
|
|
path: this.$route.path,
|
|
query: { category: newCats, ...noCategory },
|
|
})
|
|
}
|
|
},
|
|
|
|
removeFilter(filter) {
|
|
this.currentFilters = { ...this.appliedFilters }
|
|
this.currentFilters = Object.fromEntries(
|
|
Object.entries(this.currentFilters).filter(([key]) => key !== filter)
|
|
)
|
|
|
|
return this.$router.push({
|
|
name: 'busqueda',
|
|
query: { ...this.currentFilters },
|
|
})
|
|
},
|
|
|
|
|
|
search() {
|
|
if (this.searchText) {
|
|
return this.$router.push({
|
|
name: 'busqueda',
|
|
query: { q: this.searchText },
|
|
})
|
|
}
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.ad {
|
|
margin: 40px auto;
|
|
width: 100%;
|
|
height: 100px;
|
|
background-color: $color-grey-nav;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
.applied-filters {
|
|
@include mobile {
|
|
display: none;
|
|
}
|
|
.title {
|
|
font-size: $xl;
|
|
color: $color-navy;
|
|
}
|
|
}
|
|
|
|
.filter-buttons {
|
|
margin-bottom: 30px;
|
|
|
|
button {
|
|
margin-right: 5px;
|
|
margin-bottom: 5px;
|
|
border: none;
|
|
border-radius: 5px;
|
|
padding: 8px 10px;
|
|
color: $color-light;
|
|
background-color: $color-dark-green;
|
|
|
|
img {
|
|
width: 18px;
|
|
margin-left: 5px;
|
|
position: relative;
|
|
bottom: 1px;
|
|
}
|
|
}
|
|
|
|
.btn-delete-all {
|
|
background-color: $color-darker-green;
|
|
}
|
|
}
|
|
|
|
.carousel {
|
|
@include mobile {
|
|
display: none;
|
|
}
|
|
.title {
|
|
font-size: $xl;
|
|
color: $color-navy;
|
|
@include tablet {
|
|
margin-top: 3rem;
|
|
}
|
|
}
|
|
.items {
|
|
margin: auto;
|
|
}
|
|
}
|
|
.results {
|
|
.title {
|
|
font-size: $xl;
|
|
color: $color-navy;
|
|
}
|
|
.count {
|
|
font-size: $xs;
|
|
color: $color-greytext;
|
|
}
|
|
}
|
|
.pagination {
|
|
margin-top: 40px;
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.no-results {
|
|
p {
|
|
text-align: center;
|
|
font-size: $xl;
|
|
color: $color-navy;
|
|
margin-top: 100px;
|
|
margin-bottom: 100px;
|
|
}
|
|
}
|
|
|
|
.loading-spinner {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 15px;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100%;
|
|
}
|
|
</style>
|