Implement or move sort by date filter in filter menu

This commit is contained in:
Wolfgang Huß 2021-04-12 15:09:28 +02:00
parent 90b9ffb917
commit 16d8a42d9b
8 changed files with 167 additions and 93 deletions

View File

@ -33,6 +33,7 @@ export default {
data() { data() {
return { return {
isPopoverOpen: false, isPopoverOpen: false,
developperNoAutoClosing: true, // Wolle // stops automatic closing of menu for developper purposes: default is 'false'
} }
}, },
computed: { computed: {
@ -113,6 +114,7 @@ export default {
} }
}, },
popoveMouseLeave() { popoveMouseLeave() {
if (this.developperNoAutoClosing) return
if (this.disabled) { if (this.disabled) {
return return
} }

View File

@ -0,0 +1,56 @@
<template>
<filter-menu-section :divider="false" class="date-sort-filter">
<template #filter-list>
<!-- Wolle 👇🏼 translations & click
<labeled-button
icon="user-plus"
:label="$t('filter-menu.following')"
:filled="filteredByUsersFollowed"
:title="$t('contribution.filterFollow')"
@click="toggleFilteredByFollowed(currentUser.id)"
/> -->
<li class="item">
<labeled-button
icon="sort-amount-asc"
:label="'Newest first'"
:filled="orderBy === 'createdAt_desc'"
:title="'Sort posts by the newest first'"
@click="toggleOrder('createdAt_desc')"
/>
</li>
<li class="item">
<labeled-button
icon="sort-amount-desc"
:label="'Oldest first'"
:filled="orderBy === 'createdAt_asc'"
:title="'Sort posts by the oldest first'"
@click="toggleOrder('createdAt_asc')"
/>
</li>
</template>
</filter-menu-section>
</template>
<script>
import { mapGetters, mapMutations } from 'vuex'
import FilterMenuSection from '~/components/FilterMenu/FilterMenuSection'
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
export default {
name: 'DateSortFilter',
components: {
FilterMenuSection,
LabeledButton,
},
computed: {
...mapGetters({
orderBy: 'posts/orderBy',
}),
},
methods: {
...mapMutations({
toggleOrder: 'posts/TOGGLE_ORDER',
}),
},
}
</script>

View File

@ -15,6 +15,10 @@
<h2 class="title">{{ $t('filter-menu.filter-by') }}</h2> <h2 class="title">{{ $t('filter-menu.filter-by') }}</h2>
<following-filter /> <following-filter />
</div> </div>
<div class="filter-menu-options">
<h2 class="title">{{ 'Sorted by …' }}</h2> <!-- Wolle -->
<date-sort-filter />
</div>
</template> </template>
</dropdown> </dropdown>
</template> </template>
@ -23,11 +27,13 @@
import Dropdown from '~/components/Dropdown' import Dropdown from '~/components/Dropdown'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import FollowingFilter from './FollowingFilter' import FollowingFilter from './FollowingFilter'
import DateSortFilter from './DateSortFilter'
export default { export default {
components: { components: {
Dropdown, Dropdown,
FollowingFilter, FollowingFilter,
DateSortFilter,
}, },
props: { props: {
placement: { type: String }, placement: { type: String },

View File

@ -38,7 +38,10 @@ export default {
} }
> .sidebar { > .sidebar {
flex-basis: 12%; display: flex;
flex-wrap: wrap;
flex-basis: 80%;
flex-grow: 1;
max-width: $size-width-filter-sidebar; max-width: $size-width-filter-sidebar;
} }
@ -55,21 +58,21 @@ export default {
flex-grow: 1; flex-grow: 1;
> .item { > .item {
width: 12.5%; width: 50%;
padding: 0 $space-x-small; padding: 0 $space-x-small;
margin-bottom: $space-small; margin-bottom: $space-small;
text-align: center; text-align: center;
@media only screen and (max-width: 800px) { @media only screen and (max-width: 800px) {
width: 16%; width: 50%;
} }
@media only screen and (max-width: 630px) { @media only screen and (max-width: 630px) {
width: 25%; width: 40%;
} }
@media only screen and (max-width: 440px) { @media only screen and (max-width: 440px) {
width: 50%; width: 30%;
} }
} }
} }

View File

@ -24,20 +24,21 @@ describe('PostIndex', () => {
store = new Vuex.Store({ store = new Vuex.Store({
getters: { getters: {
'posts/filter': () => ({}), 'posts/filter': () => ({}),
'posts/orderOptions': () => () => [ // Wolle
{ // 'posts/orderOptions': () => () => [
key: 'store.posts.orderBy.oldest.label', // {
label: 'store.posts.orderBy.oldest.label', // key: 'store.posts.orderBy.oldest.label',
icon: 'sort-amount-asc', // label: 'store.posts.orderBy.oldest.label',
value: 'createdAt_asc', // icon: 'sort-amount-asc',
}, // value: 'createdAt_asc',
{ // },
key: 'store.posts.orderBy.newest.label', // {
label: 'store.posts.orderBy.newest.label', // key: 'store.posts.orderBy.newest.label',
icon: 'sort-amount-desc', // label: 'store.posts.orderBy.newest.label',
value: 'createdAt_desc', // icon: 'sort-amount-desc',
}, // value: 'createdAt_desc',
], // },
// ],
'posts/selectedOrder': () => () => 'createdAt_desc', 'posts/selectedOrder': () => () => 'createdAt_desc',
'posts/orderIcon': () => 'sort-amount-desc', 'posts/orderIcon': () => 'sort-amount-desc',
'posts/orderBy': () => 'createdAt_desc', 'posts/orderBy': () => 'createdAt_desc',
@ -119,10 +120,10 @@ describe('PostIndex', () => {
}) })
}) })
it('calls store when using order by menu', () => { // Wolle it('calls store when using order by menu', () => {
wrapper.findAll('li').at(0).trigger('click') // wrapper.findAll('li').at(0).trigger('click')
expect(mutations['posts/SELECT_ORDER']).toHaveBeenCalledWith({}, 'createdAt_asc') // expect(mutations['posts/SELECT_ORDER']).toHaveBeenCalledWith({}, 'createdAt_asc')
}) // })
}) })
}) })
}) })

View File

@ -97,7 +97,8 @@ import HcEmpty from '~/components/Empty/Empty'
import PostTeaser from '~/components/PostTeaser/PostTeaser.vue' import PostTeaser from '~/components/PostTeaser/PostTeaser.vue'
import MasonryGrid from '~/components/MasonryGrid/MasonryGrid.vue' import MasonryGrid from '~/components/MasonryGrid/MasonryGrid.vue'
import MasonryGridItem from '~/components/MasonryGrid/MasonryGridItem.vue' import MasonryGridItem from '~/components/MasonryGrid/MasonryGridItem.vue'
import { mapGetters, mapMutations } from 'vuex' // Wolle import { mapGetters, mapMutations } from 'vuex'
import { mapGetters } from 'vuex'
import { filterPosts } from '~/graphql/PostQuery.js' import { filterPosts } from '~/graphql/PostQuery.js'
import UpdateQuery from '~/components/utils/UpdateQuery' import UpdateQuery from '~/components/utils/UpdateQuery'
import links from '~/constants/links.js' import links from '~/constants/links.js'
@ -129,24 +130,24 @@ export default {
computed: { computed: {
...mapGetters({ ...mapGetters({
postsFilter: 'posts/filter', postsFilter: 'posts/filter',
orderOptions: 'posts/orderOptions', // Wolle care for the store !!! orderOptions: 'posts/orderOptions',
orderBy: 'posts/orderBy', orderBy: 'posts/orderBy',
selectedOrder: 'posts/selectedOrder', // Wolle selectedOrder: 'posts/selectedOrder',
sortingIcon: 'posts/orderIcon', // Wolle sortingIcon: 'posts/orderIcon',
}), }),
selected: { // Wolle selected: {
get() { // get() {
return this.selectedOrder(this) // return this.selectedOrder(this)
}, // },
set({ value }) { // set({ value }) {
this.offset = 0 // this.offset = 0
this.posts = [] // this.posts = []
this.selectOrder(value) // this.selectOrder(value)
}, // },
}, // },
sortingOptions() { // Wolle sortingOptions() {
return this.orderOptions(this) // return this.orderOptions(this)
}, // },
finalFilters() { finalFilters() {
let filter = this.postsFilter let filter = this.postsFilter
if (this.hashtag) { if (this.hashtag) {
@ -163,9 +164,9 @@ export default {
}, },
watchQuery: ['hashtag'], watchQuery: ['hashtag'],
methods: { methods: {
...mapMutations({ // Wolle ...mapMutations({
selectOrder: 'posts/SELECT_ORDER', // selectOrder: 'posts/SELECT_ORDER',
}), // }),
clearSearch() { clearSearch() {
this.$router.push({ path: '/' }) this.$router.push({ path: '/' })
this.hashtag = null this.hashtag = null

View File

@ -7,25 +7,26 @@ import clone from 'lodash/clone'
const defaultFilter = {} const defaultFilter = {}
const orderOptions = { // Wolle const orderOptions = {
createdAt_asc: { // createdAt_asc: {
value: 'createdAt_asc', // value: 'createdAt_asc',
key: 'store.posts.orderBy.oldest.label', // key: 'store.posts.orderBy.oldest.label',
icon: 'sort-amount-asc', // icon: 'sort-amount-asc',
}, // },
createdAt_desc: { // createdAt_desc: {
value: 'createdAt_desc', // value: 'createdAt_desc',
key: 'store.posts.orderBy.newest.label', // key: 'store.posts.orderBy.newest.label',
icon: 'sort-amount-desc', // icon: 'sort-amount-desc',
}, // },
} // }
export const state = () => { export const state = () => {
return { return {
filter: { filter: {
...defaultFilter, ...defaultFilter,
}, },
order: orderOptions.createdAt_desc, // Wolle order: orderOptions.createdAt_desc,
order: 'createdAt_desc',
} }
} }
@ -76,8 +77,9 @@ export const mutations = {
if (isEmpty(get(filter, 'emotions_some.emotion_in'))) delete filter.emotions_some if (isEmpty(get(filter, 'emotions_some.emotion_in'))) delete filter.emotions_some
state.filter = filter state.filter = filter
}, },
SELECT_ORDER(state, value) { TOGGLE_ORDER(state, value) {
state.order = orderOptions[value] // Wolle state.order = orderOptions[value]
state.order = value
}, },
} }
@ -100,13 +102,13 @@ export const getters = {
filteredByEmotions(state) { filteredByEmotions(state) {
return get(state.filter, 'emotions_some.emotion_in') || [] return get(state.filter, 'emotions_some.emotion_in') || []
}, },
orderOptions: (state) => ({ $t }) => // Wolle orderOptions: (state) => ({ $t }) =>
Object.values(orderOptions).map((option) => { // Object.values(orderOptions).map((option) => {
return { // return {
...option, // ...option,
label: $t(option.key), // label: $t(option.key),
} // }
}), // }),
selectedOrder: (state) => ({ $t }) => { selectedOrder: (state) => ({ $t }) => {
return { return {
...state.order, ...state.order,
@ -114,7 +116,8 @@ export const getters = {
} }
}, },
orderBy(state) { orderBy(state) {
return state.order.value // return state.order.value
return state.order
}, },
orderIcon(state) { orderIcon(state) {
return state.order.icon return state.order.icon

View File

@ -80,35 +80,36 @@ describe('getters', () => {
}) })
}) })
describe('orderByOptions', () => { // Wolle describe('orderByOptions', () => {
it('returns all options regardless of current state', () => { // it('returns all options regardless of current state', () => {
const $t = jest.fn((t) => t) // const $t = jest.fn((t) => t)
expect(getters.orderOptions()({ $t })).toEqual([ // expect(getters.orderOptions()({ $t })).toEqual([
{ // {
key: 'store.posts.orderBy.oldest.label', // key: 'store.posts.orderBy.oldest.label',
label: 'store.posts.orderBy.oldest.label', // label: 'store.posts.orderBy.oldest.label',
icon: 'sort-amount-asc', // icon: 'sort-amount-asc',
value: 'createdAt_asc', // value: 'createdAt_asc',
}, // },
{ // {
key: 'store.posts.orderBy.newest.label', // key: 'store.posts.orderBy.newest.label',
label: 'store.posts.orderBy.newest.label', // label: 'store.posts.orderBy.newest.label',
icon: 'sort-amount-desc', // icon: 'sort-amount-desc',
value: 'createdAt_desc', // value: 'createdAt_desc',
}, // },
]) // ])
}) // })
}) // })
describe('orderBy', () => { describe('orderBy', () => {
it('returns value for graphql query', () => { it('returns value for graphql query', () => {
state = { state = {
order: { // Wolle order: {
key: 'store.posts.orderBy.newest.label', // key: 'store.posts.orderBy.newest.label',
label: 'store.posts.orderBy.newest.label', // label: 'store.posts.orderBy.newest.label',
icon: 'sort-amount-desc', // icon: 'sort-amount-desc',
value: 'createdAt_desc', // value: 'createdAt_desc',
}, // },
order: 'createdAt_desc',
} }
expect(getters.orderBy(state)).toEqual('createdAt_desc') expect(getters.orderBy(state)).toEqual('createdAt_desc')
}) })
@ -255,13 +256,14 @@ describe('mutations', () => {
}) })
}) })
describe('SELECT_ORDER', () => { describe('TOGGLE_ORDER', () => {
beforeEach(() => { beforeEach(() => {
testMutation = (key) => { testMutation = (key) => {
mutations.SELECT_ORDER(state, key) mutations.TOGGLE_ORDER(state, key)
return getters.orderBy(state) return getters.orderBy(state)
} }
}) })
it('switches the currently selected order', () => { it('switches the currently selected order', () => {
state = { state = {
// does not matter // does not matter