feat(webapp): add reason and call to action on post view page if commenting is disabled (#8958)

Co-authored-by: Ulf Gebhardt <ulf.gebhardt@webcraft-media.de>
This commit is contained in:
Wolfgang Huß 2025-10-10 19:21:07 +02:00 committed by GitHub
parent 2a7d2f10ed
commit 558e964c83
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 897 additions and 449 deletions

View File

@ -0,0 +1,38 @@
import { shallowMount } from '@vue/test-utils'
import Component from './JoinLeaveButton.vue'
const localVue = global.localVue
describe('JoinLeaveButton.vue', () => {
let propsData, wrapper, mocks
beforeEach(() => {
propsData = {
group: {
id: 'g-1',
name: 'Group 1',
},
userId: 'u1',
isMember: false,
isNonePendingMember: false,
}
mocks = {
$t: jest.fn((t) => t),
}
})
const Wrapper = () => {
return shallowMount(Component, { propsData, localVue, mocks })
}
describe('shallowMount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('renders', () => {
expect(wrapper).toMatchSnapshot()
})
})
})

View File

@ -4,7 +4,7 @@
:disabled="disabled"
:loading="localLoading"
:icon="icon"
:filled="isMember && !hovered"
:filled="filled || (isMember && !hovered)"
:danger="isMember && hovered"
v-tooltip="tooltip"
@mouseenter.native="onHover"
@ -26,6 +26,7 @@ export default {
userId: { type: String, required: true },
isMember: { type: Boolean, required: true },
isNonePendingMember: { type: Boolean, required: true },
filled: { type: Boolean, default: false },
disabled: { type: Boolean, default: false },
loading: { type: Boolean, default: false },
},

View File

@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`JoinLeaveButton.vue shallowMount renders 1`] = `
<base-button-stub icon="plus" size="regular" type="button" class="join-leave-button has-tooltip" data-original-title="null">
group.joinLeaveButton.join
</base-button-stub>
`;

View File

@ -0,0 +1,79 @@
import { mount, RouterLinkStub } from '@vue/test-utils'
import Component from './CtaJoinLeaveGroup.vue'
const localVue = global.localVue
describe('CtaJoinLeaveGroup.vue', () => {
let propsData, wrapper, mocks, stubs
beforeEach(() => {
propsData = {
group: {
id: 'g-123',
slug: 'group-123',
name: 'Group 123',
myRole: null,
},
}
mocks = {
$t: jest.fn((t) => t),
$store: {
getters: {
'auth/user': {
id: 'u-1',
},
},
},
$apollo: {
mutate: jest.fn(),
},
}
stubs = {
NuxtLink: RouterLinkStub,
}
})
const Wrapper = () => {
return mount(Component, { propsData, localVue, mocks, stubs })
}
describe('mount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('renders', () => {
expect(wrapper).toMatchSnapshot()
})
describe('clicking on button', () => {
beforeEach(async () => {
mocks.$apollo.mutate = jest.fn().mockResolvedValue({
data: {
JoinGroup: {
id: 'g-123',
slug: 'group-123',
name: 'Group 123',
myRoleInGroup: 'usual',
},
},
})
wrapper.find('.base-button').trigger('click')
await wrapper.vm.$nextTick()
})
it('emits update event', async () => {
expect(wrapper.emitted().update).toEqual([
[
{
id: 'g-123',
slug: 'group-123',
name: 'Group 123',
myRoleInGroup: 'usual',
},
],
])
})
})
})
})

View File

@ -0,0 +1,64 @@
<template>
<ds-space centered margin="xxx-small">
<ds-space margin-bottom="small" />
<ds-heading tag="h4">
{{ $t('contribution.comment.commenting-disabled.no-group-member.reason') }}
<nuxt-link
:to="{
name: 'groups-id-slug',
params: { slug: group.slug, id: group.id },
}"
>
{{ group.name }}
</nuxt-link>
</ds-heading>
<ds-text>
{{ $t('contribution.comment.commenting-disabled.no-group-member.call-to-action') }}
</ds-text>
<join-leave-button
:group="group"
:userId="$store.getters['auth/user'].id"
:isMember="isGroupMember"
:isNonePendingMember="isGroupMemberNonePending"
:filled="true"
@update="updateJoinLeave"
/>
</ds-space>
</template>
<script>
import JoinLeaveButton from '~/components/Button/JoinLeaveButton'
export default {
name: 'CtaJoinLeaveGroup',
components: {
JoinLeaveButton,
},
props: {
group: {
type: Object,
require: true,
},
},
computed: {
isGroupMember() {
return this.group ? !!this.group.myRole : false
},
isGroupMemberNonePending() {
return this.group ? ['usual', 'admin', 'owner'].includes(this.group.myRole) : false
},
},
methods: {
async updateJoinLeave(data) {
this.$emit('update', data)
},
},
}
</script>
<style lang="scss" scoped>
.join-leave-button {
width: auto;
margin: auto !important;
}
</style>

View File

@ -0,0 +1,36 @@
import { shallowMount } from '@vue/test-utils'
import Component from './CtaUnblockAuthor.vue'
const localVue = global.localVue
describe('CtaUnblockAuthor.vue', () => {
let propsData, wrapper, mocks
beforeEach(() => {
propsData = {
author: {
id: 'u-123',
slug: 'user-123',
name: 'User 123',
},
}
mocks = {
$t: jest.fn((t) => t),
}
})
const Wrapper = () => {
return shallowMount(Component, { propsData, localVue, mocks })
}
describe('shallowMount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('renders', () => {
expect(wrapper).toMatchSnapshot()
})
})
})

View File

@ -0,0 +1,38 @@
<template>
<ds-space centered margin="xxx-small">
<ds-space margin-bottom="small" />
<ds-heading tag="h4">
{{ $t('contribution.comment.commenting-disabled.blocked-author.reason') }}
</ds-heading>
<ds-text>
{{ $t('contribution.comment.commenting-disabled.blocked-author.call-to-action') }}
</ds-text>
<nuxt-link :to="authorLink">
<base-button icon="arrow-right" filled>
{{
$t('contribution.comment.commenting-disabled.blocked-author.button-label', {
name: author.name,
})
}}
</base-button>
</nuxt-link>
</ds-space>
</template>
<script>
export default {
name: 'CtaUnblockAuthor',
props: {
author: {
type: Object,
require: true,
},
},
computed: {
authorLink() {
const { id, slug } = this.author
return { name: 'profile-id-slug', params: { slug, id } }
},
},
}
</script>

View File

@ -0,0 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CtaJoinLeaveGroup.vue mount renders 1`] = `
<div class="ds-space ds-space-centered" style="margin-top: 2px; margin-bottom: 2px;">
<div class="ds-space" style="margin-bottom: 16px;"></div>
<h4 class="ds-heading ds-heading-h4">
contribution.comment.commenting-disabled.no-group-member.reason
<a>
Group 123
</a>
</h4>
<p class="ds-text">
contribution.comment.commenting-disabled.no-group-member.call-to-action
</p> <button type="button" class="join-leave-button base-button --filled has-tooltip" data-original-title="null"><span class="base-icon"><!----></span>
<!---->
group.joinLeaveButton.join
</button>
</div>
`;

View File

@ -0,0 +1,18 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CtaUnblockAuthor.vue shallowMount renders 1`] = `
<ds-space-stub marginbottom="large" margin="xxx-small" centered="true" tag="div">
<ds-space-stub marginbottom="small" tag="div"></ds-space-stub>
<ds-heading-stub tag="h4">
contribution.comment.commenting-disabled.blocked-author.reason
</ds-heading-stub>
<ds-text-stub tag="p">
contribution.comment.commenting-disabled.blocked-author.call-to-action
</ds-text-stub>
<nuxt-link to="[object Object]">
<base-button-stub filled="true" icon="arrow-right" size="regular" type="button">
contribution.comment.commenting-disabled.blocked-author.button-label
</base-button-stub>
</nuxt-link>
</ds-space-stub>
`;

View File

@ -1,19 +1,22 @@
<template>
<ds-space class="hc-empty" centered :margin="margin">
<ds-text>
<img
:src="iconPath"
width="80"
class="hc-empty-icon"
style="margin-bottom: 5px"
alt="Empty"
/>
<br />
<ds-text v-show="message" class="hc-empty-message" color="softer">
{{ message }}
<div>
<ds-space class="hc-empty" centered :margin="margin">
<ds-text>
<img
:src="iconPath"
width="80"
class="hc-empty-icon"
style="margin-bottom: 5px"
alt="Empty"
/>
<br />
<ds-text v-show="message" class="hc-empty-message" color="softer">
{{ message }}
</ds-text>
</ds-text>
</ds-text>
</ds-space>
</ds-space>
<slot />
</div>
</template>
<script>

View File

@ -333,6 +333,19 @@
"spirituality": "Spiritualität"
}
},
"comment": {
"commenting-disabled": {
"blocked-author": {
"button-label": "Besuche „{name}“",
"call-to-action": "Möchtest du kommentieren, dann deblockiere ihn auf seinem Profil.",
"reason": "Du blockierst den Beitragsautor."
},
"no-group-member": {
"call-to-action": "Möchtest du kommentieren, dann trete der Gruppe bei.",
"reason": "Du bist kein Mitglied der Gruppe:"
}
}
},
"emotions-label": {
"angry": "Verärgert",
"cry": "Zum Weinen",
@ -824,6 +837,7 @@
},
"post": {
"comment": {
"joinGroup": "Gruppe „<b>{name}</b>“ beigetreten",
"reply": "Antworten",
"submit": "Kommentiere",
"submitted": "Kommentar gesendet",
@ -1017,7 +1031,6 @@
"explanation": {
"closing": "Das sollte fürs Erste genügen, damit blockierte Nutzer dich nicht mehr länger belästigen können.",
"commenting-disabled": "Du kannst den Beitrag derzeit nicht kommentieren.",
"commenting-explanation": "Dafür kann es mehrere Gründe geben, bitte schau in unsere ",
"intro": "Wenn ein anderer Nutzer durch dich blockiert wurde, dann passiert Folgendes:",
"notifications": "Von Dir blockierte Nutzer werden keine Benachrichtigungen mehr erhalten, falls sie in deinen Beiträgen erwähnt werden.",
"their-perspective": "Umgekehrt das gleiche: Die blockierte Person bekommt auch in ihren Benachrichtigungen deine Beiträge nicht mehr zu sehen.",

View File

@ -333,6 +333,19 @@
"spirituality": "Spirituality"
}
},
"comment": {
"commenting-disabled": {
"blocked-author": {
"button-label": "Visit “{name}”",
"call-to-action": "If you want to leave a comment, unblock them in their profile.",
"reason": "You are blocking the author of the post."
},
"no-group-member": {
"call-to-action": "If you want to comment, join the group.",
"reason": "You are not a member of the group:"
}
}
},
"emotions-label": {
"angry": "Angry",
"cry": "Cry",
@ -824,6 +837,7 @@
},
"post": {
"comment": {
"joinGroup": "Joined group „<b>{name}</b>“",
"reply": "Reply",
"submit": "Comment",
"submitted": "Comment submitted!",
@ -1016,8 +1030,7 @@
"empty": "So far, you have not blocked anybody.",
"explanation": {
"closing": "This should be sufficient for now so that blocked users can no longer bother you.",
"commenting-disabled": "Commenting is not possible at this time on this post.",
"commenting-explanation": "This can happen for several reasons, please see our ",
"commenting-disabled": "You cannot comment on this post at this time.",
"intro": "If another user has been blocked by you, this is what happens:",
"notifications": "Blocked users will no longer receive notifications if they mention each other.",
"their-perspective": "Vice versa: The blocked person will also no longer be able to interact with your contributions.",

View File

@ -333,6 +333,19 @@
"spirituality": null
}
},
"comment": {
"commenting-disabled": {
"blocked-author": {
"button-label": null,
"call-to-action": null,
"reason": null
},
"no-group-member": {
"call-to-action": null,
"reason": null
}
}
},
"emotions-label": {
"angry": "Enfadado",
"cry": "Llorar",
@ -824,6 +837,7 @@
},
"post": {
"comment": {
"joinGroup": null,
"reply": "Contestar",
"submit": "Comentario",
"submitted": "Comentario enviado",
@ -833,9 +847,6 @@
"title": null
},
"createNewEvent": {
"forGroup": {
"title": null
},
"title": null
},
"edited": "editado",
@ -1020,7 +1031,6 @@
"explanation": {
"closing": "Esto debería ser suficiente por ahora para que los usuarios bloqueados no puedan molestarle más.",
"commenting-disabled": "No es posible hacer comentarios en este momento en esta contribución",
"commenting-explanation": "Esto puede suceder por varias razones, por favor vea nuestra ",
"intro": "Si otro usuario ha sido bloqueado por usted, esto es lo que sucede:",
"notifications": "Los usuarios bloqueados no recibirán más notificaciones si se mencionan en sus contribuciones.",
"their-perspective": "Viceversa: la persona bloqueada tampoco verá más sus contribuciones en sus noticias.",

View File

@ -333,6 +333,19 @@
"spirituality": null
}
},
"comment": {
"commenting-disabled": {
"blocked-author": {
"button-label": null,
"call-to-action": null,
"reason": null
},
"no-group-member": {
"call-to-action": null,
"reason": null
}
}
},
"emotions-label": {
"angry": "En colère",
"cry": "Pleurer",
@ -824,6 +837,7 @@
},
"post": {
"comment": {
"joinGroup": null,
"reply": null,
"submit": "Commenté",
"submitted": "Commentaire soumis",
@ -833,9 +847,6 @@
"title": null
},
"createNewEvent": {
"forGroup": {
"title": null
},
"title": null
},
"edited": "édité",
@ -1020,7 +1031,6 @@
"explanation": {
"closing": "Ceci devrait être suffisant pour le moment afin que les utilisateurs bloqués ne puissent plus vous déranger.",
"commenting-disabled": null,
"commenting-explanation": null,
"intro": "Si vous avez bloqué un autre utilisateur, voici ce qui se passe:",
"notifications": "Les utilisateurs bloqués ne recevront plus de notifications s'ils sont mentionnés dans vos postes.",
"their-perspective": "Vice versa: la personne bloquée ne verra plus non plus vos postes dans son fil d'actualités.",

View File

@ -333,6 +333,19 @@
"spirituality": null
}
},
"comment": {
"commenting-disabled": {
"blocked-author": {
"button-label": null,
"call-to-action": null,
"reason": null
},
"no-group-member": {
"call-to-action": null,
"reason": null
}
}
},
"emotions-label": {
"angry": null,
"cry": null,
@ -824,6 +837,7 @@
},
"post": {
"comment": {
"joinGroup": null,
"reply": null,
"submit": null,
"submitted": null,
@ -833,9 +847,6 @@
"title": null
},
"createNewEvent": {
"forGroup": {
"title": null
},
"title": null
},
"edited": null,
@ -1020,7 +1031,6 @@
"explanation": {
"closing": null,
"commenting-disabled": null,
"commenting-explanation": null,
"intro": null,
"notifications": null,
"their-perspective": null,

View File

@ -333,6 +333,19 @@
"spirituality": null
}
},
"comment": {
"commenting-disabled": {
"blocked-author": {
"button-label": null,
"call-to-action": null,
"reason": null
},
"no-group-member": {
"call-to-action": null,
"reason": null
}
}
},
"emotions-label": {
"angry": null,
"cry": null,
@ -824,6 +837,7 @@
},
"post": {
"comment": {
"joinGroup": null,
"reply": null,
"submit": null,
"submitted": null,
@ -833,9 +847,6 @@
"title": null
},
"createNewEvent": {
"forGroup": {
"title": null
},
"title": null
},
"edited": null,
@ -1020,7 +1031,6 @@
"explanation": {
"closing": null,
"commenting-disabled": null,
"commenting-explanation": null,
"intro": null,
"notifications": null,
"their-perspective": null,

View File

@ -333,6 +333,19 @@
"spirituality": null
}
},
"comment": {
"commenting-disabled": {
"blocked-author": {
"button-label": null,
"call-to-action": null,
"reason": null
},
"no-group-member": {
"call-to-action": null,
"reason": null
}
}
},
"emotions-label": {
"angry": null,
"cry": null,
@ -824,6 +837,7 @@
},
"post": {
"comment": {
"joinGroup": null,
"reply": null,
"submit": "Komentarz",
"submitted": "Komentarz dodany",
@ -833,9 +847,6 @@
"title": null
},
"createNewEvent": {
"forGroup": {
"title": null
},
"title": null
},
"edited": null,
@ -1020,7 +1031,6 @@
"explanation": {
"closing": null,
"commenting-disabled": null,
"commenting-explanation": null,
"intro": null,
"notifications": null,
"their-perspective": null,

View File

@ -333,6 +333,19 @@
"spirituality": null
}
},
"comment": {
"commenting-disabled": {
"blocked-author": {
"button-label": null,
"call-to-action": null,
"reason": null
},
"no-group-member": {
"call-to-action": null,
"reason": null
}
}
},
"emotions-label": {
"angry": "Irritado",
"cry": "Chorando",
@ -824,6 +837,7 @@
},
"post": {
"comment": {
"joinGroup": null,
"reply": null,
"submit": "Commentar",
"submitted": "Comentário Enviado",
@ -833,9 +847,6 @@
"title": null
},
"createNewEvent": {
"forGroup": {
"title": null
},
"title": null
},
"edited": "editado",
@ -1020,7 +1031,6 @@
"explanation": {
"closing": "Isso deve ser suficiente por enquanto para que os usuários bloqueados não possam mais incomodá-lo.",
"commenting-disabled": null,
"commenting-explanation": null,
"intro": "Se outro usuário foi bloqueado por você, isto é o que acontece:",
"notifications": "Usuários bloqueados não receberão mais notificações se forem mencionados em suas mensagens.",
"their-perspective": "Vice versa: A pessoa bloqueada também não verá mais suas mensagens em seu feed de notícias.",

View File

@ -333,6 +333,19 @@
"spirituality": null
}
},
"comment": {
"commenting-disabled": {
"blocked-author": {
"button-label": null,
"call-to-action": null,
"reason": null
},
"no-group-member": {
"call-to-action": null,
"reason": null
}
}
},
"emotions-label": {
"angry": "Возмутительно",
"cry": "Плачу",
@ -824,6 +837,7 @@
},
"post": {
"comment": {
"joinGroup": null,
"reply": "Ответ",
"submit": "Комментировать",
"submitted": "Комментарий отправлен",
@ -833,9 +847,6 @@
"title": null
},
"createNewEvent": {
"forGroup": {
"title": null
},
"title": null
},
"edited": "Изменен",
@ -1020,7 +1031,6 @@
"explanation": {
"closing": "На данный момент этого должно быть достаточно, чтобы заблокированные пользователи больше вас не беспокоили.",
"commenting-disabled": "Комментировать этот пост на данный момент невозможно.",
"commenting-explanation": "Это может произойти по нескольким причинам, пожалуйста, смотрите наш",
"intro": "Если блокируете другого пользователя, происходит следующее:",
"notifications": "Заблокированные пользователи больше не будут получать уведомления об упоминаниях в ваших постах.",
"their-perspective": "И наоборот — заблокированный пользователь больше не видит ваши посты в своей ленте.",

View File

@ -933,32 +933,36 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
data-test="icon-empty"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -1401,32 +1405,36 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
data-test="icon-empty"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -1889,32 +1897,36 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
data-test="icon-empty"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -2841,32 +2853,36 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
data-test="icon-empty"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -3824,32 +3840,36 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
data-test="icon-empty"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -4625,32 +4645,36 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
data-test="icon-empty"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -5446,32 +5470,36 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
data-test="icon-empty"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -6358,32 +6386,36 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
data-test="icon-empty"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -7406,32 +7438,36 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a hidde
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
data-test="icon-empty"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -8395,32 +8431,36 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a hidde
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
data-test="icon-empty"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>

View File

@ -240,12 +240,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(peterLustig)
wrapper = Wrapper(() => {
return {
Group: [
{
...yogaPractice,
myRole: 'owner',
},
],
group: {
...yogaPractice,
myRole: 'owner',
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})
@ -280,12 +278,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(jennyRostock)
wrapper = Wrapper(() => {
return {
Group: [
{
...yogaPractice,
myRole: 'usual',
},
],
group: {
...yogaPractice,
myRole: 'usual',
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})
@ -301,12 +297,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(bobDerBaumeister)
wrapper = Wrapper(() => {
return {
Group: [
{
...yogaPractice,
myRole: 'pending',
},
],
group: {
...yogaPractice,
myRole: 'pending',
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})
@ -322,12 +316,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(huey)
wrapper = Wrapper(() => {
return {
Group: [
{
...yogaPractice,
myRole: null,
},
],
group: {
...yogaPractice,
myRole: null,
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})
@ -346,12 +338,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(peterLustig)
wrapper = Wrapper(() => {
return {
Group: [
{
...schoolForCitizens,
myRole: 'owner',
},
],
group: {
...schoolForCitizens,
myRole: 'owner',
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})
@ -367,12 +357,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(jennyRostock)
wrapper = Wrapper(() => {
return {
Group: [
{
...schoolForCitizens,
myRole: 'usual',
},
],
group: {
...schoolForCitizens,
myRole: 'usual',
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})
@ -411,12 +399,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(bobDerBaumeister)
wrapper = Wrapper(() => {
return {
Group: [
{
...schoolForCitizens,
myRole: 'pending',
},
],
group: {
...schoolForCitizens,
myRole: 'pending',
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})
@ -432,12 +418,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(huey)
wrapper = Wrapper(() => {
return {
Group: [
{
...schoolForCitizens,
myRole: null,
},
],
group: {
...schoolForCitizens,
myRole: null,
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})
@ -457,12 +441,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(peterLustig)
wrapper = Wrapper(() => {
return {
Group: [
{
...investigativeJournalism,
myRole: 'owner',
},
],
group: {
...investigativeJournalism,
myRole: 'owner',
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})
@ -478,12 +460,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(jennyRostock)
wrapper = Wrapper(() => {
return {
Group: [
{
...investigativeJournalism,
myRole: 'usual',
},
],
group: {
...investigativeJournalism,
myRole: 'usual',
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})
@ -499,12 +479,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(bobDerBaumeister)
wrapper = Wrapper(() => {
return {
Group: [
{
...investigativeJournalism,
myRole: 'pending',
},
],
group: {
...investigativeJournalism,
myRole: 'pending',
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})
@ -520,12 +498,10 @@ describe('GroupProfileSlug', () => {
currentUserMock.mockReturnValue(huey)
wrapper = Wrapper(() => {
return {
Group: [
{
...investigativeJournalism,
myRole: null,
},
],
group: {
...investigativeJournalism,
myRole: null,
},
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
}
})

View File

@ -352,15 +352,13 @@ export default {
membersCountToLoad: 25,
updateGroupMutation,
isDescriptionCollapsed: true,
group: {},
}
},
computed: {
...mapGetters({
currentUser: 'auth/user',
}),
group() {
return this.Group && this.Group[0] ? this.Group[0] : {}
},
groupName() {
const { name } = this.group || {}
return name || this.$t('profile.userAnonym')
@ -556,8 +554,8 @@ export default {
// "membersCountStartValue" is updated to avoid counting from 0 when join/leave
this.membersCountStartValue = (this.GroupMembers && this.GroupMembers.length) || 0
},
updateJoinLeave({ myRoleInGroup }) {
this.Group[0].myRole = myRoleInGroup
updateJoinLeave() {
this.$apollo.queries.Group.refetch()
if (this.isAllowedSeeingGroupMembers) {
this.$apollo.queries.GroupMembers.refetch()
} else {
@ -595,6 +593,9 @@ export default {
id: this.$route.params.id,
}
},
update({ Group }) {
this.group = Group && Group[0] ? Group[0] : {}
},
error(error) {
this.$toast.error(error.message)
},

View File

@ -125,27 +125,40 @@
@toggleObservePost="toggleObservePost"
/>
</div>
<!-- Comments -->
<!-- comments -->
<ds-section>
<!-- comment list -->
<comment-list
:post="post"
@toggleNewCommentForm="toggleNewCommentForm"
@reply="reply"
/>
<ds-space margin-bottom="large" />
<!-- commenting form -->
<comment-form
v-if="showNewCommentForm && !isBlocked && canCommentPost"
v-if="
showNewCommentForm &&
!isBlocked &&
(!this.post.group || commentingAllowedByGroupRole)
"
ref="commentForm"
:post="post"
@createComment="createComment"
/>
<ds-placeholder v-if="isBlocked">
{{ $t('settings.blocked-users.explanation.commenting-disabled') }}
<br />
{{ $t('settings.blocked-users.explanation.commenting-explanation') }}
<page-params-link :pageParams="links.FAQ">
{{ $t('site.faq') }}
</page-params-link>
<!-- commenting disabled -->
<ds-placeholder v-else>
<hc-empty
margin="xxx-small"
icon="messages"
:message="$t('settings.blocked-users.explanation.commenting-disabled')"
>
<cta-unblock-author v-if="isBlocked" :author="post.author" />
<cta-join-leave-group
v-else-if="!commentingAllowedByGroupRole"
:group="group"
@update="updateJoinLeave"
/>
</hc-empty>
</ds-placeholder>
</ds-section>
</base-card>
@ -160,23 +173,25 @@
<script>
import ContentViewer from '~/components/Editor/ContentViewer'
import HcCategory from '~/components/Category'
import HcHashtag from '~/components/Hashtag/Hashtag'
import CommentForm from '~/components/CommentForm/CommentForm'
import CommentList from '~/components/CommentList/CommentList'
import ContentMenu from '~/components/ContentMenu/ContentMenu'
import CtaUnblockAuthor from '~/components/Empty/CallToAction/CtaUnblockAuthor.vue'
import CtaJoinLeaveGroup from '~/components/Empty/CallToAction/CtaJoinLeaveGroup.vue'
import DateTimeRange from '~/components/DateTimeRange/DateTimeRange'
import UserTeaser from '~/components/UserTeaser/UserTeaser'
import ShoutButton from '~/components/ShoutButton.vue'
import ObserveButton from '~/components/ObserveButton.vue'
import HcCategory from '~/components/Category'
import HcEmpty from '~/components/Empty/Empty'
import HcHashtag from '~/components/Hashtag/Hashtag'
import LocationTeaser from '~/components/LocationTeaser/LocationTeaser'
import PageParamsLink from '~/components/_new/features/PageParamsLink/PageParamsLink.vue'
import ObserveButton from '~/components/ObserveButton.vue'
import ResponsiveImage from '~/components/ResponsiveImage/ResponsiveImage.vue'
import ShoutButton from '~/components/ShoutButton.vue'
import UserTeaser from '~/components/UserTeaser/UserTeaser'
import {
postMenuModalsData,
deletePostMutation,
sortTagsAlphabetically,
} from '~/components/utils/PostHelpers'
import ResponsiveImage from '~/components/ResponsiveImage/ResponsiveImage.vue'
import PostQuery from '~/graphql/PostQuery'
import { groupQuery } from '~/graphql/groups'
import PostMutations from '~/graphql/PostMutations'
@ -192,18 +207,20 @@ export default {
mode: 'out-in',
},
components: {
ContentMenu,
CommentForm,
CommentList,
ContentMenu,
ContentViewer,
CtaUnblockAuthor,
CtaJoinLeaveGroup,
DateTimeRange,
HcCategory,
HcEmpty,
HcHashtag,
ShoutButton,
ObserveButton,
LocationTeaser,
PageParamsLink,
ObserveButton,
ResponsiveImage,
ShoutButton,
UserTeaser,
},
mixins: [GetCategories, postListActions, SortCategories],
@ -298,10 +315,8 @@ export default {
'--hero-image-aspect-ratio': 1.0 / this.post.image.aspectRatio,
}
},
canCommentPost() {
return (
!this.post.group || (this.group && ['usual', 'admin', 'owner'].includes(this.group.myRole))
)
commentingAllowedByGroupRole() {
return this.group && ['usual', 'admin', 'owner'].includes(this.group.myRole)
},
},
methods: {
@ -343,6 +358,10 @@ export default {
toggleNewCommentForm(showNewCommentForm) {
this.showNewCommentForm = showNewCommentForm
},
updateJoinLeave() {
this.$apollo.queries.Group.refetch()
this.$toast.success(this.$t('post.comment.joinGroup', { name: this.post.group.name }))
},
},
apollo: {
Post: {
@ -378,6 +397,7 @@ export default {
skip() {
return !(this.post && this.post.group)
},
fetchPolicy: 'cache-and-network',
},
},
}

View File

@ -551,32 +551,35 @@ exports[`ProfileSlug given an authenticated user given another profile user and
<div
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div>
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -1229,32 +1232,35 @@ exports[`ProfileSlug given an authenticated user given another profile user and
<div
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div>
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -1808,32 +1814,35 @@ exports[`ProfileSlug given an authenticated user given the logged in user as pro
<div
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div>
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>
@ -2429,32 +2438,35 @@ exports[`ProfileSlug given an authenticated user given the logged in user as pro
<div
style="grid-row-end: span 4; grid-column-start: 1; grid-column-end: -1;"
>
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<p
class="ds-text"
<div>
<div
class="ds-space hc-empty ds-space-centered"
style="margin-top: 64px; margin-bottom: 64px;"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
<p
class="ds-text"
>
<img
alt="Empty"
class="hc-empty-icon"
src="/img/empty/file.svg"
style="margin-bottom: 5px;"
width="80"
/>
<br />
<span
class="ds-text hc-empty-message ds-text-softer ds-text-inline"
style="display: none;"
>
</span>
</p>
</span>
</p>
</div>
</div>
</div>
</div>