diff --git a/webapp/components/Comment.spec.js b/webapp/components/Comment.spec.js index e899a05e1..4fdc48bbd 100644 --- a/webapp/components/Comment.spec.js +++ b/webapp/components/Comment.spec.js @@ -25,6 +25,9 @@ describe('Comment.vue', () => { success: jest.fn(), error: jest.fn(), }, + $filters: { + truncate: a => a, + }, $apollo: { mutate: jest.fn().mockResolvedValue(), }, diff --git a/webapp/components/Comment.vue b/webapp/components/Comment.vue index 4796dd783..67bdb92a8 100644 --- a/webapp/components/Comment.vue +++ b/webapp/components/Comment.vue @@ -9,12 +9,13 @@ + @@ -59,6 +60,30 @@ export default { if (this.deleted) return {} return this.comment.author || {} }, + menuModalsData() { + return { + delete: { + titleIdent: 'delete.comment.title', + messageIdent: 'delete.comment.message', + messageParams: { + name: this.$filters.truncate(this.comment.contentExcerpt, 30), + }, + buttons: { + confirm: { + danger: true, + icon: 'trash', + textIdent: 'delete.submit', + callback: this.deleteCommentCallback, + }, + cancel: { + icon: 'close', + textIdent: 'delete.cancel', + callback: () => {}, + }, + }, + }, + } + }, }, methods: { isAuthor(id) { diff --git a/webapp/components/ContentMenu.vue b/webapp/components/ContentMenu.vue index 6b83b0bb9..935526867 100644 --- a/webapp/components/ContentMenu.vue +++ b/webapp/components/ContentMenu.vue @@ -43,7 +43,13 @@ export default { return value.match(/(contribution|comment|organization|user)/) }, }, - callbacks: { type: Object, required: true }, + modalsData: { + type: Object, + required: false, + // default: () => { + // return {} + // }, + }, }, computed: { routes() { @@ -145,7 +151,7 @@ export default { data: { type: this.resourceType, resource: this.resource, - callbacks: this.callbacks, + modalsData: this.modalsData, }, }) }, diff --git a/webapp/components/ContributionForm/index.vue b/webapp/components/ContributionForm/index.vue index f6bd9d38c..203c0963f 100644 --- a/webapp/components/ContributionForm/index.vue +++ b/webapp/components/ContributionForm/index.vue @@ -49,6 +49,7 @@ import gql from 'graphql-tag' import HcEditor from '~/components/Editor' import orderBy from 'lodash/orderBy' import locales from '~/locales' +import PostMutations from '~/graphql/PostMutations.js' export default { components: { @@ -106,11 +107,10 @@ export default { }, methods: { submit() { - const postMutations = require('~/graphql/PostMutations.js').default(this) this.loading = true this.$apollo .mutate({ - mutation: this.id ? postMutations.UpdatePost : postMutations.CreatePost, + mutation: this.id ? PostMutations().UpdatePost : PostMutations().CreatePost, variables: { id: this.id, title: this.form.title, diff --git a/webapp/components/Modal.spec.js b/webapp/components/Modal.spec.js index 0e2158e96..35ece0bee 100644 --- a/webapp/components/Modal.spec.js +++ b/webapp/components/Modal.spec.js @@ -1,6 +1,6 @@ import { shallowMount, createLocalVue } from '@vue/test-utils' import Modal from './Modal.vue' -import DeleteModal from './Modal/DeleteModal.vue' +import ConfirmModal from './Modal/ConfirmModal.vue' import DisableModal from './Modal/DisableModal.vue' import ReportModal from './Modal/ReportModal.vue' import Vuex from 'vuex' @@ -60,7 +60,7 @@ describe('Modal.vue', () => { it('initially empty', () => { wrapper = Wrapper() - expect(wrapper.contains(DeleteModal)).toBe(false) + expect(wrapper.contains(ConfirmModal)).toBe(false) expect(wrapper.contains(DisableModal)).toBe(false) expect(wrapper.contains(ReportModal)).toBe(false) }) @@ -75,10 +75,6 @@ describe('Modal.vue', () => { id: 'c456', title: 'some title', }, - callbacks: { - confirm: null, - cancel: null, - }, }, } wrapper = Wrapper() @@ -93,10 +89,6 @@ describe('Modal.vue', () => { type: 'contribution', name: 'some title', id: 'c456', - callbacks: { - confirm: null, - cancel: null, - }, }) }) @@ -117,20 +109,12 @@ describe('Modal.vue', () => { name: 'Author name', }, }, - callbacks: { - confirm: null, - cancel: null, - }, } wrapper = Wrapper() expect(wrapper.find(DisableModal).props()).toEqual({ type: 'comment', name: 'Author name', id: 'c456', - callbacks: { - confirm: null, - cancel: null, - }, }) }) @@ -140,20 +124,12 @@ describe('Modal.vue', () => { resource: { id: 'c456', }, - callbacks: { - confirm: null, - cancel: null, - }, } wrapper = Wrapper() expect(wrapper.find(DisableModal).props()).toEqual({ type: 'comment', name: '', id: 'c456', - callbacks: { - confirm: null, - cancel: null, - }, }) }) }) diff --git a/webapp/components/Modal.vue b/webapp/components/Modal.vue index 317b5007a..3c83a0922 100644 --- a/webapp/components/Modal.vue +++ b/webapp/components/Modal.vue @@ -6,7 +6,6 @@ :id="data.resource.id" :type="data.type" :name="name" - :callbacks="data.callbacks" @close="close" /> - diff --git a/webapp/components/PostCard/spec.js b/webapp/components/PostCard/spec.js deleted file mode 100644 index 8f818b26b..000000000 --- a/webapp/components/PostCard/spec.js +++ /dev/null @@ -1,61 +0,0 @@ -import { config, mount, createLocalVue, RouterLinkStub } from '@vue/test-utils' -import PostCard from '.' -import Styleguide from '@human-connection/styleguide' -import Vuex from 'vuex' -import Filters from '~/plugins/vue-filters' - -const localVue = createLocalVue() - -localVue.use(Vuex) -localVue.use(Styleguide) -localVue.use(Filters) - -config.stubs['no-ssr'] = '' -config.stubs['v-popover'] = '' - -describe('PostCard', () => { - let stubs - let mocks - let propsData - let getters - - beforeEach(() => { - propsData = {} - stubs = { - NuxtLink: RouterLinkStub, - } - mocks = { - $t: jest.fn(), - } - getters = { - 'auth/user': () => { - return {} - }, - } - }) - - const Wrapper = () => { - const store = new Vuex.Store({ - getters, - }) - return mount(PostCard, { - stubs, - mocks, - propsData, - store, - localVue, - }) - } - - describe('given a post', () => { - beforeEach(() => { - propsData.post = { - title: "It's a title", - } - }) - - it('renders title', () => { - expect(Wrapper().text()).toContain("It's a title") - }) - }) -}) diff --git a/webapp/components/ReleaseModal/ReleaseModal.vue b/webapp/components/ReleaseModal/ReleaseModal.vue index 79abe7765..dace3d665 100644 --- a/webapp/components/ReleaseModal/ReleaseModal.vue +++ b/webapp/components/ReleaseModal/ReleaseModal.vue @@ -40,6 +40,8 @@ export default { }, methods: { cancel() { + // TODO: Use the "modalData" structure introduced in "ConfirmModal" and refactor this here. Be aware that all the Jest tests have to be refactored as well !!! + // await this.modalData.buttons.cancel.callback() this.isOpen = false setTimeout(() => { this.$emit('close') @@ -47,6 +49,8 @@ export default { }, async confirm() { try { + // TODO: Use the "modalData" structure introduced in "ConfirmModal" and refactor this here. Be aware that all the Jest tests have to be refactored as well !!! + // await this.modalData.buttons.confirm.callback() await this.$apollo.mutate({ mutation: gql` mutation($id: ID!) { diff --git a/webapp/components/comments/CommentList/CommentList.spec.js b/webapp/components/comments/CommentList/CommentList.spec.js index c4ee0624c..b15e4f7d6 100644 --- a/webapp/components/comments/CommentList/CommentList.spec.js +++ b/webapp/components/comments/CommentList/CommentList.spec.js @@ -24,7 +24,9 @@ describe('CommentList.vue', () => { let data propsData = { - post: { id: 1 }, + post: { + id: 1, + }, } store = new Vuex.Store({ getters: { @@ -35,6 +37,9 @@ describe('CommentList.vue', () => { }) mocks = { $t: jest.fn(), + $filters: { + truncate: a => a, + }, $apollo: { queries: { Post: { @@ -51,13 +56,24 @@ describe('CommentList.vue', () => { describe('shallowMount', () => { const Wrapper = () => { - return mount(CommentList, { store, mocks, localVue, propsData, data }) + return mount(CommentList, { + store, + mocks, + localVue, + propsData, + data, + }) } beforeEach(() => { wrapper = Wrapper() wrapper.setData({ - comments: [{ id: 'c1', contentExcerpt: 'this is a comment' }], + comments: [ + { + id: 'c1', + contentExcerpt: 'this is a comment', + }, + ], }) }) diff --git a/webapp/components/utils/PostHelpers.js b/webapp/components/utils/PostHelpers.js new file mode 100644 index 000000000..5ff912a97 --- /dev/null +++ b/webapp/components/utils/PostHelpers.js @@ -0,0 +1,35 @@ +import PostMutations from '~/graphql/PostMutations.js' + +export function postMenuModalsData(truncatedPostName, confirmCallback, cancelCallback = () => {}) { + return { + delete: { + titleIdent: 'delete.contribution.title', + messageIdent: 'delete.contribution.message', + messageParams: { + name: truncatedPostName, + }, + buttons: { + confirm: { + danger: true, + icon: 'trash', + textIdent: 'delete.submit', + callback: confirmCallback, + }, + cancel: { + icon: 'close', + textIdent: 'delete.cancel', + callback: cancelCallback, + }, + }, + }, + } +} + +export function deletePostMutation(postId) { + return { + mutation: PostMutations().DeletePost, + variables: { + id: postId, + }, + } +} diff --git a/webapp/graphql/PostMutations.js b/webapp/graphql/PostMutations.js index 86b07c9b6..ad629bee7 100644 --- a/webapp/graphql/PostMutations.js +++ b/webapp/graphql/PostMutations.js @@ -1,8 +1,8 @@ import gql from 'graphql-tag' -export default app => { +export default () => { return { - CreatePost: gql(` + CreatePost: gql` mutation($title: String!, $content: String!, $language: String) { CreatePost(title: $title, content: $content, language: $language) { id @@ -13,8 +13,8 @@ export default app => { language } } - `), - UpdatePost: gql(` + `, + UpdatePost: gql` mutation($id: ID!, $title: String!, $content: String!, $language: String) { UpdatePost(id: $id, title: $title, content: $content, language: $language) { id @@ -25,6 +25,13 @@ export default app => { language } } - `), + `, + DeletePost: gql` + mutation($id: ID!) { + DeletePost(id: $id) { + id + } + } + `, } } diff --git a/webapp/locales/de.json b/webapp/locales/de.json index ac301f0e1..efe05a472 100644 --- a/webapp/locales/de.json +++ b/webapp/locales/de.json @@ -245,7 +245,7 @@ "comment": { "title": "Lösche Kommentar", "type": "Comment", - "message": "Bist du sicher, dass du den Kommentar von \"{name}\" löschen möchtest?", + "message": "Bist du sicher, dass du den Kommentar \"{name}\" löschen möchtest?", "success": "Kommentar erfolgreich gelöscht!" } }, diff --git a/webapp/locales/en.json b/webapp/locales/en.json index 2395ca8ca..4fdcadedb 100644 --- a/webapp/locales/en.json +++ b/webapp/locales/en.json @@ -245,7 +245,7 @@ "comment": { "title": "Delete Comment", "type": "Comment", - "message": "Do you really want to delete the comment from \"{name}\"?", + "message": "Do you really want to delete the comment \"{name}\"?", "success": "Comment successfully deleted!" } }, diff --git a/webapp/mixins/PostMutationHelpers.js b/webapp/mixins/PostMutationHelpers.js deleted file mode 100644 index 2e7a91e4d..000000000 --- a/webapp/mixins/PostMutationHelpers.js +++ /dev/null @@ -1,39 +0,0 @@ -import gql from 'graphql-tag' - -export default { - methods: { - async deletePostCallback(postDisplayType = 'list') { - // console.log('inside "deletePostCallback" !!! ', this.post) - try { - var gqlMutation = gql` - mutation($id: ID!) { - DeletePost(id: $id) { - id - } - } - ` - await this.$apollo.mutate({ - mutation: gqlMutation, - variables: { - id: this.post.id, - }, - }) - this.$toast.success(this.$t('delete.contribution.success')) - // console.log('called "this.$t" !!!') - switch (postDisplayType) { - case 'list': - this.$emit('deletePost') - // console.log('emitted "deletePost" !!!') - break - default: - // case 'page' - // console.log('called "this.$router.history.push" !!!') - this.$router.history.push('/') // Single page type: Redirect to index (main) page - break - } - } catch (err) { - this.$toast.error(err.message) - } - }, - }, -} diff --git a/webapp/pages/index.vue b/webapp/pages/index.vue index 2b8b1ff44..a18c80b9f 100644 --- a/webapp/pages/index.vue +++ b/webapp/pages/index.vue @@ -9,7 +9,7 @@ :key="post.id" :post="post" :width="{ base: '100%', xs: '100%', md: '50%', xl: '33%' }" - @deletePost="deletePost(index, post.id)" + @removePostFromList="deletePost(index, post.id)" /> diff --git a/webapp/pages/post/_id/_slug/index.spec.js b/webapp/pages/post/_id/_slug/index.spec.js index 5bf4ea168..33916c7a5 100644 --- a/webapp/pages/post/_id/_slug/index.spec.js +++ b/webapp/pages/post/_id/_slug/index.spec.js @@ -56,7 +56,7 @@ describe('PostSlug', () => { beforeEach(jest.useFakeTimers) - describe('test mixin "PostMutationHelpers"', () => { + describe('test Post callbacks', () => { beforeEach(() => { wrapper = Wrapper() wrapper.setData({ @@ -70,22 +70,14 @@ describe('PostSlug', () => { }) }) - describe('deletion of Post from Page by invoking "deletePostCallback(`page`)"', () => { + describe('deletion of Post from Page by invoking "deletePostCallback()"', () => { beforeEach(() => { - wrapper.vm.deletePostCallback('page') + wrapper.vm.deletePostCallback() }) describe('after timeout', () => { beforeEach(jest.runAllTimers) - it('not emits "deletePost"', () => { - expect(wrapper.emitted().deletePost).toBeFalsy() - }) - - it('does go to index (main) page', () => { - expect(mocks.$router.history.push).toHaveBeenCalledTimes(1) - }) - it('does call mutation', () => { expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1) }) @@ -93,6 +85,10 @@ describe('PostSlug', () => { it('mutation is successful', () => { expect(mocks.$toast.success).toHaveBeenCalledTimes(1) }) + + it('does go to index (main) page', () => { + expect(mocks.$router.history.push).toHaveBeenCalledTimes(1) + }) }) }) }) diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue index d2113dff7..5751f42b0 100644 --- a/webapp/pages/post/_id/_slug/index.vue +++ b/webapp/pages/post/_id/_slug/index.vue @@ -7,12 +7,13 @@ > + @@ -70,7 +71,7 @@ import HcUser from '~/components/User' import HcShoutButton from '~/components/ShoutButton.vue' import HcCommentForm from '~/components/comments/CommentForm' import HcCommentList from '~/components/comments/CommentList' -import PostMutationHelpers from '~/mixins/PostMutationHelpers' +import { postMenuModalsData, deletePostMutation } from '~/components/utils/PostHelpers' export default { name: 'PostSlug', @@ -87,7 +88,6 @@ export default { HcCommentForm, HcCommentList, }, - mixins: [PostMutationHelpers], head() { return { title: this.title, @@ -209,10 +209,28 @@ export default { this.ready = true }, 50) }, + computed: { + menuModalsData() { + return postMenuModalsData( + // "this.post" may not always be defined at the beginning … + this.post ? this.$filters.truncate(this.post.title, 30) : '', + this.deletePostCallback, + ) + }, + }, methods: { isAuthor(id) { return this.$store.getters['auth/user'].id === id }, + async deletePostCallback() { + try { + await this.$apollo.mutate(deletePostMutation(this.post.id)) + this.$toast.success(this.$t('delete.contribution.success')) + this.$router.history.push('/') // Redirect to index (main) page + } catch (err) { + this.$toast.error(err.message) + } + }, }, } diff --git a/webapp/pages/post/_id/_slug/more-info.vue b/webapp/pages/post/_id/_slug/more-info.vue index 1cb93ae6c..167926e95 100644 --- a/webapp/pages/post/_id/_slug/more-info.vue +++ b/webapp/pages/post/_id/_slug/more-info.vue @@ -1,8 +1,6 @@