diff --git a/backend/src/schema/resolvers/posts.spec.js b/backend/src/schema/resolvers/posts.spec.js
index 7c5e88d69..af2d8089c 100644
--- a/backend/src/schema/resolvers/posts.spec.js
+++ b/backend/src/schema/resolvers/posts.spec.js
@@ -91,7 +91,7 @@ afterEach(async () => {
})
describe('Post', () => {
- const postQuery = gql`
+ const postQueryFilteredByCategories = gql`
query Post($filter: _PostFilter) {
Post(filter: $filter) {
id
@@ -102,13 +102,28 @@ describe('Post', () => {
}
`
+ const postQueryFilteredByEmotions = gql`
+ query Post($filter: _PostFilter) {
+ Post(filter: $filter) {
+ id
+ emotions {
+ emotion
+ }
+ }
+ }
+ `
+
describe('can be filtered', () => {
- it('by categories', async () => {
- await Promise.all([
+ let post31, post32
+ beforeEach(async () => {
+ ;[post31, post32] = await Promise.all([
factory.create('Post', { id: 'p31', categoryIds: ['cat4'] }),
factory.create('Post', { id: 'p32', categoryIds: ['cat15'] }),
factory.create('Post', { id: 'p33', categoryIds: ['cat9'] }),
])
+ })
+
+ it('by categories', async () => {
const expected = {
data: {
Post: [
@@ -120,7 +135,50 @@ describe('Post', () => {
},
}
variables = { ...variables, filter: { categories_some: { id_in: ['cat9'] } } }
- await expect(query({ query: postQuery, variables })).resolves.toMatchObject(expected)
+ await expect(
+ query({ query: postQueryFilteredByCategories, variables }),
+ ).resolves.toMatchObject(expected)
+ })
+
+ it('by emotions', async () => {
+ const expected = {
+ data: {
+ Post: [
+ {
+ id: 'p31',
+ emotions: [{ emotion: 'happy' }],
+ },
+ ],
+ },
+ }
+ await user.relateTo(post31, 'emoted', { emotion: 'happy' })
+ variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy'] } } }
+ await expect(query({ query: postQueryFilteredByEmotions, variables })).resolves.toMatchObject(
+ expected,
+ )
+ })
+
+ it('supports filtering by multiple emotions', async () => {
+ const expected = [
+ {
+ id: 'p31',
+ emotions: [{ emotion: 'happy' }],
+ },
+ {
+ id: 'p32',
+ emotions: [{ emotion: 'cry' }],
+ },
+ ]
+ await user.relateTo(post31, 'emoted', { emotion: 'happy' })
+ await user.relateTo(post32, 'emoted', { emotion: 'cry' })
+ variables = { ...variables, filter: { emotions_some: { emotion_in: ['happy', 'cry'] } } }
+ await expect(query({ query: postQueryFilteredByEmotions, variables })).resolves.toMatchObject(
+ {
+ data: {
+ Post: expect.arrayContaining(expected),
+ },
+ },
+ )
})
})
})
diff --git a/backend/src/schema/types/type/EMOTED.gql b/backend/src/schema/types/type/EMOTED.gql
index cb8d37d62..ee1576517 100644
--- a/backend/src/schema/types/type/EMOTED.gql
+++ b/backend/src/schema/types/type/EMOTED.gql
@@ -3,8 +3,8 @@ type EMOTED @relation(name: "EMOTED") {
to: Post
emotion: Emotion
- #createdAt: DateTime
- #updatedAt: DateTime
+ # createdAt: DateTime
+ # updatedAt: DateTime
createdAt: String
updatedAt: String
}
@@ -15,6 +15,12 @@ input _EMOTEDInput {
updatedAt: String
}
+input _PostEMOTEDFilter {
+ emotion_in: [Emotion]
+ createdAt: String
+ updatedAt: String
+}
+
type Mutation {
AddPostEmotions(to: _PostInput!, data: _EMOTEDInput!): EMOTED
RemovePostEmotions(to: _PostInput!, data: _EMOTEDInput!): EMOTED
diff --git a/backend/src/seed/factories/posts.js b/backend/src/seed/factories/posts.js
index e81251c53..3058204a1 100644
--- a/backend/src/seed/factories/posts.js
+++ b/backend/src/seed/factories/posts.js
@@ -30,7 +30,7 @@ export default function create() {
let { categories, categoryIds } = args
delete args.categories
delete args.categoryIds
- if (categories && categoryIds) throw new Error('You provided both category and categoryIds')
+ if (categories && categoryIds) throw new Error('You provided both categories and categoryIds')
if (categoryIds)
categories = await Promise.all(categoryIds.map(id => neodeInstance.find('Category', id)))
categories = categories || (await Promise.all([factoryInstance.create('Category')]))
diff --git a/webapp/components/FilterPosts/FilterPostsMenuItems.vue b/webapp/components/FilterPosts/CategoriesFilterMenuItems.vue
similarity index 62%
rename from webapp/components/FilterPosts/FilterPostsMenuItems.vue
rename to webapp/components/FilterPosts/CategoriesFilterMenuItems.vue
index c761070b7..7a35bf3cc 100644
--- a/webapp/components/FilterPosts/FilterPostsMenuItems.vue
+++ b/webapp/components/FilterPosts/CategoriesFilterMenuItems.vue
@@ -1,6 +1,5 @@
-
-
+
-
-
-
-
-
-
-
+
diff --git a/webapp/components/FilterPosts/FilterPosts.spec.js b/webapp/components/FilterPosts/FilterPosts.spec.js
index 509ff32b7..0cbd3e962 100644
--- a/webapp/components/FilterPosts/FilterPosts.spec.js
+++ b/webapp/components/FilterPosts/FilterPosts.spec.js
@@ -19,6 +19,7 @@ describe('FilterPosts.vue', () => {
let allCategoriesButton
let environmentAndNatureButton
let democracyAndPoliticsButton
+ let happyEmotionButton
beforeEach(() => {
mocks = {
@@ -52,6 +53,7 @@ describe('FilterPosts.vue', () => {
'postsFilter/TOGGLE_FILTER_BY_FOLLOWED': jest.fn(),
'postsFilter/RESET_CATEGORIES': jest.fn(),
'postsFilter/TOGGLE_CATEGORY': jest.fn(),
+ 'postsFilter/TOGGLE_EMOTION': jest.fn(),
}
getters = {
'postsFilter/isActive': () => false,
@@ -61,6 +63,7 @@ describe('FilterPosts.vue', () => {
},
'postsFilter/filteredCategoryIds': jest.fn(() => []),
'postsFilter/filteredByUsersFollowed': jest.fn(),
+ 'postsFilter/filteredByEmotions': jest.fn(() => []),
}
const openFilterPosts = () => {
const store = new Vuex.Store({ mutations, getters })
@@ -120,5 +123,22 @@ describe('FilterPosts.vue', () => {
expect(mutations['postsFilter/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('button.emotions-buttons').at(1)
+ happyEmotionButton.trigger('click')
+ expect(mutations['postsFilter/TOGGLE_EMOTION']).toHaveBeenCalledWith({}, 'happy')
+ })
+
+ it('sets the attribute `src` to colorized image', () => {
+ getters['postsFilter/filteredByEmotions'] = jest.fn(() => ['happy'])
+ const wrapper = openFilterPosts()
+ happyEmotionButton = wrapper.findAll('button.emotions-buttons').at(1)
+ const happyEmotionButtonImage = happyEmotionButton.find('img')
+ expect(happyEmotionButtonImage.attributes().src).toEqual('/img/svg/emoji/happy_color.svg')
+ })
+ })
})
})
diff --git a/webapp/components/FilterPosts/FilterPosts.vue b/webapp/components/FilterPosts/FilterPosts.vue
index defc0eb0a..8a12ac633 100644
--- a/webapp/components/FilterPosts/FilterPosts.vue
+++ b/webapp/components/FilterPosts/FilterPosts.vue
@@ -11,20 +11,25 @@
-
+
+
+
+
+
diff --git a/webapp/pages/index.vue b/webapp/pages/index.vue
index 9b5c20977..361a7091c 100644
--- a/webapp/pages/index.vue
+++ b/webapp/pages/index.vue
@@ -27,12 +27,8 @@
-
- {{ $t('index.no-results') }}
-
-
- {{ $t('index.change-filter-settings') }}
-
+ {{ $t('index.no-results') }}
+ {{ $t('index.change-filter-settings') }}
diff --git a/webapp/store/postsFilter.js b/webapp/store/postsFilter.js
index 487194bae..964b265c0 100644
--- a/webapp/store/postsFilter.js
+++ b/webapp/store/postsFilter.js
@@ -40,6 +40,12 @@ export const mutations = {
if (isEmpty(get(filter, 'categories_some.id_in'))) delete filter.categories_some
state.filter = filter
},
+ TOGGLE_EMOTION(state, emotion) {
+ const filter = clone(state.filter)
+ update(filter, 'emotions_some.emotion_in', emotions => xor(emotions, [emotion]))
+ if (isEmpty(get(filter, 'emotions_some.emotion_in'))) delete filter.emotions_some
+ state.filter = filter
+ },
}
export const getters = {
@@ -55,4 +61,7 @@ export const getters = {
filteredByUsersFollowed(state) {
return !!get(state.filter, 'author.followedBy_some.id')
},
+ filteredByEmotions(state) {
+ return get(state.filter, 'emotions_some.emotion_in') || []
+ },
}
diff --git a/webapp/store/postsFilter.spec.js b/webapp/store/postsFilter.spec.js
index f06b4a31d..68a3dbd6e 100644
--- a/webapp/store/postsFilter.spec.js
+++ b/webapp/store/postsFilter.spec.js
@@ -43,6 +43,30 @@ describe('getters', () => {
expect(getters.filteredByUsersFollowed(state)).toBe(false)
})
})
+
+ describe('filteredByEmotions', () => {
+ it('returns an emotions array if filter is set', () => {
+ state = { filter: { emotions_some: { emotion_in: ['sad'] } } }
+ expect(getters.filteredByEmotions(state)).toEqual(['sad'])
+ })
+
+ it('returns an emotions array even when other filters are set', () => {
+ state = {
+ filter: { emotions_some: { emotion_in: ['sad'] }, categories_some: { id_in: [23] } },
+ }
+ expect(getters.filteredByEmotions(state)).toEqual(['sad'])
+ })
+
+ it('returns empty array if filter is not set', () => {
+ state = { filter: {} }
+ expect(getters.filteredByEmotions(state)).toEqual([])
+ })
+
+ it('returns empty array if another filter is set, but not emotions', () => {
+ state = { filter: { categories_some: { id_in: [23] } } }
+ expect(getters.filteredByEmotions(state)).toEqual([])
+ })
+ })
})
describe('mutations', () => {