Refactor FilterPosts

- extract FilterPostsMenuItems to its own component
- update tests accordingly
- add _.chunk from lodash to dry out code
This commit is contained in:
Matt Rider 2019-07-10 17:10:01 -03:00
parent 0113751003
commit 6536574a3b
3 changed files with 252 additions and 224 deletions

View File

@ -1,12 +1,16 @@
import { mount, createLocalVue } from '@vue/test-utils'
import FilterPosts from './FilterPosts.vue'
import Styleguide from '@human-connection/styleguide'
import VTooltip from 'v-tooltip'
import Styleguide from '@human-connection/styleguide'
import Vuex from 'vuex'
import FilterPosts from './FilterPosts.vue'
import FilterPostsMenuItem from './FilterPostsMenuItems.vue'
import { mutations } from '~/store/posts'
const localVue = createLocalVue()
localVue.use(Styleguide)
localVue.use(VTooltip)
localVue.use(Vuex)
describe('FilterPosts.vue', () => {
let wrapper
@ -23,7 +27,9 @@ describe('FilterPosts.vue', () => {
$apollo: {
query: jest
.fn()
.mockResolvedValueOnce()
.mockResolvedValueOnce({
data: { Post: { title: 'Post with Category', category: [{ id: 'cat4' }] } },
})
.mockRejectedValue({ message: 'We were unable to filter' }),
},
$t: jest.fn(),
@ -44,8 +50,13 @@ describe('FilterPosts.vue', () => {
})
describe('mount', () => {
const store = new Vuex.Store({
mutations: {
'posts/SET_POSTS': mutations.SET_POSTS,
},
})
const Wrapper = () => {
return mount(FilterPosts, { mocks, localVue, propsData })
return mount(FilterPosts, { mocks, localVue, propsData, store })
}
beforeEach(() => {
@ -72,7 +83,8 @@ describe('FilterPosts.vue', () => {
it('adds a categories id to selectedCategoryIds when clicked', () => {
environmentAndNatureButton = wrapper.findAll('button').at(1)
environmentAndNatureButton.trigger('click')
expect(wrapper.vm.selectedCategoryIds).toEqual(['cat4'])
const filterPostsMenuItem = wrapper.find(FilterPostsMenuItem)
expect(filterPostsMenuItem.vm.selectedCategoryIds).toEqual(['cat4'])
})
it('sets primary to true when the button is clicked', () => {
@ -110,5 +122,13 @@ describe('FilterPosts.vue', () => {
}),
)
})
it('toggles the categoryIds when clicked more than once', () => {
environmentAndNatureButton = wrapper.findAll('button').at(1)
environmentAndNatureButton.trigger('click')
environmentAndNatureButton.trigger('click')
const filterPostsMenuItem = wrapper.find(FilterPostsMenuItem)
expect(filterPostsMenuItem.vm.selectedCategoryIds).toEqual([])
})
})
})

View File

@ -5,203 +5,21 @@
<ds-icon style="margin-left: 2px" size="xx-small" name="angle-down" />
</a>
<template slot="popover">
<ds-container>
<ds-space />
<ds-flex :groupedCategories="chunk">
<ds-flex-item
:width="{ base: '100%', sm: '100%', md: '100%', lg: '20%' }"
class="categories-list"
>
<ds-space margin-bottom="x-small" />
<ds-flex id="filter-posts-header">
<ds-heading tag="h4">{{ $t('filter-posts.header') }}</ds-heading>
<ds-flex-item width="10%" />
<ds-flex-item width="100%">
<ds-button
icon="check"
@click.stop.prevent="toggleCategory()"
:primary="allCategories"
/>
<ds-flex-item>
<label>{{ $t('filter-posts.all') }}</label>
</ds-flex-item>
<ds-space />
</ds-flex-item>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[0]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[1]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex class="categories-list">
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[2]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[3]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[4]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[5]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[6]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[7]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
</ds-flex>
</ds-container>
<filter-posts-menu-items :chunk="chunk" @filterPosts="filterPosts" />
</template>
</dropdown>
</template>
<script>
import _ from 'lodash'
import Dropdown from '~/components/Dropdown'
import { filterPosts } from '~/graphql/PostQuery.js'
import { mapMutations } from 'vuex'
import FilterPostsMenuItems from '~/components/FilterPosts/FilterPostsMenuItems'
export default {
components: {
Dropdown,
FilterPostsMenuItems,
},
props: {
placement: { type: String, default: 'bottom-start' },
@ -211,22 +29,11 @@ export default {
data() {
return {
pageSize: 12,
selectedCategoryIds: [],
allCategories: true,
}
},
computed: {
chunk() {
const groupedCategories = []
for (let i = 0; i < this.categories.length; i++) {
const last = groupedCategories[groupedCategories.length - 1]
if (!last || last.length === 2) {
groupedCategories.push([this.categories[i]])
} else {
last.push(this.categories[i])
}
}
return groupedCategories
return _.chunk(this.categories, 2)
},
},
methods: {
@ -234,10 +41,7 @@ export default {
setPosts: 'posts/SET_POSTS',
}),
filterPosts(categoryIds) {
const filter = categoryIds.length
? { categories_some: { id_in: this.selectedCategoryIds } }
: {}
filter.categories_some ? (this.allCategories = false) : (this.allCategories = true)
const filter = categoryIds.length ? { categories_some: { id_in: categoryIds } } : {}
this.$apollo
.query({
query: filterPosts(this.$i18n),
@ -252,23 +56,6 @@ export default {
})
.catch(error => this.$toast.error(error.message))
},
isActive(id) {
const index = this.selectedCategoryIds.indexOf(id)
if (index > -1) {
return true
}
return false
},
toggleCategory(id) {
const index = this.selectedCategoryIds.indexOf(id)
if (index > -1) {
this.selectedCategoryIds.splice(index, 1)
} else {
this.selectedCategoryIds.push(id)
}
if (!id) this.selectedCategoryIds = []
this.filterPosts(this.selectedCategoryIds)
},
},
}
</script>

View File

@ -0,0 +1,221 @@
<template>
<ds-container>
<ds-space />
<ds-flex>
<ds-flex-item
:width="{ base: '100%', sm: '100%', md: '100%', lg: '20%' }"
class="categories-list"
>
<ds-space margin-bottom="x-small" />
<ds-flex id="filter-posts-header">
<ds-heading tag="h4">{{ $t('filter-posts.header') }}</ds-heading>
<ds-flex-item width="10%" />
<ds-flex-item width="100%">
<ds-button
icon="check"
@click.stop.prevent="toggleCategory()"
:primary="allCategories"
/>
<ds-flex-item>
<label>{{ $t('filter-posts.all') }}</label>
</ds-flex-item>
<ds-space />
</ds-flex-item>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[0]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[1]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex class="categories-list">
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[2]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[3]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[4]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[5]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[6]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
<ds-flex-item :width="{ base: '50%', sm: '0%', md: '50%', lg: '10%' }">
<ds-flex v-for="category in chunk[7]" :key="category.id" class="categories-list">
<ds-flex>
<ds-flex-item width="100%">
<ds-button
:icon="category.icon"
:primary="isActive(category.id)"
@click.stop.prevent="toggleCategory(category.id)"
/>
<ds-space margin-bottom="small" />
</ds-flex-item>
<ds-flex>
<ds-flex-item>
<label>{{ category.name }}</label>
</ds-flex-item>
<ds-space margin-bottom="xx-large" />
</ds-flex>
</ds-flex>
</ds-flex>
</ds-flex-item>
</ds-flex>
</ds-container>
</template>
<script>
export default {
props: {
chunk: { type: Array, default: () => [] },
},
data() {
return {
selectedCategoryIds: [],
allCategories: true,
}
},
methods: {
isActive(id) {
const index = this.selectedCategoryIds.indexOf(id)
if (index > -1) {
return true
}
return false
},
toggleCategory(id) {
const index = this.selectedCategoryIds.indexOf(id)
if (index > -1) {
this.selectedCategoryIds.splice(index, 1)
} else {
this.selectedCategoryIds.push(id)
}
if (!id) this.selectedCategoryIds = []
this.selectedCategoryIds.length ? (this.allCategories = false) : (this.allCategories = true)
this.$emit('filterPosts', this.selectedCategoryIds)
},
},
}
</script>