mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge branch 'master' of github.com:Human-Connection/Human-Connection into 296-image_component-leftover
This commit is contained in:
commit
7fc8f2ecb7
@ -77,6 +77,13 @@ export default {
|
||||
}).href,
|
||||
icon: 'edit'
|
||||
})
|
||||
routes.push({
|
||||
name: this.$t(`post.delete.title`),
|
||||
callback: () => {
|
||||
this.openModal('delete')
|
||||
},
|
||||
icon: 'trash'
|
||||
})
|
||||
}
|
||||
if (this.isOwner && this.resourceType === 'comment') {
|
||||
routes.push({
|
||||
|
||||
@ -14,19 +14,28 @@
|
||||
:name="name"
|
||||
@close="close"
|
||||
/>
|
||||
<delete-modal
|
||||
v-if="open === 'delete'"
|
||||
:id="data.resource.id"
|
||||
:type="data.type"
|
||||
:name="name"
|
||||
@close="close"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DisableModal from '~/components/Modal/DisableModal'
|
||||
import ReportModal from '~/components/Modal/ReportModal'
|
||||
import DeleteModal from '~/components/Modal/DeleteModal'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Modal',
|
||||
components: {
|
||||
DisableModal,
|
||||
ReportModal
|
||||
ReportModal,
|
||||
DeleteModal
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
|
||||
155
webapp/components/Modal/DeleteModal.spec.js
Normal file
155
webapp/components/Modal/DeleteModal.spec.js
Normal file
@ -0,0 +1,155 @@
|
||||
import { shallowMount, mount, createLocalVue } from '@vue/test-utils'
|
||||
import DeleteModal from './DeleteModal.vue'
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import Styleguide from '@human-connection/styleguide'
|
||||
import VueRouter from 'vue-router'
|
||||
|
||||
const routes = [{ path: '/' }]
|
||||
const router = new VueRouter({ routes })
|
||||
const localVue = createLocalVue()
|
||||
|
||||
localVue.use(Vuex)
|
||||
localVue.use(Styleguide)
|
||||
localVue.use(VueRouter)
|
||||
|
||||
describe('DeleteModal.vue', () => {
|
||||
let wrapper
|
||||
let Wrapper
|
||||
let propsData
|
||||
let mocks
|
||||
|
||||
beforeEach(() => {
|
||||
propsData = {
|
||||
type: 'contribution',
|
||||
id: 'c300'
|
||||
}
|
||||
mocks = {
|
||||
$t: jest.fn(),
|
||||
$filters: {
|
||||
truncate: a => a
|
||||
},
|
||||
$toast: {
|
||||
success: () => {},
|
||||
error: () => {}
|
||||
},
|
||||
$apollo: {
|
||||
mutate: jest.fn().mockResolvedValue()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
describe('shallowMount', () => {
|
||||
const Wrapper = () => {
|
||||
return shallowMount(DeleteModal, { propsData, mocks, localVue, router })
|
||||
}
|
||||
|
||||
describe('defaults', () => {
|
||||
it('success false', () => {
|
||||
expect(Wrapper().vm.success).toBe(false)
|
||||
})
|
||||
|
||||
it('loading false', () => {
|
||||
expect(Wrapper().vm.loading).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('given a post', () => {
|
||||
beforeEach(() => {
|
||||
propsData = {
|
||||
id: 'p23',
|
||||
type: 'post',
|
||||
name: 'It is a post'
|
||||
}
|
||||
})
|
||||
|
||||
it('mentions post title', () => {
|
||||
Wrapper()
|
||||
const calls = mocks.$t.mock.calls
|
||||
const expected = [['post.delete.message', { name: 'It is a post' }]]
|
||||
expect(calls).toEqual(expect.arrayContaining(expected))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('mount', () => {
|
||||
const Wrapper = () => {
|
||||
return mount(DeleteModal, { propsData, mocks, localVue, router })
|
||||
}
|
||||
|
||||
beforeEach(jest.useFakeTimers)
|
||||
|
||||
it('renders', () => {
|
||||
expect(Wrapper().is('div')).toBe(true)
|
||||
})
|
||||
|
||||
describe('given id', () => {
|
||||
beforeEach(() => {
|
||||
propsData = {
|
||||
type: 'user',
|
||||
id: 'u3'
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
describe('click cancel button', () => {
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
wrapper.find('button.cancel').trigger('click')
|
||||
})
|
||||
|
||||
describe('after timeout', () => {
|
||||
beforeEach(jest.runAllTimers)
|
||||
|
||||
it('fades away', () => {
|
||||
expect(wrapper.vm.isOpen).toBe(false)
|
||||
})
|
||||
|
||||
it('emits "close"', () => {
|
||||
expect(wrapper.emitted().close).toBeTruthy()
|
||||
})
|
||||
|
||||
it('does not call mutation', () => {
|
||||
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('click confirm button', () => {
|
||||
beforeEach(() => {
|
||||
wrapper.find('button.confirm').trigger('click')
|
||||
})
|
||||
|
||||
it('calls delete mutation', () => {
|
||||
expect(mocks.$apollo.mutate).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('sets success', () => {
|
||||
expect(wrapper.vm.success).toBe(true)
|
||||
})
|
||||
|
||||
it('displays a success message', () => {
|
||||
const calls = mocks.$t.mock.calls
|
||||
const expected = [['post.delete.success']]
|
||||
expect(calls).toEqual(expect.arrayContaining(expected))
|
||||
})
|
||||
|
||||
describe('after timeout', () => {
|
||||
beforeEach(jest.runAllTimers)
|
||||
|
||||
it('fades away', () => {
|
||||
expect(wrapper.vm.isOpen).toBe(false)
|
||||
})
|
||||
|
||||
it('emits close', () => {
|
||||
expect(wrapper.emitted().close).toBeTruthy()
|
||||
})
|
||||
|
||||
it('resets success', () => {
|
||||
expect(wrapper.vm.success).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
134
webapp/components/Modal/DeleteModal.vue
Normal file
134
webapp/components/Modal/DeleteModal.vue
Normal file
@ -0,0 +1,134 @@
|
||||
<template>
|
||||
<ds-modal
|
||||
:title="title"
|
||||
:is-open="isOpen"
|
||||
@cancel="cancel"
|
||||
>
|
||||
<transition name="ds-transition-fade">
|
||||
<ds-flex
|
||||
v-if="success"
|
||||
class="hc-modal-success"
|
||||
centered
|
||||
>
|
||||
<sweetalert-icon icon="success" />
|
||||
</ds-flex>
|
||||
</transition>
|
||||
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<p v-html="message" />
|
||||
|
||||
<template
|
||||
slot="footer"
|
||||
>
|
||||
<ds-button
|
||||
class="cancel"
|
||||
icon="close"
|
||||
@click="cancel"
|
||||
>
|
||||
{{ $t('post.delete.cancel') }}
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
danger
|
||||
class="confirm"
|
||||
icon="trash"
|
||||
:loading="loading"
|
||||
@click="confirm"
|
||||
>
|
||||
{{ $t('post.delete.submit') }}
|
||||
</ds-button>
|
||||
</template>
|
||||
</ds-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import { SweetalertIcon } from 'vue-sweetalert-icons'
|
||||
|
||||
export default {
|
||||
name: 'DeleteModal',
|
||||
components: {
|
||||
SweetalertIcon
|
||||
},
|
||||
props: {
|
||||
name: { type: String, default: '' },
|
||||
type: { type: String, required: true },
|
||||
id: { type: String, required: true }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isOpen: true,
|
||||
success: false,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return this.$t(`post.delete.title`)
|
||||
},
|
||||
message() {
|
||||
const name = this.$filters.truncate(this.name, 30)
|
||||
return this.$t(`post.delete.message`, { name })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async cancel() {
|
||||
this.isOpen = false
|
||||
setTimeout(() => {
|
||||
this.$emit('close')
|
||||
}, 1000)
|
||||
},
|
||||
async confirm() {
|
||||
this.loading = true
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: gql`
|
||||
mutation($id: ID!) {
|
||||
DeletePost(id: $id) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: { id: this.id }
|
||||
})
|
||||
this.success = true
|
||||
this.$toast.success(this.$t('post.delete.success'))
|
||||
setTimeout(() => {
|
||||
this.isOpen = false
|
||||
setTimeout(() => {
|
||||
this.success = false
|
||||
this.$emit('close')
|
||||
if (this.$router.history.current.name === 'post-id-slug') {
|
||||
// redirect to index
|
||||
this.$router.history.push('/')
|
||||
} else {
|
||||
// reload the page (when deleting from profile or index)
|
||||
window.location.assign(window.location.href)
|
||||
}
|
||||
}, 500)
|
||||
}, 1500)
|
||||
} catch (err) {
|
||||
this.success = false
|
||||
this.$toast.error(err.message)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.hc-modal-success {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: #fff;
|
||||
opacity: 1;
|
||||
z-index: $z-index-modal;
|
||||
border-radius: $border-radius-x-large;
|
||||
}
|
||||
</style>
|
||||
@ -5,7 +5,7 @@
|
||||
>
|
||||
<ds-avatar
|
||||
style="display: inline-block; vertical-align: middle;"
|
||||
size="32px"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div style="display: inline-block; height: 100%; vertical-align: middle;">
|
||||
@ -40,7 +40,7 @@
|
||||
:image="user.avatar"
|
||||
:name="userName"
|
||||
style="display: inline-block; vertical-align: middle;"
|
||||
size="32px"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div style="display: inline-block; height: 100%; vertical-align: middle;">
|
||||
|
||||
@ -97,8 +97,8 @@ export default {
|
||||
})
|
||||
.then(res => {
|
||||
this.loading = false
|
||||
this.$root.$emit('refetchPostComments', res.data.CreateComment)
|
||||
this.$refs.editor.clear()
|
||||
this.$root.$emit('refetchPostComments')
|
||||
this.clear()
|
||||
this.$toast.success(this.$t('post.comment.submitted'))
|
||||
this.disabled = false
|
||||
})
|
||||
|
||||
92
webapp/components/comments/CommentForm/spec.js
Normal file
92
webapp/components/comments/CommentForm/spec.js
Normal file
@ -0,0 +1,92 @@
|
||||
import { config, mount, createLocalVue, createWrapper } from '@vue/test-utils'
|
||||
import CommentForm from './index.vue'
|
||||
import Vue from 'vue'
|
||||
import Styleguide from '@human-connection/styleguide'
|
||||
|
||||
const localVue = createLocalVue()
|
||||
|
||||
localVue.use(Styleguide)
|
||||
|
||||
config.stubs['no-ssr'] = '<span><slot /></span>'
|
||||
|
||||
describe('CommentForm.vue', () => {
|
||||
let mocks
|
||||
let wrapper
|
||||
let propsData
|
||||
let cancelBtn
|
||||
let cancelMethodSpy
|
||||
|
||||
beforeEach(() => {
|
||||
;(mocks = {
|
||||
$t: jest.fn(),
|
||||
$apollo: {
|
||||
mutate: jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce({
|
||||
data: { CreateComment: { contentExcerpt: 'this is a comment' } }
|
||||
})
|
||||
.mockRejectedValue({ message: 'Ouch!' })
|
||||
},
|
||||
$toast: {
|
||||
error: jest.fn(),
|
||||
success: jest.fn()
|
||||
}
|
||||
}),
|
||||
(propsData = {
|
||||
post: { id: 1 }
|
||||
})
|
||||
})
|
||||
|
||||
describe('mount', () => {
|
||||
const Wrapper = () => {
|
||||
return mount(CommentForm, { mocks, localVue, propsData })
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
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.find('form').trigger('submit')
|
||||
})
|
||||
|
||||
it('shows a success toaster', async () => {
|
||||
await mocks.$apollo.mutate
|
||||
expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('clears the editor', () => {
|
||||
expect(cancelMethodSpy).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('emits a method call with the returned comment', () => {
|
||||
const rootWrapper = createWrapper(wrapper.vm.$root)
|
||||
expect(rootWrapper.emitted().refetchPostComments.length).toEqual(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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -48,7 +48,7 @@
|
||||
<ds-avatar
|
||||
:image="user.avatar"
|
||||
:name="user.name"
|
||||
size="42"
|
||||
size="small"
|
||||
/>
|
||||
<ds-icon
|
||||
size="xx-small"
|
||||
|
||||
@ -135,6 +135,14 @@
|
||||
"takeAction": {
|
||||
"name": "Take action"
|
||||
},
|
||||
"delete": {
|
||||
"submit": "Delete",
|
||||
"cancel": "Cancel",
|
||||
"success": "Post deleted successfully",
|
||||
"title": "Delete Post",
|
||||
"type": "Contribution",
|
||||
"message": "Do you really want to delete the post \"<b>{name}</b>\"?"
|
||||
},
|
||||
"comment": {
|
||||
"submit": "Comment",
|
||||
"submitted": "Comment Submitted"
|
||||
|
||||
@ -88,6 +88,14 @@
|
||||
},
|
||||
"takeAction": {
|
||||
"name": "Tomar acción"
|
||||
},
|
||||
"delete": {
|
||||
"submit": "Borrar",
|
||||
"cancel": "Cancelar",
|
||||
"success": "Mensaje borrado satisfactoriamente",
|
||||
"title": "Borrar mensaje",
|
||||
"type": "Mensaje",
|
||||
"message": "¿Realmente quieres borrar el mensaje \"<b>{name}</b>\"?"
|
||||
}
|
||||
},
|
||||
"quotes": {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user