Last active
July 7, 2017 13:59
-
-
Save stephan-v/58cd37042b3c20ff4af0e21e0fbdf92e to your computer and use it in GitHub Desktop.
Search filter component.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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