mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
refactor: CategoriesFilter to not use ds-flex
Co-authored-by: mattwr18 <mattwr18@gmail.com> - introduce LabeledButton component - rename FilterMenu to HashtagsFilter and FilterPosts to FilterMenu
This commit is contained in:
parent
33237d8803
commit
1ffde6bf10
@ -19,3 +19,10 @@ h6,
|
|||||||
p {
|
p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|||||||
125
webapp/components/FilterMenu/CategoriesFilter.vue
Normal file
125
webapp/components/FilterMenu/CategoriesFilter.vue
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<template>
|
||||||
|
<section class="categories-filter">
|
||||||
|
<h4 class="title">{{ $t('filter-menu.categories.header') }}</h4>
|
||||||
|
<labeled-button
|
||||||
|
:filled="!filteredCategoryIds.length"
|
||||||
|
icon="check"
|
||||||
|
:label="$t('filter-menu.categories.all')"
|
||||||
|
@click="resetCategories"
|
||||||
|
/>
|
||||||
|
<div class="divider" />
|
||||||
|
<ul class="categories-list">
|
||||||
|
<li v-for="category in categories" :key="category.id" class="menu-item">
|
||||||
|
<labeled-button
|
||||||
|
:icon="category.icon"
|
||||||
|
:filled="filteredCategoryIds.includes(category.id)"
|
||||||
|
:label="$t(`contribution.category.name.${category.slug}`)"
|
||||||
|
@click="toggleCategory(category.id)"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
|
import CategoryQuery from '~/graphql/CategoryQuery.js'
|
||||||
|
import LabeledButton from '~/components/_new/generic/LabeledButton/LabeledButton'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
LabeledButton,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
categories: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
filteredCategoryIds: 'posts/filteredCategoryIds',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations({
|
||||||
|
resetCategories: 'posts/RESET_CATEGORIES',
|
||||||
|
toggleCategory: 'posts/TOGGLE_CATEGORY',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
apollo: {
|
||||||
|
Category: {
|
||||||
|
query() {
|
||||||
|
return CategoryQuery()
|
||||||
|
},
|
||||||
|
update({ Category }) {
|
||||||
|
if (!Category) return []
|
||||||
|
this.categories = Category
|
||||||
|
},
|
||||||
|
fetchPolicy: 'cache-and-network',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.categories-filter {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-top: $space-small;
|
||||||
|
|
||||||
|
> .title {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .labeled-button {
|
||||||
|
margin-top: $space-small;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .divider {
|
||||||
|
border-left: $border-size-base solid $border-color-soft;
|
||||||
|
margin: $space-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .categories-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-basis: 80%;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
> .menu-item {
|
||||||
|
width: 12.5%;
|
||||||
|
margin: $space-small 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px) {
|
||||||
|
.categories-list > .menu-item {
|
||||||
|
width: 16%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 630px) {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
> .categories-list > .menu-item {
|
||||||
|
width: 25%;
|
||||||
|
margin: $space-x-small 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .title {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .divider {
|
||||||
|
border-top: $border-size-base solid $border-color-soft;
|
||||||
|
margin: $space-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 440px) {
|
||||||
|
.categories-list > .menu-item {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,42 +1,166 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
|
|
||||||
|
import Vuex from 'vuex'
|
||||||
import FilterMenu from './FilterMenu.vue'
|
import FilterMenu from './FilterMenu.vue'
|
||||||
|
import locales from '~/locales'
|
||||||
|
import orderBy from 'lodash/orderBy'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
|
let mutations
|
||||||
|
let getters
|
||||||
|
|
||||||
|
const languages = orderBy(locales, 'name')
|
||||||
|
|
||||||
describe('FilterMenu.vue', () => {
|
describe('FilterMenu.vue', () => {
|
||||||
let wrapper
|
|
||||||
let mocks
|
let mocks
|
||||||
let propsData
|
let propsData
|
||||||
|
let menuToggle
|
||||||
|
let allCategoriesButton
|
||||||
|
let environmentAndNatureButton
|
||||||
|
let democracyAndPoliticsButton
|
||||||
|
let happyEmotionButton
|
||||||
|
let englishButton
|
||||||
|
let spanishButton
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mocks = { $t: () => {} }
|
mocks = {
|
||||||
|
$apollo: {
|
||||||
|
query: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
data: { Post: { title: 'Post with Category', category: [{ id: 'cat4' }] } },
|
||||||
|
})
|
||||||
|
.mockRejectedValue({ message: 'We were unable to filter' }),
|
||||||
|
},
|
||||||
|
$t: jest.fn(),
|
||||||
|
$i18n: {
|
||||||
|
locale: () => 'en',
|
||||||
|
},
|
||||||
|
$toast: {
|
||||||
|
error: jest.fn(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
propsData = {
|
||||||
|
categories: [
|
||||||
|
{ id: 'cat4', name: 'Environment & Nature', icon: 'tree' },
|
||||||
|
{ id: 'cat15', name: 'Consumption & Sustainability', icon: 'shopping-cart' },
|
||||||
|
{ id: 'cat9', name: 'Democracy & Politics', icon: 'university' },
|
||||||
|
],
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('given a hashtag', () => {
|
describe('mount', () => {
|
||||||
beforeEach(() => {
|
mutations = {
|
||||||
propsData = {
|
'posts/TOGGLE_FILTER_BY_FOLLOWED': jest.fn(),
|
||||||
hashtag: 'Frieden',
|
'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,
|
||||||
|
'auth/isModerator': () => false,
|
||||||
|
'auth/user': () => {
|
||||||
|
return { id: 'u34' }
|
||||||
|
},
|
||||||
|
'posts/filteredCategoryIds': jest.fn(() => []),
|
||||||
|
'posts/filteredByUsersFollowed': jest.fn(),
|
||||||
|
'posts/filteredByEmotions': jest.fn(() => []),
|
||||||
|
'posts/filteredLanguageCodes': jest.fn(() => []),
|
||||||
|
}
|
||||||
|
const openFilterMenu = () => {
|
||||||
|
const store = new Vuex.Store({ mutations, getters })
|
||||||
|
const wrapper = mount(FilterMenu, { mocks, localVue, propsData, store })
|
||||||
|
menuToggle = wrapper.findAll('button').at(0)
|
||||||
|
menuToggle.trigger('click')
|
||||||
|
return wrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
it('groups the categories by pair', () => {
|
||||||
|
const wrapper = openFilterMenu()
|
||||||
|
expect(wrapper.vm.chunk).toEqual([
|
||||||
|
[
|
||||||
|
{ id: 'cat4', name: 'Environment & Nature', icon: 'tree' },
|
||||||
|
{ id: 'cat15', name: 'Consumption & Sustainability', icon: 'shopping-cart' },
|
||||||
|
],
|
||||||
|
[{ id: 'cat9', name: 'Democracy & Politics', icon: 'university' }],
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('mount', () => {
|
it('starts with all categories button active', () => {
|
||||||
const Wrapper = () => {
|
const wrapper = openFilterMenu()
|
||||||
return mount(FilterMenu, { mocks, localVue, propsData })
|
allCategoriesButton = wrapper.findAll('button').at(1)
|
||||||
}
|
expect(allCategoriesButton.attributes().class).toContain('--filled')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls TOGGLE_CATEGORY when clicked', () => {
|
||||||
|
const wrapper = openFilterMenu()
|
||||||
|
environmentAndNatureButton = wrapper.findAll('button').at(2)
|
||||||
|
environmentAndNatureButton.trigger('click')
|
||||||
|
expect(mutations['posts/TOGGLE_CATEGORY']).toHaveBeenCalledWith({}, 'cat4')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls TOGGLE_LANGUAGE when clicked', () => {
|
||||||
|
const wrapper = openFilterMenu()
|
||||||
|
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 `filled` when corresponding category is filtered', () => {
|
||||||
|
getters['posts/filteredCategoryIds'] = jest.fn(() => ['cat9'])
|
||||||
|
const wrapper = openFilterMenu()
|
||||||
|
democracyAndPoliticsButton = wrapper.findAll('button').at(4)
|
||||||
|
expect(democracyAndPoliticsButton.attributes().class).toContain('--filled')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets language button attribute `filled` when corresponding language is filtered', () => {
|
||||||
|
getters['posts/filteredLanguageCodes'] = jest.fn(() => ['es'])
|
||||||
|
const wrapper = openFilterMenu()
|
||||||
|
spanishButton = wrapper
|
||||||
|
.findAll('button.language-buttons')
|
||||||
|
.at(languages.findIndex(l => l.code === 'es'))
|
||||||
|
expect(spanishButton.attributes().class).toContain('--filled')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets "filter-by-followed" button attribute `filled`', () => {
|
||||||
|
getters['posts/filteredByUsersFollowed'] = jest.fn(() => true)
|
||||||
|
const wrapper = openFilterMenu()
|
||||||
|
expect(wrapper.find('.base-button[data-test="filter-by-followed"]').classes('--filled')).toBe(
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('click "filter-by-followed" button', () => {
|
||||||
|
let wrapper
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
wrapper = Wrapper()
|
wrapper = openFilterMenu()
|
||||||
|
wrapper.find('.base-button[data-test="filter-by-followed"]').trigger('click')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('renders a card', () => {
|
it('calls TOGGLE_FILTER_BY_FOLLOWED', () => {
|
||||||
wrapper = Wrapper()
|
expect(mutations['posts/TOGGLE_FILTER_BY_FOLLOWED']).toHaveBeenCalledWith({}, 'u34')
|
||||||
expect(wrapper.is('.base-card')).toBe(true)
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('click on an "emotions-buttons" button', () => {
|
||||||
|
it('calls TOGGLE_EMOTION when clicked', () => {
|
||||||
|
const wrapper = openFilterMenu()
|
||||||
|
happyEmotionButton = wrapper.findAll('.emotion-button .base-button').at(1)
|
||||||
|
happyEmotionButton.trigger('click')
|
||||||
|
expect(mutations['posts/TOGGLE_EMOTION']).toHaveBeenCalledWith({}, 'happy')
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('click clear search button', () => {
|
it('sets the attribute `src` to colorized image', () => {
|
||||||
it('emits clearSearch', () => {
|
getters['posts/filteredByEmotions'] = jest.fn(() => ['happy'])
|
||||||
wrapper.find('.base-button').trigger('click')
|
const wrapper = openFilterMenu()
|
||||||
expect(wrapper.emitted().clearSearch).toHaveLength(1)
|
happyEmotionButton = wrapper.findAll('.emotion-button .base-button').at(1)
|
||||||
})
|
const happyEmotionButtonImage = happyEmotionButton.find('img')
|
||||||
|
expect(happyEmotionButtonImage.attributes().src).toEqual('/img/svg/emoji/happy_color.svg')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,36 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<base-card class="filter-menu">
|
<dropdown ref="menu" :placement="placement" :offset="offset">
|
||||||
<h2>{{ $t('filter-menu.hashtag-search', { hashtag }) }}</h2>
|
|
||||||
<base-button
|
<base-button
|
||||||
icon="close"
|
slot="default"
|
||||||
circle
|
icon="filter"
|
||||||
:title="this.$t('filter-menu.clearSearch')"
|
:filled="filterActive"
|
||||||
@click="clearSearch"
|
:ghost="!filterActive"
|
||||||
/>
|
slot-scope="{ toggleMenu }"
|
||||||
</base-card>
|
@click.prevent="toggleMenu()"
|
||||||
|
>
|
||||||
|
<base-icon class="dropdown-arrow" name="angle-down" />
|
||||||
|
</base-button>
|
||||||
|
<template slot="popover">
|
||||||
|
<ds-container>
|
||||||
|
<categories-filter />
|
||||||
|
<general-filter />
|
||||||
|
<language-filter />
|
||||||
|
</ds-container>
|
||||||
|
</template>
|
||||||
|
</dropdown>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Dropdown from '~/components/Dropdown'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
import CategoriesFilter from './CategoriesFilter'
|
||||||
|
import GeneralFilter from './GeneralFilter'
|
||||||
|
import LanguageFilter from './LanguageFilter'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
components: {
|
||||||
hashtag: {
|
Dropdown,
|
||||||
type: String,
|
CategoriesFilter,
|
||||||
required: true,
|
GeneralFilter,
|
||||||
},
|
LanguageFilter,
|
||||||
},
|
},
|
||||||
methods: {
|
props: {
|
||||||
clearSearch() {
|
placement: { type: String },
|
||||||
this.$emit('clearSearch')
|
offset: { type: [String, Number] },
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
filterActive: 'posts/isActive',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.filter-menu.base-card {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: $space-x-small $space-base;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<ds-space>
|
<ds-space>
|
||||||
<ds-flex id="filter-posts-by-followers-header">
|
<ds-flex id="filter-menu-by-followers-header">
|
||||||
<ds-heading tag="h4">{{ $t('filter-posts.general.header') }}</ds-heading>
|
<ds-heading tag="h4">{{ $t('filter-menu.general.header') }}</ds-heading>
|
||||||
<ds-space margin-bottom="large" />
|
<ds-space margin-bottom="large" />
|
||||||
</ds-flex>
|
</ds-flex>
|
||||||
<ds-flex :gutter="{ lg: 'large' }">
|
<ds-flex :gutter="{ lg: 'large' }">
|
||||||
@ -14,14 +14,14 @@
|
|||||||
icon="user-plus"
|
icon="user-plus"
|
||||||
circle
|
circle
|
||||||
:filled="filteredByUsersFollowed"
|
:filled="filteredByUsersFollowed"
|
||||||
@click="toggleFilteredByFollowed(user.id)"
|
@click="toggleFilteredByFollowed(currentUser.id)"
|
||||||
v-tooltip="{
|
v-tooltip="{
|
||||||
content: this.$t('contribution.filterFollow'),
|
content: this.$t('contribution.filterFollow'),
|
||||||
placement: 'left',
|
placement: 'left',
|
||||||
delay: { show: 500 },
|
delay: { show: 500 },
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<label class="follow-label">{{ $t('filter-posts.followers.label') }}</label>
|
<label class="follow-label">{{ $t('filter-menu.followers.label') }}</label>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<emotion-button
|
<emotion-button
|
||||||
v-for="emotion in emotionsArray"
|
v-for="emotion in emotionsArray"
|
||||||
@ -42,9 +42,6 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
EmotionButton,
|
EmotionButton,
|
||||||
},
|
},
|
||||||
props: {
|
|
||||||
user: { type: Object, required: true },
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
emotionsArray: ['funny', 'happy', 'surprised', 'cry', 'angry'],
|
emotionsArray: ['funny', 'happy', 'surprised', 'cry', 'angry'],
|
||||||
@ -54,6 +51,7 @@ export default {
|
|||||||
...mapGetters({
|
...mapGetters({
|
||||||
filteredByUsersFollowed: 'posts/filteredByUsersFollowed',
|
filteredByUsersFollowed: 'posts/filteredByUsersFollowed',
|
||||||
filteredByEmotions: 'posts/filteredByEmotions',
|
filteredByEmotions: 'posts/filteredByEmotions',
|
||||||
|
currentUser: 'auth/user',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -71,11 +69,11 @@ export default {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
#filter-posts-header {
|
#filter-menu-header {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
#filter-posts-by-followers-header {
|
#filter-menu-by-followers-header {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +90,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 960px) {
|
@media only screen and (max-width: 960px) {
|
||||||
#filter-posts-header {
|
#filter-menu-header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<ds-space margin-top="large">
|
<ds-space margin-top="large">
|
||||||
<ds-flex id="filter-posts-header">
|
<ds-flex id="filter-menu-header">
|
||||||
<ds-heading tag="h4">{{ $t('filter-posts.language.header') }}</ds-heading>
|
<ds-heading tag="h4">{{ $t('filter-menu.language.header') }}</ds-heading>
|
||||||
<ds-space margin-bottom="large" />
|
<ds-space margin-bottom="large" />
|
||||||
</ds-flex>
|
</ds-flex>
|
||||||
<ds-flex :gutter="{ lg: 'small' }">
|
<ds-flex :gutter="{ lg: 'small' }">
|
||||||
@ -19,7 +19,7 @@
|
|||||||
@click="resetLanguages"
|
@click="resetLanguages"
|
||||||
/>
|
/>
|
||||||
<ds-flex-item>
|
<ds-flex-item>
|
||||||
<label class="language-labels">{{ $t('filter-posts.language.all') }}</label>
|
<label class="language-labels">{{ $t('filter-menu.language.all') }}</label>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-space />
|
<ds-space />
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
@ -62,9 +62,6 @@ import orderBy from 'lodash/orderBy'
|
|||||||
import { mapGetters, mapMutations } from 'vuex'
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
|
||||||
chunk: { type: Array, default: () => [] },
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
filteredLanguageCodes: 'posts/filteredLanguageCodes',
|
filteredLanguageCodes: 'posts/filteredLanguageCodes',
|
||||||
@ -1,103 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ds-space margin-top="large">
|
|
||||||
<ds-flex id="filter-posts-header">
|
|
||||||
<ds-heading tag="h4">{{ $t('filter-posts.categories.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="categories-menu-item"
|
|
||||||
>
|
|
||||||
<ds-flex>
|
|
||||||
<ds-flex-item width="10%" />
|
|
||||||
<ds-flex-item width="100%">
|
|
||||||
<base-button
|
|
||||||
circle
|
|
||||||
icon="check"
|
|
||||||
@click="resetCategories"
|
|
||||||
:filled="!filteredCategoryIds.length"
|
|
||||||
/>
|
|
||||||
<ds-flex-item>
|
|
||||||
<label class="category-labels">{{ $t('filter-posts.categories.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="categories-menu-divider"
|
|
||||||
/>
|
|
||||||
<ds-flex-item
|
|
||||||
:width="{ base: '50%', sm: '50%', md: '50%', lg: '11%' }"
|
|
||||||
v-for="index in chunk.length"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<ds-flex v-for="category in chunk[index - 1]" :key="category.id" class="categories-menu">
|
|
||||||
<ds-flex class="categories-menu">
|
|
||||||
<ds-flex-item width="100%" class="categories-menu-item">
|
|
||||||
<base-button
|
|
||||||
circle
|
|
||||||
:icon="category.icon"
|
|
||||||
:filled="filteredCategoryIds.includes(category.id)"
|
|
||||||
@click="toggleCategory(category.id)"
|
|
||||||
/>
|
|
||||||
<ds-space margin-bottom="small" />
|
|
||||||
</ds-flex-item>
|
|
||||||
<ds-flex>
|
|
||||||
<ds-flex-item class="categories-menu-item">
|
|
||||||
<label class="category-labels">
|
|
||||||
{{ $t(`contribution.category.name.${category.slug}`) }}
|
|
||||||
</label>
|
|
||||||
</ds-flex-item>
|
|
||||||
<ds-space margin-bottom="xx-large" />
|
|
||||||
</ds-flex>
|
|
||||||
</ds-flex>
|
|
||||||
</ds-flex>
|
|
||||||
</ds-flex-item>
|
|
||||||
</ds-flex>
|
|
||||||
</ds-space>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { mapGetters, mapMutations } from 'vuex'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
chunk: { type: Array, default: () => [] },
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapGetters({
|
|
||||||
filteredCategoryIds: 'posts/filteredCategoryIds',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapMutations({
|
|
||||||
resetCategories: 'posts/RESET_CATEGORIES',
|
|
||||||
toggleCategory: 'posts/TOGGLE_CATEGORY',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss">
|
|
||||||
.categories-menu-item {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.categories-menu {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-labels,
|
|
||||||
.follow-label {
|
|
||||||
font-size: $font-size-small;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width: 960px) {
|
|
||||||
#categories-menu-divider {
|
|
||||||
border-left: 1px solid $border-color-soft;
|
|
||||||
margin: 9px 0px 40px 0px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,167 +0,0 @@
|
|||||||
import { mount } from '@vue/test-utils'
|
|
||||||
|
|
||||||
import Vuex from 'vuex'
|
|
||||||
import FilterPosts from './FilterPosts.vue'
|
|
||||||
import locales from '~/locales'
|
|
||||||
import orderBy from 'lodash/orderBy'
|
|
||||||
|
|
||||||
const localVue = global.localVue
|
|
||||||
|
|
||||||
let mutations
|
|
||||||
let getters
|
|
||||||
|
|
||||||
const languages = orderBy(locales, 'name')
|
|
||||||
|
|
||||||
describe('FilterPosts.vue', () => {
|
|
||||||
let mocks
|
|
||||||
let propsData
|
|
||||||
let menuToggle
|
|
||||||
let allCategoriesButton
|
|
||||||
let environmentAndNatureButton
|
|
||||||
let democracyAndPoliticsButton
|
|
||||||
let happyEmotionButton
|
|
||||||
let englishButton
|
|
||||||
let spanishButton
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mocks = {
|
|
||||||
$apollo: {
|
|
||||||
query: jest
|
|
||||||
.fn()
|
|
||||||
.mockResolvedValueOnce({
|
|
||||||
data: { Post: { title: 'Post with Category', category: [{ id: 'cat4' }] } },
|
|
||||||
})
|
|
||||||
.mockRejectedValue({ message: 'We were unable to filter' }),
|
|
||||||
},
|
|
||||||
$t: jest.fn(),
|
|
||||||
$i18n: {
|
|
||||||
locale: () => 'en',
|
|
||||||
},
|
|
||||||
$toast: {
|
|
||||||
error: jest.fn(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
propsData = {
|
|
||||||
categories: [
|
|
||||||
{ id: 'cat4', name: 'Environment & Nature', icon: 'tree' },
|
|
||||||
{ id: 'cat15', name: 'Consumption & Sustainability', icon: 'shopping-cart' },
|
|
||||||
{ id: 'cat9', name: 'Democracy & Politics', icon: 'university' },
|
|
||||||
],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('mount', () => {
|
|
||||||
mutations = {
|
|
||||||
'posts/TOGGLE_FILTER_BY_FOLLOWED': jest.fn(),
|
|
||||||
'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,
|
|
||||||
'auth/isModerator': () => false,
|
|
||||||
'auth/user': () => {
|
|
||||||
return { id: 'u34' }
|
|
||||||
},
|
|
||||||
'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 })
|
|
||||||
const wrapper = mount(FilterPosts, { mocks, localVue, propsData, store })
|
|
||||||
menuToggle = wrapper.findAll('button').at(0)
|
|
||||||
menuToggle.trigger('click')
|
|
||||||
return wrapper
|
|
||||||
}
|
|
||||||
|
|
||||||
it('groups the categories by pair', () => {
|
|
||||||
const wrapper = openFilterPosts()
|
|
||||||
expect(wrapper.vm.chunk).toEqual([
|
|
||||||
[
|
|
||||||
{ id: 'cat4', name: 'Environment & Nature', icon: 'tree' },
|
|
||||||
{ id: 'cat15', name: 'Consumption & Sustainability', icon: 'shopping-cart' },
|
|
||||||
],
|
|
||||||
[{ id: 'cat9', name: 'Democracy & Politics', icon: 'university' }],
|
|
||||||
])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('starts with all categories button active', () => {
|
|
||||||
const wrapper = openFilterPosts()
|
|
||||||
allCategoriesButton = wrapper.findAll('button').at(1)
|
|
||||||
expect(allCategoriesButton.attributes().class).toContain('--filled')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('calls TOGGLE_CATEGORY when clicked', () => {
|
|
||||||
const wrapper = openFilterPosts()
|
|
||||||
environmentAndNatureButton = wrapper.findAll('button').at(2)
|
|
||||||
environmentAndNatureButton.trigger('click')
|
|
||||||
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 `filled` when corresponding category is filtered', () => {
|
|
||||||
getters['posts/filteredCategoryIds'] = jest.fn(() => ['cat9'])
|
|
||||||
const wrapper = openFilterPosts()
|
|
||||||
democracyAndPoliticsButton = wrapper.findAll('button').at(4)
|
|
||||||
expect(democracyAndPoliticsButton.attributes().class).toContain('--filled')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('sets language button attribute `filled` 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('--filled')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('sets "filter-by-followed" button attribute `filled`', () => {
|
|
||||||
getters['posts/filteredByUsersFollowed'] = jest.fn(() => true)
|
|
||||||
const wrapper = openFilterPosts()
|
|
||||||
expect(wrapper.find('.base-button[data-test="filter-by-followed"]').classes('--filled')).toBe(
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('click "filter-by-followed" button', () => {
|
|
||||||
let wrapper
|
|
||||||
beforeEach(() => {
|
|
||||||
wrapper = openFilterPosts()
|
|
||||||
wrapper.find('.base-button[data-test="filter-by-followed"]').trigger('click')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('calls TOGGLE_FILTER_BY_FOLLOWED', () => {
|
|
||||||
expect(mutations['posts/TOGGLE_FILTER_BY_FOLLOWED']).toHaveBeenCalledWith({}, 'u34')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('click on an "emotions-buttons" button', () => {
|
|
||||||
it('calls TOGGLE_EMOTION when clicked', () => {
|
|
||||||
const wrapper = openFilterPosts()
|
|
||||||
happyEmotionButton = wrapper.findAll('.emotion-button .base-button').at(1)
|
|
||||||
happyEmotionButton.trigger('click')
|
|
||||||
expect(mutations['posts/TOGGLE_EMOTION']).toHaveBeenCalledWith({}, 'happy')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('sets the attribute `src` to colorized image', () => {
|
|
||||||
getters['posts/filteredByEmotions'] = jest.fn(() => ['happy'])
|
|
||||||
const wrapper = openFilterPosts()
|
|
||||||
happyEmotionButton = wrapper.findAll('.emotion-button .base-button').at(1)
|
|
||||||
const happyEmotionButtonImage = happyEmotionButton.find('img')
|
|
||||||
expect(happyEmotionButtonImage.attributes().src).toEqual('/img/svg/emoji/happy_color.svg')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
<template>
|
|
||||||
<dropdown ref="menu" :placement="placement" :offset="offset">
|
|
||||||
<template #default="{ toggleMenu }">
|
|
||||||
<base-button
|
|
||||||
icon="filter"
|
|
||||||
:filled="filterActive"
|
|
||||||
:ghost="!filterActive"
|
|
||||||
@click.prevent="toggleMenu()"
|
|
||||||
>
|
|
||||||
<base-icon class="dropdown-arrow" name="angle-down" />
|
|
||||||
</base-button>
|
|
||||||
</template>
|
|
||||||
<template slot="popover">
|
|
||||||
<ds-container>
|
|
||||||
<categories-filter-menu-items :chunk="chunk" />
|
|
||||||
<general-filter-menu-items :user="currentUser" />
|
|
||||||
<language-filter-menu-items :user="currentUser" />
|
|
||||||
</ds-container>
|
|
||||||
</template>
|
|
||||||
</dropdown>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { chunk } from 'lodash'
|
|
||||||
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 },
|
|
||||||
offset: { type: [String, Number] },
|
|
||||||
categories: { type: Array, default: () => [] },
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapGetters({
|
|
||||||
currentUser: 'auth/user',
|
|
||||||
filterActive: 'posts/isActive',
|
|
||||||
}),
|
|
||||||
chunk() {
|
|
||||||
return chunk(this.categories, 2)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
43
webapp/components/HashtagsFilter/HashtagsFilter.spec.js
Normal file
43
webapp/components/HashtagsFilter/HashtagsFilter.spec.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import FilterCard from './FilterCard.vue'
|
||||||
|
|
||||||
|
const localVue = global.localVue
|
||||||
|
|
||||||
|
describe('FilterCard.vue', () => {
|
||||||
|
let wrapper
|
||||||
|
let mocks
|
||||||
|
let propsData
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mocks = { $t: () => {} }
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('given a hashtag', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
propsData = {
|
||||||
|
hashtag: 'Frieden',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('mount', () => {
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(FilterCard, { mocks, localVue, propsData })
|
||||||
|
}
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders a card', () => {
|
||||||
|
wrapper = Wrapper()
|
||||||
|
expect(wrapper.is('.base-card')).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('click clear search button', () => {
|
||||||
|
it('emits clearSearch', () => {
|
||||||
|
wrapper.find('.base-button').trigger('click')
|
||||||
|
expect(wrapper.emitted().clearSearch).toHaveLength(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
36
webapp/components/HashtagsFilter/HashtagsFilter.vue
Normal file
36
webapp/components/HashtagsFilter/HashtagsFilter.vue
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<base-card class="hashtags-filter">
|
||||||
|
<h2>{{ $t('hashtags-filter.hashtag-search', { hashtag }) }}</h2>
|
||||||
|
<base-button
|
||||||
|
icon="close"
|
||||||
|
circle
|
||||||
|
:title="this.$t('hashtags-filter.clearSearch')"
|
||||||
|
@click="clearSearch"
|
||||||
|
/>
|
||||||
|
</base-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
hashtag: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clearSearch() {
|
||||||
|
this.$emit('clearSearch')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.hashtags-filter.base-card {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: $space-x-small $space-base;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<div class="labeled-button">
|
||||||
|
<base-button circle :icon="icon" :filled="filled" @click="event => $emit('click', event)" />
|
||||||
|
<label class="label">{{ label }}</label>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
filled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.labeled-button {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 $space-x-small;
|
||||||
|
|
||||||
|
> .label {
|
||||||
|
margin-top: $space-x-small;
|
||||||
|
font-size: $font-size-small;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -30,12 +30,7 @@
|
|||||||
style="flex-grow: 0; flex-basis: auto;"
|
style="flex-grow: 0; flex-basis: auto;"
|
||||||
>
|
>
|
||||||
<client-only>
|
<client-only>
|
||||||
<filter-posts
|
<filter-menu v-show="showFilterMenuDropdown" placement="top-start" offset="8" />
|
||||||
v-show="showFilterPostsDropdown"
|
|
||||||
placement="top-start"
|
|
||||||
offset="8"
|
|
||||||
:categories="categories"
|
|
||||||
/>
|
|
||||||
</client-only>
|
</client-only>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
<ds-flex-item
|
<ds-flex-item
|
||||||
@ -85,8 +80,7 @@ import SearchField from '~/components/features/SearchField/SearchField.vue'
|
|||||||
import Modal from '~/components/Modal'
|
import Modal from '~/components/Modal'
|
||||||
import NotificationMenu from '~/components/NotificationMenu/NotificationMenu'
|
import NotificationMenu from '~/components/NotificationMenu/NotificationMenu'
|
||||||
import seo from '~/mixins/seo'
|
import seo from '~/mixins/seo'
|
||||||
import FilterPosts from '~/components/FilterPosts/FilterPosts.vue'
|
import FilterMenu from '~/components/FilterMenu/FilterMenu.vue'
|
||||||
import CategoryQuery from '~/graphql/CategoryQuery.js'
|
|
||||||
import PageFooter from '~/components/PageFooter/PageFooter'
|
import PageFooter from '~/components/PageFooter/PageFooter'
|
||||||
import AvatarMenu from '~/components/AvatarMenu/AvatarMenu'
|
import AvatarMenu from '~/components/AvatarMenu/AvatarMenu'
|
||||||
|
|
||||||
@ -97,7 +91,7 @@ export default {
|
|||||||
Modal,
|
Modal,
|
||||||
NotificationMenu,
|
NotificationMenu,
|
||||||
AvatarMenu,
|
AvatarMenu,
|
||||||
FilterPosts,
|
FilterMenu,
|
||||||
PageFooter,
|
PageFooter,
|
||||||
},
|
},
|
||||||
mixins: [seo],
|
mixins: [seo],
|
||||||
@ -105,36 +99,22 @@ export default {
|
|||||||
return {
|
return {
|
||||||
mobileSearchVisible: false,
|
mobileSearchVisible: false,
|
||||||
toggleMobileMenu: false,
|
toggleMobileMenu: false,
|
||||||
categories: [],
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
isLoggedIn: 'auth/isLoggedIn',
|
isLoggedIn: 'auth/isLoggedIn',
|
||||||
}),
|
}),
|
||||||
showFilterPostsDropdown() {
|
showFilterMenuDropdown() {
|
||||||
const [firstRoute] = this.$route.matched
|
const [firstRoute] = this.$route.matched
|
||||||
return firstRoute && firstRoute.name === 'index'
|
return firstRoute && firstRoute.name === 'index'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
Category(category) {
|
|
||||||
this.categories = category || []
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
toggleMobileMenuView() {
|
toggleMobileMenuView() {
|
||||||
this.toggleMobileMenu = !this.toggleMobileMenu
|
this.toggleMobileMenu = !this.toggleMobileMenu
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
apollo: {
|
|
||||||
Category: {
|
|
||||||
query() {
|
|
||||||
return CategoryQuery()
|
|
||||||
},
|
|
||||||
fetchPolicy: 'cache-and-network',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -331,12 +331,12 @@
|
|||||||
"post-not-found": "Dieser Beitrag konnte nicht gefunden werden",
|
"post-not-found": "Dieser Beitrag konnte nicht gefunden werden",
|
||||||
"profile-not-found": "Dieses Profil konnte nicht gefunden werden"
|
"profile-not-found": "Dieses Profil konnte nicht gefunden werden"
|
||||||
},
|
},
|
||||||
"filter-menu": {
|
"hashtags-filter": {
|
||||||
"clearSearch": "Suche löschen",
|
"clearSearch": "Suche löschen",
|
||||||
"hashtag-search": "Suche nach #{hashtag}",
|
"hashtag-search": "Suche nach #{hashtag}",
|
||||||
"title": "Deine Filterblase"
|
"title": "Deine Filterblase"
|
||||||
},
|
},
|
||||||
"filter-posts": {
|
"filter-menu": {
|
||||||
"categories": {
|
"categories": {
|
||||||
"all": "Alle",
|
"all": "Alle",
|
||||||
"header": "Themenkategorien"
|
"header": "Themenkategorien"
|
||||||
|
|||||||
@ -331,12 +331,12 @@
|
|||||||
"post-not-found": "This post could not be found",
|
"post-not-found": "This post could not be found",
|
||||||
"profile-not-found": "This profile could not be found"
|
"profile-not-found": "This profile could not be found"
|
||||||
},
|
},
|
||||||
"filter-menu": {
|
"hashtags-filter": {
|
||||||
"clearSearch": "Clear search",
|
"clearSearch": "Clear search",
|
||||||
"hashtag-search": "Searching for #{hashtag}",
|
"hashtag-search": "Searching for #{hashtag}",
|
||||||
"title": "Your filter bubble"
|
"title": "Your filter bubble"
|
||||||
},
|
},
|
||||||
"filter-posts": {
|
"filter-menu": {
|
||||||
"categories": {
|
"categories": {
|
||||||
"all": "All",
|
"all": "All",
|
||||||
"header": "Categories of Content"
|
"header": "Categories of Content"
|
||||||
|
|||||||
@ -329,12 +329,12 @@
|
|||||||
"post-not-found": "Esta contribución no se pudo encontrar",
|
"post-not-found": "Esta contribución no se pudo encontrar",
|
||||||
"profile-not-found": "Este perfil no se pudo encontrar"
|
"profile-not-found": "Este perfil no se pudo encontrar"
|
||||||
},
|
},
|
||||||
"filter-menu": {
|
"hashtags-filter": {
|
||||||
"clearSearch": "Borrar búsqueda",
|
"clearSearch": "Borrar búsqueda",
|
||||||
"hashtag-search": "Buscando a #{hashtag}",
|
"hashtag-search": "Buscando a #{hashtag}",
|
||||||
"title": "Su burbuja de filtro"
|
"title": "Su burbuja de filtro"
|
||||||
},
|
},
|
||||||
"filter-posts": {
|
"filter-menu": {
|
||||||
"categories": {
|
"categories": {
|
||||||
"all": "Todas",
|
"all": "Todas",
|
||||||
"header": "Categorías de contenido"
|
"header": "Categorías de contenido"
|
||||||
|
|||||||
@ -318,12 +318,12 @@
|
|||||||
},
|
},
|
||||||
"placeholder": "Écrivez quelque chose d'inspirant..."
|
"placeholder": "Écrivez quelque chose d'inspirant..."
|
||||||
},
|
},
|
||||||
"filter-menu": {
|
"hashtags-filter": {
|
||||||
"clearSearch": "Réinitialiser la recherche",
|
"clearSearch": "Réinitialiser la recherche",
|
||||||
"hashtag-search": "Recherche de #{hashtag}",
|
"hashtag-search": "Recherche de #{hashtag}",
|
||||||
"title": "Votre bulle de filtre"
|
"title": "Votre bulle de filtre"
|
||||||
},
|
},
|
||||||
"filter-posts": {
|
"filter-menu": {
|
||||||
"categories": {
|
"categories": {
|
||||||
"all": "Toutes",
|
"all": "Toutes",
|
||||||
"header": "Catégories de contenu"
|
"header": "Catégories de contenu"
|
||||||
|
|||||||
@ -323,12 +323,12 @@
|
|||||||
},
|
},
|
||||||
"placeholder": ""
|
"placeholder": ""
|
||||||
},
|
},
|
||||||
"filter-menu": {
|
"hashtags-filter": {
|
||||||
"clearSearch": "",
|
"clearSearch": "",
|
||||||
"hashtag-search": "",
|
"hashtag-search": "",
|
||||||
"title": ""
|
"title": ""
|
||||||
},
|
},
|
||||||
"filter-posts": {
|
"filter-menu": {
|
||||||
"categories": {
|
"categories": {
|
||||||
"all": "",
|
"all": "",
|
||||||
"header": ""
|
"header": ""
|
||||||
|
|||||||
@ -160,7 +160,7 @@
|
|||||||
"editor": {
|
"editor": {
|
||||||
"placeholder": "Napisz coś inspirującego..."
|
"placeholder": "Napisz coś inspirującego..."
|
||||||
},
|
},
|
||||||
"filter-menu": {
|
"hashtags-filter": {
|
||||||
"title": "Twoja bańka filtrująca"
|
"title": "Twoja bańka filtrująca"
|
||||||
},
|
},
|
||||||
"followButton": {
|
"followButton": {
|
||||||
|
|||||||
@ -314,12 +314,12 @@
|
|||||||
},
|
},
|
||||||
"placeholder": " Escreva algo inspirador…"
|
"placeholder": " Escreva algo inspirador…"
|
||||||
},
|
},
|
||||||
"filter-menu": {
|
"hashtags-filter": {
|
||||||
"clearSearch": "Limpar pesquisa",
|
"clearSearch": "Limpar pesquisa",
|
||||||
"hashtag-search": "Procurando por #{hashtag}",
|
"hashtag-search": "Procurando por #{hashtag}",
|
||||||
"title": "Sua bolha de filtro"
|
"title": "Sua bolha de filtro"
|
||||||
},
|
},
|
||||||
"filter-posts": {
|
"filter-menu": {
|
||||||
"categories": {
|
"categories": {
|
||||||
"all": "Todos",
|
"all": "Todos",
|
||||||
"header": "Categorias de Conteúdo"
|
"header": "Categorias de Conteúdo"
|
||||||
|
|||||||
@ -329,12 +329,12 @@
|
|||||||
"post-not-found": "Этот пост не удалось найти",
|
"post-not-found": "Этот пост не удалось найти",
|
||||||
"profile-not-found": "Этот профиль не удалось найти"
|
"profile-not-found": "Этот профиль не удалось найти"
|
||||||
},
|
},
|
||||||
"filter-menu": {
|
"hashtags-filter": {
|
||||||
"clearSearch": "Очистить поиск",
|
"clearSearch": "Очистить поиск",
|
||||||
"hashtag-search": "Поиск по #{hashtag}",
|
"hashtag-search": "Поиск по #{hashtag}",
|
||||||
"title": "Ваш фильтр пузыря"
|
"title": "Ваш фильтр пузыря"
|
||||||
},
|
},
|
||||||
"filter-posts": {
|
"filter-menu": {
|
||||||
"categories": {
|
"categories": {
|
||||||
"all": "Все",
|
"all": "Все",
|
||||||
"header": "Категории"
|
"header": "Категории"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { config, shallowMount, mount } from '@vue/test-utils'
|
import { config, shallowMount, mount } from '@vue/test-utils'
|
||||||
import PostIndex from './index.vue'
|
import PostIndex from './index.vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import FilterMenu from '~/components/FilterMenu/FilterMenu'
|
import FilterCard from '~/components/FilterCard/FilterCard'
|
||||||
|
|
||||||
const localVue = global.localVue
|
const localVue = global.localVue
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ describe('PostIndex', () => {
|
|||||||
it('clears the search when the filter menu emits clearSearch', () => {
|
it('clears the search when the filter menu emits clearSearch', () => {
|
||||||
mocks.$route.query.hashtag = '#samplehashtag'
|
mocks.$route.query.hashtag = '#samplehashtag'
|
||||||
wrapper = Wrapper()
|
wrapper = Wrapper()
|
||||||
wrapper.find(FilterMenu).vm.$emit('clearSearch')
|
wrapper.find(FilterCard).vm.$emit('clearSearch')
|
||||||
expect(wrapper.vm.hashtag).toBeNull()
|
expect(wrapper.vm.hashtag).toBeNull()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<masonry-grid>
|
<masonry-grid>
|
||||||
<ds-grid-item v-if="hashtag" :row-span="2" column-span="fullWidth">
|
<ds-grid-item v-if="hashtag" :row-span="2" column-span="fullWidth">
|
||||||
<filter-menu :hashtag="hashtag" @clearSearch="clearSearch" />
|
<hashtags-filter :hashtag="hashtag" @clearSearch="clearSearch" />
|
||||||
</ds-grid-item>
|
</ds-grid-item>
|
||||||
<ds-grid-item :row-span="2" column-span="fullWidth" class="top-info-bar">
|
<ds-grid-item :row-span="2" column-span="fullWidth" class="top-info-bar">
|
||||||
<!--<donation-info /> -->
|
<!--<donation-info /> -->
|
||||||
@ -65,7 +65,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
// import DonationInfo from '~/components/DonationInfo/DonationInfo.vue'
|
// import DonationInfo from '~/components/DonationInfo/DonationInfo.vue'
|
||||||
import FilterMenu from '~/components/FilterMenu/FilterMenu.vue'
|
import HashtagsFilter from '~/components/HashtagsFilter/HashtagsFilter.vue'
|
||||||
import HcEmpty from '~/components/Empty/Empty'
|
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'
|
||||||
@ -78,7 +78,7 @@ import UpdateQuery from '~/components/utils/UpdateQuery'
|
|||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
// DonationInfo,
|
// DonationInfo,
|
||||||
FilterMenu,
|
HashtagsFilter,
|
||||||
PostTeaser,
|
PostTeaser,
|
||||||
HcEmpty,
|
HcEmpty,
|
||||||
MasonryGrid,
|
MasonryGrid,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user