mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge pull request #2059 from Human-Connection/2045-filter-posts-by-language
🍰 First Implementation Of Filtering Posts By Language
This commit is contained in:
commit
d3922a8149
@ -1,10 +1,13 @@
|
||||
import faker from 'faker'
|
||||
import sample from 'lodash/sample'
|
||||
import { createTestClient } from 'apollo-server-testing'
|
||||
import createServer from '../server'
|
||||
import Factory from './factories'
|
||||
import { neode as getNeode, getDriver } from '../bootstrap/neo4j'
|
||||
import { gql } from '../jest/helpers'
|
||||
|
||||
const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
|
||||
/* eslint-disable no-multi-spaces */
|
||||
;(async function() {
|
||||
let authenticatedUser = null
|
||||
@ -341,39 +344,46 @@ import { gql } from '../jest/helpers'
|
||||
factory.create('Post', {
|
||||
author: peterLustig,
|
||||
id: 'p0',
|
||||
language: sample(languages),
|
||||
image: faker.image.unsplash.food(),
|
||||
categoryIds: ['cat16'],
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author: bobDerBaumeister,
|
||||
id: 'p1',
|
||||
language: sample(languages),
|
||||
image: faker.image.unsplash.technology(),
|
||||
categoryIds: ['cat1'],
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author: huey,
|
||||
id: 'p3',
|
||||
language: sample(languages),
|
||||
categoryIds: ['cat3'],
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author: dewey,
|
||||
id: 'p4',
|
||||
language: sample(languages),
|
||||
categoryIds: ['cat4'],
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author: louie,
|
||||
id: 'p5',
|
||||
language: sample(languages),
|
||||
categoryIds: ['cat5'],
|
||||
}),
|
||||
factory.create('Post', {
|
||||
authorId: 'u1',
|
||||
id: 'p6',
|
||||
language: sample(languages),
|
||||
image: faker.image.unsplash.buildings(),
|
||||
categoryIds: ['cat6'],
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author: huey,
|
||||
id: 'p9',
|
||||
language: sample(languages),
|
||||
categoryIds: ['cat9'],
|
||||
}),
|
||||
factory.create('Post', {
|
||||
@ -384,23 +394,27 @@ import { gql } from '../jest/helpers'
|
||||
factory.create('Post', {
|
||||
author: louie,
|
||||
id: 'p11',
|
||||
language: sample(languages),
|
||||
image: faker.image.unsplash.people(),
|
||||
categoryIds: ['cat11'],
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author: bobDerBaumeister,
|
||||
id: 'p13',
|
||||
language: sample(languages),
|
||||
categoryIds: ['cat13'],
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author: jennyRostock,
|
||||
id: 'p14',
|
||||
language: sample(languages),
|
||||
image: faker.image.unsplash.objects(),
|
||||
categoryIds: ['cat14'],
|
||||
}),
|
||||
factory.create('Post', {
|
||||
author: huey,
|
||||
id: 'p15',
|
||||
language: sample(languages),
|
||||
categoryIds: ['cat15'],
|
||||
}),
|
||||
])
|
||||
|
||||
@ -3,6 +3,9 @@ import VTooltip from 'v-tooltip'
|
||||
import Styleguide from '@human-connection/styleguide'
|
||||
import Vuex from 'vuex'
|
||||
import FilterPosts from './FilterPosts.vue'
|
||||
import locales from '~/locales'
|
||||
import orderBy from 'lodash/orderBy'
|
||||
|
||||
const localVue = createLocalVue()
|
||||
|
||||
localVue.use(Styleguide)
|
||||
@ -12,6 +15,8 @@ localVue.use(Vuex)
|
||||
let mutations
|
||||
let getters
|
||||
|
||||
const languages = orderBy(locales, 'name')
|
||||
|
||||
describe('FilterPosts.vue', () => {
|
||||
let mocks
|
||||
let propsData
|
||||
@ -20,6 +25,8 @@ describe('FilterPosts.vue', () => {
|
||||
let environmentAndNatureButton
|
||||
let democracyAndPoliticsButton
|
||||
let happyEmotionButton
|
||||
let englishButton
|
||||
let spanishButton
|
||||
|
||||
beforeEach(() => {
|
||||
mocks = {
|
||||
@ -54,6 +61,8 @@ describe('FilterPosts.vue', () => {
|
||||
'posts/RESET_CATEGORIES': jest.fn(),
|
||||
'posts/TOGGLE_CATEGORY': jest.fn(),
|
||||
'posts/TOGGLE_EMOTION': jest.fn(),
|
||||
'posts/TOGGLE_LANGUAGE': jest.fn(),
|
||||
'posts/RESET_LANGUAGES': jest.fn(),
|
||||
}
|
||||
getters = {
|
||||
'posts/isActive': () => false,
|
||||
@ -64,6 +73,7 @@ describe('FilterPosts.vue', () => {
|
||||
'posts/filteredCategoryIds': jest.fn(() => []),
|
||||
'posts/filteredByUsersFollowed': jest.fn(),
|
||||
'posts/filteredByEmotions': jest.fn(() => []),
|
||||
'posts/filteredLanguageCodes': jest.fn(() => []),
|
||||
}
|
||||
const openFilterPosts = () => {
|
||||
const store = new Vuex.Store({ mutations, getters })
|
||||
@ -97,6 +107,15 @@ describe('FilterPosts.vue', () => {
|
||||
expect(mutations['posts/TOGGLE_CATEGORY']).toHaveBeenCalledWith({}, 'cat4')
|
||||
})
|
||||
|
||||
it('calls TOGGLE_LANGUAGE when clicked', () => {
|
||||
const wrapper = openFilterPosts()
|
||||
englishButton = wrapper
|
||||
.findAll('button.language-buttons')
|
||||
.at(languages.findIndex(l => l.code === 'en'))
|
||||
englishButton.trigger('click')
|
||||
expect(mutations['posts/TOGGLE_LANGUAGE']).toHaveBeenCalledWith({}, 'en')
|
||||
})
|
||||
|
||||
it('sets category button attribute `primary` when corresponding category is filtered', () => {
|
||||
getters['posts/filteredCategoryIds'] = jest.fn(() => ['cat9'])
|
||||
const wrapper = openFilterPosts()
|
||||
@ -104,6 +123,15 @@ describe('FilterPosts.vue', () => {
|
||||
expect(democracyAndPoliticsButton.attributes().class).toContain('ds-button-primary')
|
||||
})
|
||||
|
||||
it('sets language button attribute `primary` when corresponding language is filtered', () => {
|
||||
getters['posts/filteredLanguageCodes'] = jest.fn(() => ['es'])
|
||||
const wrapper = openFilterPosts()
|
||||
spanishButton = wrapper
|
||||
.findAll('button.language-buttons')
|
||||
.at(languages.findIndex(l => l.code === 'es'))
|
||||
expect(spanishButton.attributes().class).toContain('ds-button-primary')
|
||||
})
|
||||
|
||||
it('sets "filter-by-followed-authors-only" button attribute `primary`', () => {
|
||||
getters['posts/filteredByUsersFollowed'] = jest.fn(() => true)
|
||||
const wrapper = openFilterPosts()
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
<ds-container>
|
||||
<categories-filter-menu-items :chunk="chunk" />
|
||||
<general-filter-menu-items :user="currentUser" />
|
||||
<language-filter-menu-items :user="currentUser" />
|
||||
</ds-container>
|
||||
</template>
|
||||
</dropdown>
|
||||
@ -24,12 +25,14 @@ import Dropdown from '~/components/Dropdown'
|
||||
import { mapGetters } from 'vuex'
|
||||
import CategoriesFilterMenuItems from './CategoriesFilterMenuItems'
|
||||
import GeneralFilterMenuItems from './GeneralFilterMenuItems'
|
||||
import LanguageFilterMenuItems from './LanguageFilterMenuItems'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Dropdown,
|
||||
CategoriesFilterMenuItems,
|
||||
GeneralFilterMenuItems,
|
||||
LanguageFilterMenuItems,
|
||||
},
|
||||
props: {
|
||||
placement: { type: String },
|
||||
|
||||
104
webapp/components/FilterPosts/LanguageFilterMenuItems.vue
Normal file
104
webapp/components/FilterPosts/LanguageFilterMenuItems.vue
Normal file
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<ds-space margin-top="large">
|
||||
<ds-flex id="filter-posts-header">
|
||||
<ds-heading tag="h4">{{ $t('filter-posts.language.header') }}</ds-heading>
|
||||
<ds-space margin-bottom="large" />
|
||||
</ds-flex>
|
||||
<ds-flex :gutter="{ lg: 'small' }">
|
||||
<ds-flex-item
|
||||
:width="{ base: '100%', sm: '100%', md: '100%', lg: '5%' }"
|
||||
class="language-menu-item"
|
||||
>
|
||||
<ds-flex>
|
||||
<ds-flex-item width="10%" />
|
||||
<ds-flex-item width="100%">
|
||||
<ds-button
|
||||
icon="check"
|
||||
@click.stop.prevent="resetLanguages"
|
||||
:primary="!filteredLanguageCodes.length"
|
||||
/>
|
||||
<ds-flex-item>
|
||||
<label class="language-labels">{{ $t('filter-posts.language.all') }}</label>
|
||||
</ds-flex-item>
|
||||
<ds-space />
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '0%', sm: '0%', md: '0%', lg: '4%' }" />
|
||||
<ds-flex-item
|
||||
:width="{ base: '0%', sm: '0%', md: '0%', lg: '3%' }"
|
||||
id="languages-menu-divider"
|
||||
/>
|
||||
<ds-flex v-for="language in locales" :key="language.code" class="languages-menu">
|
||||
<ds-flex class="languages-menu">
|
||||
<ds-flex-item width="100%" class="language-menu-item">
|
||||
<ds-button
|
||||
class="language-buttons"
|
||||
:primary="filteredLanguageCodes.includes(language.code)"
|
||||
@click.stop.prevent="toggleLanguage(language.code)"
|
||||
>
|
||||
{{ language.code.toUpperCase() }}
|
||||
</ds-button>
|
||||
<ds-space margin-bottom="small" />
|
||||
</ds-flex-item>
|
||||
<ds-flex>
|
||||
<ds-flex-item class="language-menu-item">
|
||||
<label class="language-labels">
|
||||
{{ language.name }}
|
||||
</label>
|
||||
</ds-flex-item>
|
||||
<ds-space margin-bottom="xx-large" />
|
||||
</ds-flex>
|
||||
</ds-flex>
|
||||
</ds-flex>
|
||||
</ds-flex>
|
||||
</ds-space>
|
||||
</template>
|
||||
<script>
|
||||
import locales from '~/locales'
|
||||
import orderBy from 'lodash/orderBy'
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
chunk: { type: Array, default: () => [] },
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
filteredLanguageCodes: 'posts/filteredLanguageCodes',
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({
|
||||
resetLanguages: 'posts/RESET_LANGUAGES',
|
||||
toggleLanguage: 'posts/TOGGLE_LANGUAGE',
|
||||
}),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
locales: orderBy(locales, 'name'),
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.language-menu-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.languages-menu {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.language-labels,
|
||||
.follow-label {
|
||||
font-size: $font-size-small;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 960px) {
|
||||
#languages-menu-divider {
|
||||
border-left: 1px solid $border-color-soft;
|
||||
margin: 9px 0px 40px 0px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -86,6 +86,10 @@
|
||||
},
|
||||
"followers": {
|
||||
"label": "Benutzern, denen ich folge"
|
||||
},
|
||||
"language": {
|
||||
"header": "Sprachen",
|
||||
"all": "Alle"
|
||||
}
|
||||
},
|
||||
"site": {
|
||||
|
||||
@ -87,6 +87,10 @@
|
||||
},
|
||||
"followers": {
|
||||
"label": "Users I follow"
|
||||
},
|
||||
"language": {
|
||||
"header": "Languages",
|
||||
"all": "All"
|
||||
}
|
||||
},
|
||||
"site": {
|
||||
|
||||
@ -48,12 +48,23 @@ export const mutations = {
|
||||
delete filter.categories_some
|
||||
state.filter = filter
|
||||
},
|
||||
RESET_LANGUAGES(state) {
|
||||
const filter = clone(state.filter)
|
||||
delete filter.language_in
|
||||
state.filter = filter
|
||||
},
|
||||
TOGGLE_CATEGORY(state, categoryId) {
|
||||
const filter = clone(state.filter)
|
||||
update(filter, 'categories_some.id_in', categoryIds => xor(categoryIds, [categoryId]))
|
||||
if (isEmpty(get(filter, 'categories_some.id_in'))) delete filter.categories_some
|
||||
state.filter = filter
|
||||
},
|
||||
TOGGLE_LANGUAGE(state, languageCode) {
|
||||
const filter = clone(state.filter)
|
||||
update(filter, 'language_in', languageCodes => xor(languageCodes, [languageCode]))
|
||||
if (isEmpty(get(filter, 'language_in'))) delete filter.language_in
|
||||
state.filter = filter
|
||||
},
|
||||
TOGGLE_EMOTION(state, emotion) {
|
||||
const filter = clone(state.filter)
|
||||
update(filter, 'emotions_some.emotion_in', emotions => xor(emotions, [emotion]))
|
||||
@ -75,6 +86,9 @@ export const getters = {
|
||||
filteredCategoryIds(state) {
|
||||
return get(state.filter, 'categories_some.id_in') || []
|
||||
},
|
||||
filteredLanguageCodes(state) {
|
||||
return get(state.filter, 'language_in') || []
|
||||
},
|
||||
filteredByUsersFollowed(state) {
|
||||
return !!get(state.filter, 'author.followedBy_some.id')
|
||||
},
|
||||
|
||||
@ -19,12 +19,24 @@ describe('getters', () => {
|
||||
expect(getters.filteredCategoryIds(state)).toEqual([24])
|
||||
})
|
||||
|
||||
it('returns empty array if filter is not set', () => {
|
||||
it('returns empty array if category filter is not set', () => {
|
||||
state = { filter: { author: { followedBy_some: { id: 7 } } } }
|
||||
expect(getters.filteredCategoryIds(state)).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('filteredLanguageCodes', () => {
|
||||
it('returns category ids if filter is set', () => {
|
||||
state = { filter: { language_in: ['en', 'de', 'pt'] } }
|
||||
expect(getters.filteredLanguageCodes(state)).toEqual(['en', 'de', 'pt'])
|
||||
})
|
||||
|
||||
it('returns empty array if language filter is not set', () => {
|
||||
state = { filter: { author: { followedBy_some: { id: 7 } } } }
|
||||
expect(getters.filteredLanguageCodes(state)).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('filter', () => {
|
||||
it('returns filter', () => {
|
||||
state = { filter: { author: { followedBy_some: { id: 7 } } } }
|
||||
@ -104,6 +116,19 @@ describe('getters', () => {
|
||||
})
|
||||
|
||||
describe('mutations', () => {
|
||||
describe('RESET_LANGUAGES', () => {
|
||||
it('resets the languages filter', () => {
|
||||
state = {
|
||||
filter: {
|
||||
author: { followedBy_some: { id: 7 } },
|
||||
language_in: ['nl'],
|
||||
},
|
||||
}
|
||||
mutations.RESET_LANGUAGES(state)
|
||||
expect(getters.filter(state)).toEqual({ author: { followedBy_some: { id: 7 } } })
|
||||
})
|
||||
})
|
||||
|
||||
describe('RESET_CATEGORIES', () => {
|
||||
beforeEach(() => {
|
||||
testMutation = categoryId => {
|
||||
@ -122,6 +147,45 @@ describe('mutations', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('TOGGLE_LANGUAGE', () => {
|
||||
beforeEach(() => {
|
||||
testMutation = languageCode => {
|
||||
mutations.TOGGLE_LANGUAGE(state, languageCode)
|
||||
return getters.filter(state)
|
||||
}
|
||||
})
|
||||
|
||||
it('creates category filter if empty', () => {
|
||||
state = { filter: {} }
|
||||
expect(testMutation('de')).toEqual({ language_in: ['de'] })
|
||||
})
|
||||
|
||||
it('adds language code to existing filter', () => {
|
||||
state = { filter: { language_in: ['de'] } }
|
||||
expect(testMutation('en')).toEqual({ language_in: ['de', 'en'] })
|
||||
})
|
||||
|
||||
it('removes category id if present', () => {
|
||||
state = { filter: { language_in: ['de', 'en'] } }
|
||||
expect(testMutation('de')).toEqual({ language_in: ['en'] })
|
||||
})
|
||||
|
||||
it('removes language filter if empty', () => {
|
||||
state = { filter: { language_in: ['de'] } }
|
||||
expect(testMutation('de')).toEqual({})
|
||||
})
|
||||
|
||||
it('does not get in the way of other filters', () => {
|
||||
state = {
|
||||
filter: {
|
||||
author: { followedBy_some: { id: 7 } },
|
||||
language_in: ['de'],
|
||||
},
|
||||
}
|
||||
expect(testMutation('de')).toEqual({ author: { followedBy_some: { id: 7 } } })
|
||||
})
|
||||
})
|
||||
|
||||
describe('TOGGLE_CATEGORY', () => {
|
||||
beforeEach(() => {
|
||||
testMutation = categoryId => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user