Refined list deletion functions and started writing custom mutation for DeleteComment and their tests

This commit is contained in:
Wolfgang Huß 2019-05-31 15:46:34 +02:00
parent b46016203a
commit 5bec0f1d72
9 changed files with 352 additions and 244 deletions

View File

@ -16,11 +16,15 @@ const isAdmin = rule()(async (parent, args, { user }, info) => {
return user && user.role === 'admin' return user && user.role === 'admin'
}) })
const isMyOwn = rule({ cache: 'no_cache' })(async (parent, args, context, info) => { const isMyOwn = rule({
cache: 'no_cache',
})(async (parent, args, context, info) => {
return context.user.id === parent.id return context.user.id === parent.id
}) })
const belongsToMe = rule({ cache: 'no_cache' })(async (_, args, context) => { const belongsToMe = rule({
cache: 'no_cache',
})(async (_, args, context) => {
const { const {
driver, driver,
user: { id: userId }, user: { id: userId },
@ -32,7 +36,10 @@ const belongsToMe = rule({ cache: 'no_cache' })(async (_, args, context) => {
MATCH (u:User {id: $userId})<-[:NOTIFIED]-(n:Notification {id: $notificationId}) MATCH (u:User {id: $userId})<-[:NOTIFIED]-(n:Notification {id: $notificationId})
RETURN n RETURN n
`, `,
{ userId, notificationId }, {
userId,
notificationId,
},
) )
const [notification] = result.records.map(record => { const [notification] = result.records.map(record => {
return record.get('n') return record.get('n')
@ -41,12 +48,16 @@ const belongsToMe = rule({ cache: 'no_cache' })(async (_, args, context) => {
return Boolean(notification) return Boolean(notification)
}) })
const onlyEnabledContent = rule({ cache: 'strict' })(async (parent, args, ctx, info) => { const onlyEnabledContent = rule({
cache: 'strict',
})(async (parent, args, ctx, info) => {
const { disabled, deleted } = args const { disabled, deleted } = args
return !(disabled || deleted) return !(disabled || deleted)
}) })
const isAuthor = rule({ cache: 'no_cache' })(async (parent, args, { user, driver }) => { const isAuthor = rule({
cache: 'no_cache',
})(async (parent, args, { user, driver }) => {
if (!user) return false if (!user) return false
const session = driver.session() const session = driver.session()
const { id: postId } = args const { id: postId } = args
@ -55,7 +66,9 @@ const isAuthor = rule({ cache: 'no_cache' })(async (parent, args, { user, driver
MATCH (post:Post {id: $postId})<-[:WROTE]-(author) MATCH (post:Post {id: $postId})<-[:WROTE]-(author)
RETURN author RETURN author
`, `,
{ postId }, {
postId,
},
) )
const [author] = result.records.map(record => { const [author] = result.records.map(record => {
return record.get('author') return record.get('author')
@ -100,6 +113,7 @@ const permissions = shield({
enable: isModerator, enable: isModerator,
disable: isModerator, disable: isModerator,
CreateComment: isAuthenticated, CreateComment: isAuthenticated,
DeleteComment: isAuthenticated,
// CreateUser: allow, // CreateUser: allow,
}, },
User: { User: {

View File

@ -53,6 +53,11 @@ export default {
) )
session.close() session.close()
return comment
},
DeleteComment: async (object, params, context, resolveInfo) => {
const socialMedia = await neo4jgraphql(object, params, context, resolveInfo, false)
return comment return comment
}, },
}, },

View File

@ -1,3 +1,4 @@
import gql from 'graphql-tag'
import Factory from '../seed/factories' import Factory from '../seed/factories'
import { GraphQLClient } from 'graphql-request' import { GraphQLClient } from 'graphql-request'
import { host, login } from '../jest/helpers' import { host, login } from '../jest/helpers'
@ -5,6 +6,7 @@ import { host, login } from '../jest/helpers'
const factory = Factory() const factory = Factory()
let client let client
let createCommentVariables let createCommentVariables
let deleteCommentVariables
let createPostVariables let createPostVariables
let createCommentVariablesSansPostId let createCommentVariablesSansPostId
let createCommentVariablesWithNonExistentPost let createCommentVariablesWithNonExistentPost
@ -21,22 +23,22 @@ afterEach(async () => {
}) })
describe('CreateComment', () => { describe('CreateComment', () => {
const createCommentMutation = ` const createCommentMutation = gql`
mutation($postId: ID, $content: String!) { mutation($postId: ID, $content: String!) {
CreateComment(postId: $postId, content: $content) { CreateComment(postId: $postId, content: $content) {
id id
content content
}
} }
}
` `
const createPostMutation = ` const createPostMutation = gql`
mutation($id: ID!, $title: String!, $content: String!) { mutation($id: ID!, $title: String!, $content: String!) {
CreatePost(id: $id, title: $title, content: $content) { CreatePost(id: $id, title: $title, content: $content) {
id id
}
} }
}
` `
const commentQueryForPostId = ` const commentQueryForPostId = gql`
query($content: String) { query($content: String) {
Comment(content: $content) { Comment(content: $content) {
postId postId
@ -59,8 +61,13 @@ describe('CreateComment', () => {
describe('authenticated', () => { describe('authenticated', () => {
let headers let headers
beforeEach(async () => { beforeEach(async () => {
headers = await login({ email: 'test@example.org', password: '1234' }) headers = await login({
client = new GraphQLClient(host, { headers }) email: 'test@example.org',
password: '1234',
})
client = new GraphQLClient(host, {
headers,
})
createCommentVariables = { createCommentVariables = {
postId: 'p1', postId: 'p1',
content: "I'm authorised to comment", content: "I'm authorised to comment",
@ -96,7 +103,15 @@ describe('CreateComment', () => {
} }
}`) }`)
expect(User).toEqual([{ comments: [{ content: "I'm authorised to comment" }] }]) expect(User).toEqual([
{
comments: [
{
content: "I'm authorised to comment",
},
],
},
])
}) })
it('throw an error if an empty string is sent from the editor as content', async () => { it('throw an error if an empty string is sent from the editor as content', async () => {
@ -186,7 +201,204 @@ describe('CreateComment', () => {
commentQueryForPostId, commentQueryForPostId,
commentQueryVariablesByContent, commentQueryVariablesByContent,
) )
expect(Comment).toEqual([{ postId: null }]) expect(Comment).toEqual([
{
postId: null,
},
])
}) })
}) })
}) })
// describe('DeleteComment', () => {
// const createCommentMutation = gql `
// mutation($postId: ID, $content: String!) {
// CreateComment(postId: $postId, content: $content) {
// id
// content
// }
// }
// `
// const deleteCommentMutation = gql `
// mutation($id: ID!) {
// DeleteComment(id: $id) {
// id
// content
// }
// }
// `
// const createPostMutation = gql `
// mutation($id: ID!, $title: String!, $content: String!) {
// CreatePost(id: $id, title: $title, content: $content) {
// id
// }
// }
// `
// const commentQueryForPostId = gql `
// query($content: String) {
// Comment(content: $content) {
// postId
// }
// }
// `
// describe('unauthenticated', () => {
// it('throws authorization error', async () => {
// deleteCommentVariables = {
// id: 'c1',
// }
// client = new GraphQLClient(host)
// await expect(client.request(deleteCommentMutation, deleteCommentVariables)).rejects.toThrow(
// 'Not Authorised',
// )
// })
// })
// // describe('authenticated', () => {
// // let headers
// // beforeEach(async () => {
// // headers = await login({
// // email: 'test@example.org',
// // password: '1234'
// // })
// // client = new GraphQLClient(host, {
// // headers
// // })
// // createCommentVariables = {
// // postId: 'p1',
// // content: "I'm authorised to comment",
// // }
// // createPostVariables = {
// // id: 'p1',
// // title: 'post to comment on',
// // content: 'please comment on me',
// // }
// // await client.request(createPostMutation, createPostVariables)
// // })
// // it('creates a comment', async () => {
// // const expected = {
// // CreateComment: {
// // content: "I'm authorised to comment",
// // },
// // }
// // await expect(
// // client.request(createCommentMutation, createCommentVariables),
// // ).resolves.toMatchObject(expected)
// // })
// // it('assigns the authenticated user as author', async () => {
// // await client.request(createCommentMutation, createCommentVariables)
// // const {
// // User
// // } = await client.request(`{
// // User(email: "test@example.org") {
// // comments {
// // content
// // }
// // }
// // }`)
// // expect(User).toEqual([{
// // comments: [{
// // content: "I'm authorised to comment"
// // }]
// // }])
// // })
// // it('throw an error if an empty string is sent from the editor as content', async () => {
// // createCommentVariables = {
// // postId: 'p1',
// // content: '<p></p>',
// // }
// // await expect(client.request(createCommentMutation, createCommentVariables)).rejects.toThrow(
// // 'Comment must be at least 1 character long!',
// // )
// // })
// // it('throws an error if a comment sent from the editor does not contain a single character', async () => {
// // createCommentVariables = {
// // postId: 'p1',
// // content: '<p> </p>',
// // }
// // await expect(client.request(createCommentMutation, createCommentVariables)).rejects.toThrow(
// // 'Comment must be at least 1 character long!',
// // )
// // })
// // it('throws an error if postId is sent as an empty string', async () => {
// // createCommentVariables = {
// // postId: 'p1',
// // content: '',
// // }
// // await expect(client.request(createCommentMutation, createCommentVariables)).rejects.toThrow(
// // 'Comment must be at least 1 character long!',
// // )
// // })
// // it('throws an error if content is sent as an string of empty characters', async () => {
// // createCommentVariables = {
// // postId: 'p1',
// // content: ' ',
// // }
// // await expect(client.request(createCommentMutation, createCommentVariables)).rejects.toThrow(
// // 'Comment must be at least 1 character long!',
// // )
// // })
// // it('throws an error if postId is sent as an empty string', async () => {
// // createCommentVariablesSansPostId = {
// // postId: '',
// // content: 'this comment should not be created',
// // }
// // await expect(
// // client.request(createCommentMutation, createCommentVariablesSansPostId),
// // ).rejects.toThrow('Comment cannot be created without a post!')
// // })
// // it('throws an error if postId is sent as an string of empty characters', async () => {
// // createCommentVariablesSansPostId = {
// // postId: ' ',
// // content: 'this comment should not be created',
// // }
// // await expect(
// // client.request(createCommentMutation, createCommentVariablesSansPostId),
// // ).rejects.toThrow('Comment cannot be created without a post!')
// // })
// // it('throws an error if the post does not exist in the database', async () => {
// // createCommentVariablesWithNonExistentPost = {
// // postId: 'p2',
// // content: "comment should not be created cause the post doesn't exist",
// // }
// // await expect(
// // client.request(createCommentMutation, createCommentVariablesWithNonExistentPost),
// // ).rejects.toThrow('Comment cannot be created without a post!')
// // })
// // it('does not create the comment with the postId as an attribute', async () => {
// // const commentQueryVariablesByContent = {
// // content: "I'm authorised to comment",
// // }
// // await client.request(createCommentMutation, createCommentVariables)
// // const {
// // Comment
// // } = await client.request(
// // commentQueryForPostId,
// // commentQueryVariablesByContent,
// // )
// // expect(Comment).toEqual([{
// // postId: null
// // }])
// // })
// // })
// })

View File

@ -1,8 +1,4 @@
import { import { config, shallowMount, createLocalVue } from '@vue/test-utils'
config,
shallowMount,
createLocalVue
} from '@vue/test-utils'
import Comment from './Comment.vue' import Comment from './Comment.vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import Styleguide from '@human-connection/styleguide' import Styleguide from '@human-connection/styleguide'
@ -25,6 +21,13 @@ describe('Comment.vue', () => {
propsData = {} propsData = {}
mocks = { mocks = {
$t: jest.fn(), $t: jest.fn(),
$toast: {
success: jest.fn(),
error: jest.fn(),
},
$apollo: {
mutate: jest.fn().mockResolvedValue(),
},
} }
getters = { getters = {
'auth/user': () => { 'auth/user': () => {
@ -76,12 +79,9 @@ describe('Comment.vue', () => {
}) })
it('translates a placeholder', () => { it('translates a placeholder', () => {
/* const wrapper = */ wrapper = Wrapper()
Wrapper()
const calls = mocks.$t.mock.calls const calls = mocks.$t.mock.calls
const expected = [ const expected = [['comment.content.unavailable-placeholder']]
['comment.content.unavailable-placeholder']
]
expect(calls).toEqual(expect.arrayContaining(expected)) expect(calls).toEqual(expect.arrayContaining(expected))
}) })
@ -121,10 +121,6 @@ describe('Comment.vue', () => {
expect(wrapper.emitted().deleteComment.length).toBe(1) expect(wrapper.emitted().deleteComment.length).toBe(1)
}) })
// it('does not go to index (main) page', () => {
// expect(mocks.$router.history.push).not.toHaveBeenCalled()
// })
it('does call mutation', () => { it('does call mutation', () => {
expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1) expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
}) })

View File

@ -1,18 +1,32 @@
<template> <template>
<dropdown class="content-menu" <dropdown
:placement="placement" offset="5"> class="content-menu"
<template slot="default" :placement="placement"
slot-scope="{toggleMenu}"> offset="5"
<slot name="button" >
:toggleMenu="toggleMenu"> <template
<ds-button class="content-menu-trigger" slot="default"
size="small" ghost @click.prevent="toggleMenu"> slot-scope="{toggleMenu}"
>
<slot
name="button"
:toggleMenu="toggleMenu"
>
<ds-button
class="content-menu-trigger"
size="small"
ghost
@click.prevent="toggleMenu"
>
<ds-icon name="ellipsis-v" /> <ds-icon name="ellipsis-v" />
</ds-button> </ds-button>
</slot> </slot>
</template> </template>
<div slot="popover" <div
slot-scope="{toggleMenu}" class="content-menu-popover"> slot="popover"
slot-scope="{toggleMenu}"
class="content-menu-popover"
>
<ds-menu :routes="routes"> <ds-menu :routes="routes">
<ds-menu-item <ds-menu-item
slot="menuitem" slot="menuitem"

View File

@ -22,7 +22,7 @@
v-for="(comment, index) in comments" v-for="(comment, index) in comments"
:key="comment.id" :key="comment.id"
:comment="comment" :comment="comment"
@deleteComment="deleteComment(index)" @deleteComment="comments.splice(index, 1)"
/> />
</div> </div>
<hc-empty <hc-empty
@ -65,9 +65,6 @@ export default {
this.$apollo.queries.Post.refetch() this.$apollo.queries.Post.refetch()
} }
}, },
deleteComment(index) {
this.comments.splice(index, 1)
},
}, },
apollo: { apollo: {
Post: { Post: {

View File

@ -1,10 +1,7 @@
<template> <template>
<div> <div>
<ds-flex <ds-flex v-if="Post && Post.length"
v-if="Post && Post.length" :width="{ base: '100%' }" gutter="base">
:width="{ base: '100%' }"
gutter="base"
>
<hc-post-card <hc-post-card
v-for="(post, index) in uniq(Post)" v-for="(post, index) in uniq(Post)"
:key="post.id" :key="post.id"
@ -23,11 +20,8 @@
primary primary
/> />
</no-ssr> </no-ssr>
<hc-load-more <hc-load-more v-if="true"
v-if="true" :loading="$apollo.loading" @click="showMoreContributions" />
:loading="$apollo.loading"
@click="showMoreContributions"
/>
</div> </div>
</template> </template>
@ -90,7 +84,8 @@ export default {
this.Post = this.Post.filter(post => { this.Post = this.Post.filter(post => {
return post.id !== postId return post.id !== postId
}) })
// Ideal solution: // Why "uniq(Post)" is used in the array for list creation?
// Ideal solution here:
// this.Post.splice(index, 1) // this.Post.splice(index, 1)
}, },
}, },

View File

@ -1,11 +1,13 @@
<template> <template>
<ds-card> <ds-card>
<h2 style="margin-bottom: .2em;"> <h2 style="margin-bottom: .2em;">
Mehr Informationen Mehr Informationen
</h2> </h2>
<p>Hier findest du weitere infos zum Thema.</p> <p>Hier findest du weitere infos zum Thema.</p>
<ds-space /> <ds-space />
<h3><ds-icon name="compass" /> Themenkategorien</h3> <h3>
<ds-icon name="compass" />Themenkategorien
</h3>
<div class="tags"> <div class="tags">
<ds-icon <ds-icon
v-for="category in post.categories" v-for="category in post.categories"
@ -16,39 +18,34 @@
/>&nbsp; />&nbsp;
<!--<ds-tag <!--<ds-tag
v-for="category in post.categories" v-for="category in post.categories"
:key="category.id"><ds-icon :name="category.icon" /> {{ category.name }}</ds-tag>--> :key="category.id"><ds-icon :name="category.icon" /> {{ category.name }}</ds-tag>-->
</div> </div>
<template v-if="post.tags && post.tags.length"> <template v-if="post.tags && post.tags.length">
<h3><ds-icon name="tags" /> Schlagwörter</h3> <h3>
<ds-icon name="tags" />Schlagwörter
</h3>
<div class="tags"> <div class="tags">
<ds-tag <ds-tag v-for="tag in post.tags"
v-for="tag in post.tags" :key="tag.id">
:key="tag.id" <ds-icon name="tag" />
> {{ tag.name }}
<ds-icon name="tag" /> {{ tag.name }}
</ds-tag> </ds-tag>
</div> </div>
</template> </template>
<h3>Verwandte Beiträge</h3> <h3>Verwandte Beiträge</h3>
<ds-section style="margin: 0 -1.5rem; padding: 1.5rem;"> <ds-section style="margin: 0 -1.5rem; padding: 1.5rem;">
<ds-flex <ds-flex v-if="post.relatedContributions && post.relatedContributions.length"
v-if="post.relatedContributions && post.relatedContributions.length" gutter="small">
gutter="small"
>
<hc-post-card <hc-post-card
v-for="(relatedPost, index) in post.relatedContributions" v-for="(relatedPost, index) in post.relatedContributions"
:key="relatedPost.id" :key="relatedPost.id"
:post="relatedPost" :post="relatedPost"
:width="{ base: '100%', lg: 1 }" :width="{ base: '100%', lg: 1 }"
@deletePost="deletePost(index)" @deletePost="post.relatedContributions.splice(index, 1)"
/> />
</ds-flex> </ds-flex>
<hc-empty <hc-empty v-else
v-else margin="large" icon="file" message="No related Posts" />
margin="large"
icon="file"
message="No related Posts"
/>
</ds-section> </ds-section>
<ds-space margin-bottom="large" /> <ds-space margin-bottom="large" />
</ds-card> </ds-card>
@ -73,11 +70,6 @@ export default {
return this.Post ? this.Post[0] || {} : {} return this.Post ? this.Post[0] || {} : {}
}, },
}, },
methods: {
deletePost(index) {
this.post.relatedContributions.splice(index, 1)
},
},
apollo: { apollo: {
Post: { Post: {
query() { query() {

View File

@ -3,27 +3,15 @@
<ds-card v-if="user && user.image"> <ds-card v-if="user && user.image">
<p>PROFILE IMAGE</p> <p>PROFILE IMAGE</p>
</ds-card> </ds-card>
<ds-space /> <ds-space/>
<ds-flex <ds-flex v-if="user" :width="{ base: '100%' }" gutter="base">
v-if="user"
:width="{ base: '100%' }"
gutter="base"
>
<ds-flex-item :width="{ base: '100%', sm: 2, md: 2, lg: 1 }"> <ds-flex-item :width="{ base: '100%', sm: 2, md: 2, lg: 1 }">
<ds-card <ds-card
:class="{'disabled-content': user.disabled}" :class="{'disabled-content': user.disabled}"
style="position: relative; height: auto;" style="position: relative; height: auto;"
> >
<hc-upload <hc-upload v-if="myProfile" :user="user"/>
v-if="myProfile" <hc-avatar v-else :user="user" class="profile-avatar" size="x-large"/>
:user="user"
/>
<hc-avatar
v-else
:user="user"
class="profile-avatar"
size="x-large"
/>
<no-ssr> <no-ssr>
<content-menu <content-menu
placement="bottom-end" placement="bottom-end"
@ -35,54 +23,32 @@
/> />
</no-ssr> </no-ssr>
<ds-space margin="small"> <ds-space margin="small">
<ds-heading <ds-heading tag="h3" align="center" no-margin>{{ userName }}</ds-heading>
tag="h3" <ds-text v-if="user.location" align="center" color="soft" size="small">
align="center" <ds-icon name="map-marker"/>
no-margin
>
{{ userName }}
</ds-heading>
<ds-text
v-if="user.location"
align="center"
color="soft"
size="small"
>
<ds-icon name="map-marker" />
{{ user.location.name }} {{ user.location.name }}
</ds-text> </ds-text>
<ds-text <ds-text
align="center" align="center"
color="soft" color="soft"
size="small" size="small"
> >{{ $t('profile.memberSince') }} {{ user.createdAt | date('MMMM yyyy') }}</ds-text>
{{ $t('profile.memberSince') }} {{ user.createdAt | date('MMMM yyyy') }}
</ds-text>
</ds-space> </ds-space>
<ds-space <ds-space v-if="user.badges && user.badges.length" margin="x-small">
v-if="user.badges && user.badges.length" <hc-badges :badges="user.badges"/>
margin="x-small"
>
<hc-badges :badges="user.badges" />
</ds-space> </ds-space>
<ds-flex> <ds-flex>
<ds-flex-item> <ds-flex-item>
<no-ssr> <no-ssr>
<ds-number :label="$t('profile.followers')"> <ds-number :label="$t('profile.followers')">
<hc-count-to <hc-count-to slot="count" :end-val="followedByCount"/>
slot="count"
:end-val="followedByCount"
/>
</ds-number> </ds-number>
</no-ssr> </no-ssr>
</ds-flex-item> </ds-flex-item>
<ds-flex-item> <ds-flex-item>
<no-ssr> <no-ssr>
<ds-number :label="$t('profile.following')"> <ds-number :label="$t('profile.following')">
<hc-count-to <hc-count-to slot="count" :end-val="Number(user.followingCount) || 0"/>
slot="count"
:end-val="Number(user.followingCount) || 0"
/>
</ds-number> </ds-number>
</no-ssr> </no-ssr>
</ds-flex-item> </ds-flex-item>
@ -98,136 +64,69 @@
</ds-space> </ds-space>
<template v-if="user.about"> <template v-if="user.about">
<hr> <hr>
<ds-space <ds-space margin-top="small" margin-bottom="small">
margin-top="small" <ds-text color="soft" size="small">{{ user.about }}</ds-text>
margin-bottom="small"
>
<ds-text
color="soft"
size="small"
>
{{ user.about }}
</ds-text>
</ds-space> </ds-space>
</template> </template>
</ds-card> </ds-card>
<ds-space /> <ds-space/>
<ds-heading <ds-heading tag="h3" soft style="text-align: center; margin-bottom: 10px;">Netzwerk</ds-heading>
tag="h3"
soft
style="text-align: center; margin-bottom: 10px;"
>
Netzwerk
</ds-heading>
<ds-card style="position: relative; height: auto;"> <ds-card style="position: relative; height: auto;">
<ds-space <ds-space v-if="user.following && user.following.length" margin="x-small">
v-if="user.following && user.following.length" <ds-text tag="h5" color="soft">Wem folgt {{ userName | truncate(15) }}?</ds-text>
margin="x-small"
>
<ds-text
tag="h5"
color="soft"
>
Wem folgt {{ userName | truncate(15) }}?
</ds-text>
</ds-space> </ds-space>
<template v-if="user.following && user.following.length"> <template v-if="user.following && user.following.length">
<ds-space <ds-space v-for="follow in uniq(user.following)" :key="follow.id" margin="x-small">
v-for="follow in uniq(user.following)"
:key="follow.id"
margin="x-small"
>
<!-- TODO: find better solution for rendering errors --> <!-- TODO: find better solution for rendering errors -->
<no-ssr> <no-ssr>
<user <user :user="follow" :trunc="15"/>
:user="follow"
:trunc="15"
/>
</no-ssr> </no-ssr>
</ds-space> </ds-space>
<ds-space <ds-space v-if="user.followingCount - user.following.length" margin="small">
v-if="user.followingCount - user.following.length"
margin="small"
>
<ds-text <ds-text
size="small" size="small"
color="softer" color="softer"
> >und {{ user.followingCount - user.following.length }} weitere</ds-text>
und {{ user.followingCount - user.following.length }} weitere
</ds-text>
</ds-space> </ds-space>
</template> </template>
<template v-else> <template v-else>
<p style="text-align: center; opacity: .5;"> <p style="text-align: center; opacity: .5;">{{ userName }} folgt niemandem</p>
{{ userName }} folgt niemandem
</p>
</template> </template>
</ds-card> </ds-card>
<ds-space /> <ds-space/>
<ds-card style="position: relative; height: auto;"> <ds-card style="position: relative; height: auto;">
<ds-space <ds-space v-if="user.followedBy && user.followedBy.length" margin="x-small">
v-if="user.followedBy && user.followedBy.length" <ds-text tag="h5" color="soft">Wer folgt {{ userName | truncate(15) }}?</ds-text>
margin="x-small"
>
<ds-text
tag="h5"
color="soft"
>
Wer folgt {{ userName | truncate(15) }}?
</ds-text>
</ds-space> </ds-space>
<template v-if="user.followedBy && user.followedBy.length"> <template v-if="user.followedBy && user.followedBy.length">
<ds-space <ds-space v-for="follow in uniq(user.followedBy)" :key="follow.id" margin="x-small">
v-for="follow in uniq(user.followedBy)"
:key="follow.id"
margin="x-small"
>
<!-- TODO: find better solution for rendering errors --> <!-- TODO: find better solution for rendering errors -->
<no-ssr> <no-ssr>
<user <user :user="follow" :trunc="15"/>
:user="follow"
:trunc="15"
/>
</no-ssr> </no-ssr>
</ds-space> </ds-space>
<ds-space <ds-space v-if="user.followedByCount - user.followedBy.length" margin="small">
v-if="user.followedByCount - user.followedBy.length"
margin="small"
>
<ds-text <ds-text
size="small" size="small"
color="softer" color="softer"
> >und {{ user.followedByCount - user.followedBy.length }} weitere</ds-text>
und {{ user.followedByCount - user.followedBy.length }} weitere
</ds-text>
</ds-space> </ds-space>
</template> </template>
<template v-else> <template v-else>
<p style="text-align: center; opacity: .5;"> <p style="text-align: center; opacity: .5;">niemand folgt {{ userName }}</p>
niemand folgt {{ userName }}
</p>
</template> </template>
</ds-card> </ds-card>
<ds-space <ds-space v-if="user.socialMedia && user.socialMedia.length" margin="large">
v-if="user.socialMedia && user.socialMedia.length"
margin="large"
>
<ds-card style="position: relative; height: auto;"> <ds-card style="position: relative; height: auto;">
<ds-space margin="x-small"> <ds-space margin="x-small">
<ds-text <ds-text
tag="h5" tag="h5"
color="soft" color="soft"
> >{{ $t('profile.socialMedia') }} {{ user.name | truncate(15) }}?</ds-text>
{{ $t('profile.socialMedia') }} {{ user.name | truncate(15) }}?
</ds-text>
<template> <template>
<ds-space <ds-space v-for="link in socialMediaLinks" :key="link.username" margin="x-small">
v-for="link in socialMediaLinks"
:key="link.username"
margin="x-small"
>
<a :href="link.url"> <a :href="link.url">
<ds-avatar :image="link.favicon" /> <ds-avatar :image="link.favicon"/>
{{ 'link.username' }} {{ 'link.username' }}
</a> </a>
</ds-space> </ds-space>
@ -237,10 +136,7 @@
</ds-space> </ds-space>
</ds-flex-item> </ds-flex-item>
<ds-flex-item :width="{ base: '100%', sm: 3, md: 5, lg: 3 }"> <ds-flex-item :width="{ base: '100%', sm: 3, md: 5, lg: 3 }">
<ds-flex <ds-flex :width="{ base: '100%' }" gutter="small">
:width="{ base: '100%' }"
gutter="small"
>
<ds-flex-item class="profile-top-navigation"> <ds-flex-item class="profile-top-navigation">
<ds-card class="ds-tab-nav"> <ds-card class="ds-tab-nav">
<ds-flex> <ds-flex>
@ -249,10 +145,7 @@
<!-- TODO: find better solution for rendering errors --> <!-- TODO: find better solution for rendering errors -->
<no-ssr> <no-ssr>
<ds-number :label="$t('common.post', null, user.contributionsCount)"> <ds-number :label="$t('common.post', null, user.contributionsCount)">
<hc-count-to <hc-count-to slot="count" :end-val="user.contributionsCount"/>
slot="count"
:end-val="user.contributionsCount"
/>
</ds-number> </ds-number>
</no-ssr> </no-ssr>
</ds-space> </ds-space>
@ -299,23 +192,16 @@
:key="post.id" :key="post.id"
:post="post" :post="post"
:width="{ base: '100%', md: '100%', xl: '50%' }" :width="{ base: '100%', md: '100%', xl: '50%' }"
@deletePost="deletePost(index)" @deletePost="user.contributions.splice(index, 1)"
/> />
</template> </template>
<template v-else> <template v-else>
<ds-flex-item :width="{ base: '100%' }"> <ds-flex-item :width="{ base: '100%' }">
<hc-empty <hc-empty margin="xx-large" icon="file"/>
margin="xx-large"
icon="file"
/>
</ds-flex-item> </ds-flex-item>
</template> </template>
</ds-flex> </ds-flex>
<hc-load-more <hc-load-more v-if="hasMore" :loading="$apollo.loading" @click="showMoreContributions"/>
v-if="hasMore"
:loading="$apollo.loading"
@click="showMoreContributions"
/>
</ds-flex-item> </ds-flex-item>
</ds-flex> </ds-flex>
</div> </div>
@ -440,9 +326,6 @@ export default {
fetchPolicy: 'cache-and-network', fetchPolicy: 'cache-and-network',
}) })
}, },
deletePost(index) {
this.user.contributions.splice(index, 1)
},
}, },
apollo: { apollo: {
User: { User: {