mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge pull request #1537 from Human-Connection/1455-fix-update-comment-list
🍰 Fixes a create and update comment problem in the comments list
This commit is contained in:
commit
fb2cade2f9
@ -33,7 +33,11 @@ describe('Comment.vue', () => {
|
|||||||
},
|
},
|
||||||
$apollo: {
|
$apollo: {
|
||||||
mutate: jest.fn().mockResolvedValue({
|
mutate: jest.fn().mockResolvedValue({
|
||||||
data: { DeleteComment: { id: 'it-is-the-deleted-comment' } },
|
data: {
|
||||||
|
DeleteComment: {
|
||||||
|
id: 'it-is-the-deleted-comment',
|
||||||
|
},
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -125,7 +129,11 @@ describe('Comment.vue', () => {
|
|||||||
|
|
||||||
it('emits "deleteComment"', () => {
|
it('emits "deleteComment"', () => {
|
||||||
expect(wrapper.emitted('deleteComment')).toEqual([
|
expect(wrapper.emitted('deleteComment')).toEqual([
|
||||||
[{ id: 'it-is-the-deleted-comment' }],
|
[
|
||||||
|
{
|
||||||
|
id: 'it-is-the-deleted-comment',
|
||||||
|
},
|
||||||
|
],
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -138,6 +146,30 @@ describe('Comment.vue', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('test update comment', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
wrapper = Wrapper()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with a given comment', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await wrapper.vm.updateComment({
|
||||||
|
id: 'it-is-the-updated-comment',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits "updateComment"', () => {
|
||||||
|
expect(wrapper.emitted('updateComment')).toEqual([
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: 'it-is-the-updated-comment',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -13,26 +13,29 @@
|
|||||||
<ds-card :id="`commentId-${comment.id}`">
|
<ds-card :id="`commentId-${comment.id}`">
|
||||||
<ds-space margin-bottom="small">
|
<ds-space margin-bottom="small">
|
||||||
<hc-user :user="author" :date-time="comment.createdAt" />
|
<hc-user :user="author" :date-time="comment.createdAt" />
|
||||||
|
<!-- Content Menu (can open Modals) -->
|
||||||
|
<client-only>
|
||||||
|
<content-menu
|
||||||
|
v-show="!openEditCommentMenu"
|
||||||
|
placement="bottom-end"
|
||||||
|
resource-type="comment"
|
||||||
|
:resource="comment"
|
||||||
|
:modalsData="menuModalsData"
|
||||||
|
style="float-right"
|
||||||
|
:is-owner="isAuthor(author.id)"
|
||||||
|
@showEditCommentMenu="editCommentMenu"
|
||||||
|
/>
|
||||||
|
</client-only>
|
||||||
</ds-space>
|
</ds-space>
|
||||||
<!-- Content Menu (can open Modals) -->
|
|
||||||
<client-only>
|
|
||||||
<content-menu
|
|
||||||
placement="bottom-end"
|
|
||||||
resource-type="comment"
|
|
||||||
:resource="comment"
|
|
||||||
:modalsData="menuModalsData"
|
|
||||||
style="float-right"
|
|
||||||
:is-owner="isAuthor(author.id)"
|
|
||||||
@showEditCommentMenu="editCommentMenu"
|
|
||||||
/>
|
|
||||||
</client-only>
|
|
||||||
|
|
||||||
<ds-space margin-bottom="small" />
|
<ds-space margin-bottom="small" />
|
||||||
<div v-if="openEditCommentMenu">
|
<div v-if="openEditCommentMenu">
|
||||||
<hc-edit-comment-form
|
<hc-comment-form
|
||||||
:comment="comment"
|
:update="true"
|
||||||
:post="post"
|
:post="post"
|
||||||
|
:comment="comment"
|
||||||
@showEditCommentMenu="editCommentMenu"
|
@showEditCommentMenu="editCommentMenu"
|
||||||
|
@updateComment="updateComment"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="!openEditCommentMenu">
|
<div v-show="!openEditCommentMenu">
|
||||||
@ -66,7 +69,7 @@ import { mapGetters } from 'vuex'
|
|||||||
import HcUser from '~/components/User/User'
|
import HcUser from '~/components/User/User'
|
||||||
import ContentMenu from '~/components/ContentMenu'
|
import ContentMenu from '~/components/ContentMenu'
|
||||||
import ContentViewer from '~/components/Editor/ContentViewer'
|
import ContentViewer from '~/components/Editor/ContentViewer'
|
||||||
import HcEditCommentForm from '~/components/EditCommentForm/EditCommentForm'
|
import HcCommentForm from '~/components/CommentForm/CommentForm'
|
||||||
import CommentMutations from '~/graphql/CommentMutations'
|
import CommentMutations from '~/graphql/CommentMutations'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -80,7 +83,7 @@ export default {
|
|||||||
HcUser,
|
HcUser,
|
||||||
ContentMenu,
|
ContentMenu,
|
||||||
ContentViewer,
|
ContentViewer,
|
||||||
HcEditCommentForm,
|
HcCommentForm,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
post: { type: Object, default: () => {} },
|
post: { type: Object, default: () => {} },
|
||||||
@ -136,6 +139,9 @@ export default {
|
|||||||
editCommentMenu(showMenu) {
|
editCommentMenu(showMenu) {
|
||||||
this.openEditCommentMenu = showMenu
|
this.openEditCommentMenu = showMenu
|
||||||
},
|
},
|
||||||
|
updateComment(comment) {
|
||||||
|
this.$emit('updateComment', comment)
|
||||||
|
},
|
||||||
async deleteCommentCallback() {
|
async deleteCommentCallback() {
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
|
|||||||
@ -12,8 +12,8 @@ describe('CommentForm.vue', () => {
|
|||||||
let mocks
|
let mocks
|
||||||
let wrapper
|
let wrapper
|
||||||
let propsData
|
let propsData
|
||||||
let cancelBtn
|
|
||||||
let cancelMethodSpy
|
let cancelMethodSpy
|
||||||
|
let closeMethodSpy
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mocks = {
|
mocks = {
|
||||||
@ -21,79 +21,180 @@ describe('CommentForm.vue', () => {
|
|||||||
$i18n: {
|
$i18n: {
|
||||||
locale: () => 'en',
|
locale: () => 'en',
|
||||||
},
|
},
|
||||||
$apollo: {
|
|
||||||
mutate: jest
|
|
||||||
.fn()
|
|
||||||
.mockResolvedValueOnce({
|
|
||||||
data: {
|
|
||||||
CreateComment: {
|
|
||||||
contentExcerpt: 'this is a comment',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.mockRejectedValue({
|
|
||||||
message: 'Ouch!',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
$toast: {
|
$toast: {
|
||||||
error: jest.fn(),
|
error: jest.fn(),
|
||||||
success: jest.fn(),
|
success: jest.fn(),
|
||||||
},
|
},
|
||||||
}
|
$filters: {
|
||||||
propsData = {
|
removeHtml: a => a,
|
||||||
post: {
|
|
||||||
id: 1,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('mount', () => {
|
describe('mount', () => {
|
||||||
const Wrapper = () => {
|
describe('create comment', () => {
|
||||||
return mount(CommentForm, {
|
beforeEach(() => {
|
||||||
mocks,
|
mocks = {
|
||||||
localVue,
|
...mocks,
|
||||||
propsData,
|
$apollo: {
|
||||||
|
mutate: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
data: {
|
||||||
|
CreateComment: {
|
||||||
|
contentExcerpt: 'this is a comment',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.mockRejectedValue({
|
||||||
|
message: 'Ouch!',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
propsData = {
|
||||||
|
post: {
|
||||||
|
id: 'p001',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(CommentForm, {
|
||||||
|
mocks,
|
||||||
|
localVue,
|
||||||
|
propsData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
wrapper = Wrapper()
|
||||||
|
cancelMethodSpy = jest.spyOn(wrapper.vm, 'clear')
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
it('calls the apollo mutation when form is submitted', async () => {
|
||||||
wrapper = Wrapper()
|
|
||||||
cancelMethodSpy = jest.spyOn(wrapper.vm, 'clear')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('calls the apollo mutation when form is submitted', async () => {
|
|
||||||
wrapper.vm.updateEditorContent('this is a comment')
|
|
||||||
await wrapper.find('form').trigger('submit')
|
|
||||||
expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('calls clear method when the cancel button is clicked', () => {
|
|
||||||
wrapper.vm.updateEditorContent('ok')
|
|
||||||
cancelBtn = wrapper.find('.cancelBtn')
|
|
||||||
cancelBtn.trigger('click')
|
|
||||||
expect(cancelMethodSpy).toHaveBeenCalledTimes(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('mutation resolves', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
wrapper.vm.updateEditorContent('this is a comment')
|
wrapper.vm.updateEditorContent('this is a comment')
|
||||||
wrapper.find('form').trigger('submit')
|
await wrapper.find('form').trigger('submit')
|
||||||
|
expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows a success toaster', async () => {
|
it('calls `clear` method when the cancel button is clicked', async () => {
|
||||||
await mocks.$apollo.mutate
|
wrapper.vm.updateEditorContent('ok')
|
||||||
expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
|
await wrapper.find('.cancelBtn').trigger('submit')
|
||||||
})
|
|
||||||
|
|
||||||
it('clears the editor', () => {
|
|
||||||
expect(cancelMethodSpy).toHaveBeenCalledTimes(1)
|
expect(cancelMethodSpy).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('mutation fails', () => {
|
describe('mutation resolves', () => {
|
||||||
it('shows the error toaster', async () => {
|
beforeEach(async () => {
|
||||||
await wrapper.find('form').trigger('submit')
|
wrapper.vm.updateEditorContent('this is a comment')
|
||||||
|
wrapper.find('form').trigger('submit')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows a success toaster', async () => {
|
||||||
await mocks.$apollo.mutate
|
await mocks.$apollo.mutate
|
||||||
expect(mocks.$toast.error).toHaveBeenCalledTimes(1)
|
expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('clears the editor', () => {
|
||||||
|
expect(cancelMethodSpy).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('mutation fails', () => {
|
||||||
|
it('shows the error toaster', async () => {
|
||||||
|
await wrapper.find('form').trigger('submit')
|
||||||
|
await mocks.$apollo.mutate
|
||||||
|
expect(mocks.$toast.error).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('update comment', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mocks = {
|
||||||
|
...mocks,
|
||||||
|
$apollo: {
|
||||||
|
mutate: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValueOnce({
|
||||||
|
data: {
|
||||||
|
UpdateComment: {
|
||||||
|
contentExcerpt: 'this is a comment',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.mockRejectedValue({
|
||||||
|
message: 'Ouch!',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
propsData = {
|
||||||
|
update: true,
|
||||||
|
comment: {
|
||||||
|
id: 'c001',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const Wrapper = () => {
|
||||||
|
return mount(CommentForm, {
|
||||||
|
mocks,
|
||||||
|
localVue,
|
||||||
|
propsData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
wrapper = Wrapper()
|
||||||
|
closeMethodSpy = jest.spyOn(wrapper.vm, 'closeEditWindow')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('form submitted', () => {
|
||||||
|
it('calls the apollo mutation', async () => {
|
||||||
|
wrapper.vm.updateEditorContent('this is a comment')
|
||||||
|
await wrapper.find('form').trigger('submit')
|
||||||
|
expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calls `closeEditWindow` method', async () => {
|
||||||
|
wrapper.vm.updateEditorContent('ok')
|
||||||
|
await wrapper.find('form').trigger('submit')
|
||||||
|
expect(closeMethodSpy).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits `showEditCommentMenu` event', async () => {
|
||||||
|
wrapper.vm.updateEditorContent('ok')
|
||||||
|
await wrapper.find('form').trigger('submit')
|
||||||
|
expect(wrapper.emitted('showEditCommentMenu')).toEqual([[false]])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('cancel button is clicked', () => {
|
||||||
|
it('calls `closeEditWindow` method', async () => {
|
||||||
|
wrapper.vm.updateEditorContent('ok')
|
||||||
|
await wrapper.find('.cancelBtn').trigger('submit')
|
||||||
|
expect(closeMethodSpy).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits `showEditCommentMenu` event', async () => {
|
||||||
|
wrapper.vm.updateEditorContent('ok')
|
||||||
|
await wrapper.find('.cancelBtn').trigger('submit')
|
||||||
|
expect(wrapper.emitted('showEditCommentMenu')).toEqual([[false]])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('mutation resolves', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
wrapper.vm.updateEditorContent('this is a comment')
|
||||||
|
wrapper.find('form').trigger('submit')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows a success toaster', async () => {
|
||||||
|
await mocks.$apollo.mutate
|
||||||
|
expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('closes the editor', () => {
|
||||||
|
expect(closeMethodSpy).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('mutation fails', () => {
|
||||||
|
it('shows the error toaster', async () => {
|
||||||
|
await wrapper.find('form').trigger('submit')
|
||||||
|
await mocks.$apollo.mutate
|
||||||
|
expect(mocks.$toast.error).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,18 +2,18 @@
|
|||||||
<ds-form v-model="form" @submit="handleSubmit">
|
<ds-form v-model="form" @submit="handleSubmit">
|
||||||
<template slot-scope="{ errors }">
|
<template slot-scope="{ errors }">
|
||||||
<ds-card>
|
<ds-card>
|
||||||
<hc-editor
|
<!-- with client-only the content is not shown -->
|
||||||
ref="editor"
|
<hc-editor ref="editor" :users="users" :value="form.content" @input="updateEditorContent" />
|
||||||
:users="users"
|
|
||||||
:hashtags="null"
|
|
||||||
:value="form.content"
|
|
||||||
@input="updateEditorContent"
|
|
||||||
/>
|
|
||||||
<ds-space />
|
<ds-space />
|
||||||
<ds-flex :gutter="{ base: 'small', md: 'small', sm: 'x-large', xs: 'x-large' }">
|
<ds-flex :gutter="{ base: 'small', md: 'small', sm: 'x-large', xs: 'x-large' }">
|
||||||
<ds-flex-item :width="{ base: '0%', md: '50%', sm: '0%', xs: '0%' }" />
|
<ds-flex-item :width="{ base: '0%', md: '50%', sm: '0%', xs: '0%' }" />
|
||||||
<ds-flex-item :width="{ base: '40%', md: '20%', sm: '30%', xs: '30%' }">
|
<ds-flex-item :width="{ base: '40%', md: '20%', sm: '30%', xs: '30%' }">
|
||||||
<ds-button :disabled="disabled" ghost class="cancelBtn" @click.prevent="clear">
|
<ds-button
|
||||||
|
:disabled="disabled && !update"
|
||||||
|
ghost
|
||||||
|
class="cancelBtn"
|
||||||
|
@click.prevent="handleCancel"
|
||||||
|
>
|
||||||
{{ $t('actions.cancel') }}
|
{{ $t('actions.cancel') }}
|
||||||
</ds-button>
|
</ds-button>
|
||||||
</ds-flex-item>
|
</ds-flex-item>
|
||||||
@ -29,9 +29,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import gql from 'graphql-tag'
|
|
||||||
import HcEditor from '~/components/Editor/Editor'
|
import HcEditor from '~/components/Editor/Editor'
|
||||||
import PostQuery from '~/graphql/PostQuery'
|
import { COMMENT_MIN_LENGTH } from '../../constants/comment'
|
||||||
|
import { minimisedUserQuery } from '~/graphql/User'
|
||||||
import CommentMutations from '~/graphql/CommentMutations'
|
import CommentMutations from '~/graphql/CommentMutations'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -39,55 +39,94 @@ export default {
|
|||||||
HcEditor,
|
HcEditor,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
update: { type: Boolean, default: () => false },
|
||||||
post: { type: Object, default: () => {} },
|
post: { type: Object, default: () => {} },
|
||||||
|
comment: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
loading: false,
|
loading: false,
|
||||||
form: {
|
form: {
|
||||||
content: '',
|
content: !this.update || !this.comment.content ? '' : this.comment.content,
|
||||||
},
|
},
|
||||||
users: [],
|
users: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateEditorContent(value) {
|
updateEditorContent(value) {
|
||||||
const content = value.replace(/<(?:.|\n)*?>/gm, '').trim()
|
const sanitizedContent = this.$filters.removeHtml(value, false)
|
||||||
if (content.length < 1) {
|
if (!this.update) {
|
||||||
this.disabled = true
|
if (sanitizedContent.length < COMMENT_MIN_LENGTH) {
|
||||||
|
this.disabled = true
|
||||||
|
} else {
|
||||||
|
this.disabled = false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.disabled = false
|
this.disabled =
|
||||||
|
value === this.comment.content || sanitizedContent.length < COMMENT_MIN_LENGTH
|
||||||
}
|
}
|
||||||
this.form.content = value
|
this.form.content = value
|
||||||
},
|
},
|
||||||
clear() {
|
clear() {
|
||||||
this.$refs.editor.clear()
|
this.$refs.editor.clear()
|
||||||
},
|
},
|
||||||
|
closeEditWindow() {
|
||||||
|
this.$emit('showEditCommentMenu', false)
|
||||||
|
},
|
||||||
|
handleCancel() {
|
||||||
|
if (!this.update) {
|
||||||
|
this.clear()
|
||||||
|
} else {
|
||||||
|
this.closeEditWindow()
|
||||||
|
}
|
||||||
|
},
|
||||||
handleSubmit() {
|
handleSubmit() {
|
||||||
this.loading = true
|
let mutateParams
|
||||||
this.disabled = true
|
if (!this.update) {
|
||||||
this.$apollo
|
mutateParams = {
|
||||||
.mutate({
|
|
||||||
mutation: CommentMutations(this.$i18n).CreateComment,
|
mutation: CommentMutations(this.$i18n).CreateComment,
|
||||||
variables: {
|
variables: {
|
||||||
postId: this.post.id,
|
postId: this.post.id,
|
||||||
content: this.form.content,
|
content: this.form.content,
|
||||||
},
|
},
|
||||||
update: async (store, { data: { CreateComment } }) => {
|
}
|
||||||
const data = await store.readQuery({
|
} else {
|
||||||
query: PostQuery(this.$i18n),
|
mutateParams = {
|
||||||
variables: { id: this.post.id },
|
mutation: CommentMutations(this.$i18n).UpdateComment,
|
||||||
})
|
variables: {
|
||||||
data.Post[0].comments.push(CreateComment)
|
id: this.comment.id,
|
||||||
await store.writeQuery({ query: PostQuery(this.$i18n), data })
|
content: this.form.content,
|
||||||
},
|
},
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = true
|
||||||
|
this.disabled = true
|
||||||
|
this.$apollo
|
||||||
|
.mutate(mutateParams)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.clear()
|
if (!this.update) {
|
||||||
this.$toast.success(this.$t('post.comment.submitted'))
|
const {
|
||||||
this.disabled = false
|
data: { CreateComment },
|
||||||
|
} = res
|
||||||
|
this.$emit('createComment', CreateComment)
|
||||||
|
this.clear()
|
||||||
|
this.$toast.success(this.$t('post.comment.submitted'))
|
||||||
|
this.disabled = false
|
||||||
|
} else {
|
||||||
|
const {
|
||||||
|
data: { UpdateComment },
|
||||||
|
} = res
|
||||||
|
this.$emit('updateComment', UpdateComment)
|
||||||
|
this.$toast.success(this.$t('post.comment.updated'))
|
||||||
|
this.disabled = false
|
||||||
|
this.closeEditWindow()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
this.$toast.error(err.message)
|
this.$toast.error(err.message)
|
||||||
@ -97,16 +136,7 @@ export default {
|
|||||||
apollo: {
|
apollo: {
|
||||||
User: {
|
User: {
|
||||||
query() {
|
query() {
|
||||||
return gql`
|
return minimisedUserQuery()
|
||||||
{
|
|
||||||
User(orderBy: slug_asc) {
|
|
||||||
id
|
|
||||||
slug
|
|
||||||
name
|
|
||||||
avatar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
},
|
},
|
||||||
result(result) {
|
result(result) {
|
||||||
this.users = result.data.User
|
this.users = result.data.User
|
||||||
|
|||||||
@ -22,7 +22,8 @@
|
|||||||
:key="comment.id"
|
:key="comment.id"
|
||||||
:comment="comment"
|
:comment="comment"
|
||||||
:post="post"
|
:post="post"
|
||||||
@deleteComment="deleteComment"
|
@deleteComment="updateCommentList"
|
||||||
|
@updateComment="updateCommentList"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<hc-empty v-else name="empty" icon="messages" />
|
<hc-empty v-else name="empty" icon="messages" />
|
||||||
@ -41,9 +42,9 @@ export default {
|
|||||||
post: { type: Object, default: () => {} },
|
post: { type: Object, default: () => {} },
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
deleteComment(deleted) {
|
updateCommentList(updatedComment) {
|
||||||
this.post.comments = this.post.comments.map(comment => {
|
this.post.comments = this.post.comments.map(comment => {
|
||||||
return comment.id === deleted.id ? deleted : comment
|
return comment.id === updatedComment.id ? updatedComment : comment
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,103 +0,0 @@
|
|||||||
<template>
|
|
||||||
<ds-form v-model="form" @submit="handleSubmit">
|
|
||||||
<template slot-scope="{ errors }">
|
|
||||||
<ds-card>
|
|
||||||
<!-- with client-only the content is not shown -->
|
|
||||||
<hc-editor ref="editor" :users="users" :value="form.content" @input="updateEditorContent" />
|
|
||||||
<ds-space />
|
|
||||||
<ds-flex :gutter="{ base: 'small', md: 'small', sm: 'x-large', xs: 'x-large' }">
|
|
||||||
<ds-flex-item :width="{ base: '0%', md: '50%', sm: '0%', xs: '0%' }" />
|
|
||||||
<ds-flex-item :width="{ base: '40%', md: '20%', sm: '30%', xs: '30%' }">
|
|
||||||
<ds-button ghost class="cancelBtn" @click.prevent="closeEditWindow">
|
|
||||||
{{ $t('actions.cancel') }}
|
|
||||||
</ds-button>
|
|
||||||
</ds-flex-item>
|
|
||||||
<ds-flex-item :width="{ base: '40%', md: '20%', sm: '40%', xs: '40%' }">
|
|
||||||
<ds-button type="submit" :loading="loading" :disabled="disabled || errors" primary>
|
|
||||||
{{ $t('post.comment.submit') }}
|
|
||||||
</ds-button>
|
|
||||||
</ds-flex-item>
|
|
||||||
</ds-flex>
|
|
||||||
</ds-card>
|
|
||||||
</template>
|
|
||||||
</ds-form>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import gql from 'graphql-tag'
|
|
||||||
import HcEditor from '~/components/Editor/Editor'
|
|
||||||
import CommentMutations from '~/graphql/CommentMutations.js'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: {
|
|
||||||
HcEditor,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
comment: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
disabled: true,
|
|
||||||
loading: false,
|
|
||||||
form: {
|
|
||||||
content: this.comment.content,
|
|
||||||
},
|
|
||||||
users: [],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
updateEditorContent(value) {
|
|
||||||
const sanitizedContent = value.replace(/<(?:.|\n)*?>/gm, '').trim()
|
|
||||||
this.disabled = value === this.comment.content || sanitizedContent.length < 1
|
|
||||||
this.form.content = value
|
|
||||||
},
|
|
||||||
closeEditWindow() {
|
|
||||||
this.$emit('showEditCommentMenu', false)
|
|
||||||
},
|
|
||||||
handleSubmit() {
|
|
||||||
this.loading = true
|
|
||||||
this.disabled = true
|
|
||||||
this.$apollo
|
|
||||||
.mutate({
|
|
||||||
mutation: CommentMutations(this.$i18n).UpdateComment,
|
|
||||||
variables: {
|
|
||||||
content: this.form.content,
|
|
||||||
id: this.comment.id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.loading = false
|
|
||||||
|
|
||||||
this.$toast.success(this.$t('post.comment.updated'))
|
|
||||||
this.disabled = false
|
|
||||||
this.$emit('showEditCommentMenu', false)
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
this.$toast.error(err.message)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
apollo: {
|
|
||||||
User: {
|
|
||||||
query() {
|
|
||||||
return gql`
|
|
||||||
{
|
|
||||||
User(orderBy: slug_asc) {
|
|
||||||
id
|
|
||||||
slug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
},
|
|
||||||
result({ data: { User } }) {
|
|
||||||
this.users = User
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
1
webapp/constants/comment.js
Normal file
1
webapp/constants/comment.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const COMMENT_MIN_LENGTH = 1
|
||||||
@ -77,6 +77,19 @@ export default i18n => {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const minimisedUserQuery = () => {
|
||||||
|
return gql`
|
||||||
|
query {
|
||||||
|
User(orderBy: slug_asc) {
|
||||||
|
id
|
||||||
|
slug
|
||||||
|
name
|
||||||
|
avatar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
export const notificationQuery = i18n => {
|
export const notificationQuery = i18n => {
|
||||||
const lang = i18n.locale().toUpperCase()
|
const lang = i18n.locale().toUpperCase()
|
||||||
return gql`
|
return gql`
|
||||||
|
|||||||
@ -68,7 +68,7 @@
|
|||||||
<ds-section slot="footer">
|
<ds-section slot="footer">
|
||||||
<hc-comment-list :post="post" />
|
<hc-comment-list :post="post" />
|
||||||
<ds-space margin-bottom="large" />
|
<ds-space margin-bottom="large" />
|
||||||
<hc-comment-form :post="post" />
|
<hc-comment-form :post="post" @createComment="createComment" />
|
||||||
</ds-section>
|
</ds-section>
|
||||||
</ds-card>
|
</ds-card>
|
||||||
</transition>
|
</transition>
|
||||||
@ -151,6 +151,9 @@ export default {
|
|||||||
this.$toast.error(err.message)
|
this.$toast.error(err.message)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async createComment(comment) {
|
||||||
|
this.post.comments.push(comment)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
apollo: {
|
apollo: {
|
||||||
Post: {
|
Post: {
|
||||||
|
|||||||
@ -83,10 +83,13 @@ export default ({ app = {} }) => {
|
|||||||
|
|
||||||
return excerpt
|
return excerpt
|
||||||
},
|
},
|
||||||
removeHtml: content => {
|
removeHtml: (content, replaceLinebreaks = true) => {
|
||||||
if (!content) return ''
|
if (!content) return ''
|
||||||
// replace linebreaks with spaces first
|
let contentExcerpt = content
|
||||||
let contentExcerpt = content.replace(/<br>/gim, ' ').trim()
|
if (replaceLinebreaks) {
|
||||||
|
// replace linebreaks with spaces first
|
||||||
|
contentExcerpt = contentExcerpt.replace(/<br>/gim, ' ').trim()
|
||||||
|
}
|
||||||
// remove the rest of the HTML
|
// remove the rest of the HTML
|
||||||
contentExcerpt = contentExcerpt.replace(/<(?:.|\n)*?>/gm, '').trim()
|
contentExcerpt = contentExcerpt.replace(/<(?:.|\n)*?>/gm, '').trim()
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user