Skip to content

Instantly share code, notes, and snippets.

@stephan-v
Last active July 7, 2017 13:59
Show Gist options
  • Save stephan-v/58cd37042b3c20ff4af0e21e0fbdf92e to your computer and use it in GitHub Desktop.
Save stephan-v/58cd37042b3c20ff4af0e21e0fbdf92e to your computer and use it in GitHub Desktop.
Search filter component.
<template>
<div class="filter">
<h4>{{ title }}</h4>
<div class="checkbox" v-for="(value, key) in range">
<label>
<input type="checkbox" :value="key" v-model.number="items">
<span class="value">{{ value }}</span>
<span class="background"></span>
<div class="spinner" v-if="loading"></div>
<div class="hotel-count" v-else>
<span class="hotels" v-if="!active(Number(key)) && !activeStars">{{ count(Number(key)) }}</span>
<span class="remove" v-if="active(Number(key))">
<svg-inline name="delete"></svg-inline>
</span>
</div>
</label>
</div><!-- /.checkbox -->
</div><!-- /.filter -->
</template>
<script>
import { mapGetters } from 'vuex';
import filter from 'lodash/filter';
import intersection from 'lodash/intersection';
import SvgInline from '../../svg/SvgInline.vue';
export default {
components: {
SvgInline
},
props: {
title: {
required: true,
type: String
},
range: {
required: true,
type: Object
},
type: {
required: true,
type: String
}
},
watch: {
items() {
const encodedData = encodeURIComponent(JSON.stringify(this.cookieObject));
this.setCookie('searchsettings', encodedData);
}
},
methods: {
setCookie(name, value) {
document.cookie = `${name}=${value}; path=/; domain=.${document.domain}`;
},
count(value) {
let hotels = this.allHotels;
if (hotels.length) {
// Merge the current iteration value with the selected store values.
const union = this.mergeFilters(this[this.type], value);
hotels = this.countFilter(hotels, union, value);
}
return hotels.length;
},
countFilter(hotels, union, value) {
if (this.type === 'stars') {
hotels = filter(hotels, hotel => value === hotel.ster);
if (this.reviews.length) {
hotels = this.reviewFilter(hotels, this.reviews);
}
if (this.facilities.length) {
hotels = this.facilityFilter(hotels, this.facilities);
}
}
if (this.type === 'reviews') {
hotels = this.reviewFilter(hotels, union);
if (this.stars.length) {
hotels = this.starFilter(hotels, this.stars);
}
if (this.facilities.length) {
hotels = this.facilityFilter(hotels, this.facilities);
}
}
if (this.type === 'facilities') {
hotels = this.facilityFilter(hotels, union);
if (this.stars.length) {
hotels = this.starFilter(hotels, this.stars);
}
if (this.reviews.length) {
hotels = this.reviewFilter(hotels, this.reviews);
}
}
return hotels;
},
starFilter(hotels, stars) {
return filter(hotels, hotel => stars.includes(hotel.ster));
},
reviewFilter(hotels, reviews) {
return filter(hotels, hotel => reviews.every(review => hotel.cra_average > review));
},
facilityFilter(hotels, facilities) {
return filter(
hotels,
hotel => intersection(facilities, hotel.facilities).length === facilities.length
);
},
mergeFilters(items, value) {
// Slice to create a shallow copy and break the v-model reference.
const union = items.slice(0);
if (!union.includes(value)) union.push(value);
return union;
},
active(key) {
return this.items.includes(key) && this[this.type].length;
}
},
computed: {
...mapGetters([
'allHotels',
'stars',
'facilities',
'reviews',
'loading',
'cookieObject'
]),
items: {
get() {
return this.$store.state.search[this.type];
},
set(value) {
this.$store.dispatch('filterHotels', { items: value, type: this.type });
}
}
}
};
</script>
<style lang="scss" scoped>
.hotel-count {
display: inline;
}
.disabled {
color: #afafaf;
}
input[type=checkbox]:checked {
z-index: 1;
~ .background {
background: #87B800;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
~ .value {
color: white;
position: relative;
z-index: 1;
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment