Upload group avatar on group profile page

This commit is contained in:
Wolfgang Huß 2022-09-06 09:14:28 +02:00
parent b96dfa84e0
commit 9b83b37ea3
8 changed files with 118 additions and 12 deletions

View File

@ -161,15 +161,17 @@ export const groupQuery = gql`
description description
groupType groupType
actionRadius actionRadius
myRole
categories { categories {
id id
slug slug
name name
icon icon
} }
# avatar # test this as result avatar {
url
}
# locationName # test this as result # locationName # test this as result
myRole
} }
} }
` `

View File

@ -31,7 +31,9 @@ export default {
return resolve(root, args, context, info) return resolve(root, args, context, info)
}, },
UpdateGroup: async (resolve, root, args, context, info) => { UpdateGroup: async (resolve, root, args, context, info) => {
if (args.name) {
args.slug = args.slug || (await uniqueSlug(args.name, isUniqueFor(context, 'Group'))) args.slug = args.slug || (await uniqueSlug(args.name, isUniqueFor(context, 'Group')))
}
return resolve(root, args, context, info) return resolve(root, args, context, info)
}, },
CreatePost: async (resolve, root, args, context, info) => { CreatePost: async (resolve, root, args, context, info) => {
@ -39,6 +41,7 @@ export default {
return resolve(root, args, context, info) return resolve(root, args, context, info)
}, },
UpdatePost: async (resolve, root, args, context, info) => { UpdatePost: async (resolve, root, args, context, info) => {
// TODO: is this absolutely correct, see condition in 'UpdateGroup' above? may it works accidentally, because args.slug is always send?
args.slug = args.slug || (await uniqueSlug(args.title, isUniqueFor(context, 'Post'))) args.slug = args.slug || (await uniqueSlug(args.title, isUniqueFor(context, 'Post')))
return resolve(root, args, context, info) return resolve(root, args, context, info)
}, },

View File

@ -137,6 +137,7 @@ export default {
const { categoryIds } = params const { categoryIds } = params
const { id: groupId, avatar: avatarInput } = params const { id: groupId, avatar: avatarInput } = params
delete params.categoryIds delete params.categoryIds
delete params.avatar
if (CONFIG.CATEGORIES_ACTIVE && categoryIds) { if (CONFIG.CATEGORIES_ACTIVE && categoryIds) {
if (categoryIds.length < CATEGORIES_MIN) { if (categoryIds.length < CATEGORIES_MIN) {
throw new UserInputError('Too view categories!') throw new UserInputError('Too view categories!')
@ -270,6 +271,9 @@ export default {
hasMany: { hasMany: {
categories: '-[:CATEGORIZED]->(related:Category)', categories: '-[:CATEGORIZED]->(related:Category)',
}, },
hasOne: {
avatar: '-[:AVATAR_IMAGE]->(related:Image)',
},
}), }),
}, },
} }

View File

@ -21,7 +21,6 @@
</template> </template>
<script> <script>
import vueDropzone from 'nuxt-dropzone' import vueDropzone from 'nuxt-dropzone'
import { updateUserMutation } from '~/graphql/User.js'
export default { export default {
name: 'AvatarUploader', name: 'AvatarUploader',
@ -29,7 +28,8 @@ export default {
vueDropzone, vueDropzone,
}, },
props: { props: {
profile: { type: Object, default: null }, profile: { type: Object, required: true },
updateMutation: { type: Object, required: true },
}, },
data() { data() {
return { return {
@ -69,7 +69,7 @@ export default {
const avatarUpload = file[0] const avatarUpload = file[0]
this.$apollo this.$apollo
.mutate({ .mutate({
mutation: updateUserMutation(), mutation: this.updateMutation,
variables: { variables: {
avatar: { avatar: {
upload: avatarUpload, upload: avatarUpload,

View File

@ -1,7 +1,7 @@
<template> <template>
<div :class="['profile-avatar', size && `--${this.size}`, !isAvatar && '--no-image']"> <div :class="['profile-avatar', size && `--${this.size}`, !isAvatar && '--no-image']">
<!-- '--no-image' is neccessary, because otherwise we still have a little unwanted boarder araund the image for images with white backgrounds --> <!-- '--no-image' is neccessary, because otherwise we still have a little unwanted boarder araund the image for images with white backgrounds -->
<span class="initials">{{ userInitials }}</span> <span class="initials">{{ profileInitials }}</span>
<base-icon v-if="isAnonymous" name="eye-slash" /> <base-icon v-if="isAnonymous" name="eye-slash" />
<img <img
v-if="isAvatar" v-if="isAvatar"
@ -38,7 +38,7 @@ export default {
// TODO may we could test as well if the image is reachable? otherwise the background gets white and the initails can not be read // TODO may we could test as well if the image is reachable? otherwise the background gets white and the initails can not be read
return this.profile && this.profile.avatar return this.profile && this.profile.avatar
}, },
userInitials() { profileInitials() {
if (this.isAnonymous) return '' if (this.isAnonymous) return ''
return this.profile.name.match(/\b\w/g).join('').substring(0, 3).toUpperCase() return this.profile.name.match(/\b\w/g).join('').substring(0, 3).toUpperCase()

View File

@ -12,6 +12,7 @@ export const createGroupMutation = gql`
$groupType: GroupType! $groupType: GroupType!
$actionRadius: GroupActionRadius! $actionRadius: GroupActionRadius!
$categoryIds: [ID] $categoryIds: [ID]
$locationName: String
) { ) {
CreateGroup( CreateGroup(
id: $id id: $id
@ -22,6 +23,7 @@ export const createGroupMutation = gql`
groupType: $groupType groupType: $groupType
actionRadius: $actionRadius actionRadius: $actionRadius
categoryIds: $categoryIds categoryIds: $categoryIds
locationName: $locationName
) { ) {
id id
name name
@ -34,11 +36,87 @@ export const createGroupMutation = gql`
description description
groupType groupType
actionRadius actionRadius
categories {
id
slug
name
icon
}
# locationName # test this as result
myRole myRole
} }
} }
` `
export const updateGroupMutation = gql`
mutation (
$id: ID!
$name: String
$slug: String
$about: String
$description: String
$actionRadius: GroupActionRadius
$categoryIds: [ID]
$avatar: ImageInput
$locationName: String
) {
UpdateGroup(
id: $id
name: $name
slug: $slug
about: $about
description: $description
actionRadius: $actionRadius
categoryIds: $categoryIds
avatar: $avatar
locationName: $locationName
) {
id
name
slug
createdAt
updatedAt
disabled
deleted
about
description
groupType
actionRadius
categories {
id
slug
name
icon
}
# avatar # test this as result
# locationName # test this as result
myRole
}
}
`
export const joinGroupMutation = gql`
mutation ($groupId: ID!, $userId: ID!) {
JoinGroup(groupId: $groupId, userId: $userId) {
id
name
slug
myRoleInGroup
}
}
`
export const changeGroupMemberRoleMutation = gql`
mutation ($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) {
ChangeGroupMemberRole(groupId: $groupId, userId: $userId, roleInGroup: $roleInGroup) {
id
name
slug
myRoleInGroup
}
}
`
// ------ queries // ------ queries
export const groupQuery = gql` export const groupQuery = gql`
@ -83,13 +161,28 @@ export const groupQuery = gql`
description description
groupType groupType
actionRadius actionRadius
myRole
categories { categories {
id id
slug slug
name name
icon icon
} }
avatar {
url
}
# locationName # test this as result
myRole
}
}
`
export const groupMembersQuery = gql`
query ($id: ID!, $first: Int, $offset: Int, $orderBy: [_UserOrdering], $filter: _UserFilter) {
GroupMembers(id: $id, first: $first, offset: $offset, orderBy: $orderBy, filter: $filter) {
id
name
slug
myRoleInGroup
} }
} }
` `

View File

@ -7,7 +7,7 @@
:class="{ 'disabled-content': group.disabled }" :class="{ 'disabled-content': group.disabled }"
style="position: relative; height: auto; overflow: visible" style="position: relative; height: auto; overflow: visible"
> >
<avatar-uploader v-if="isGroupOwner" :profile="group"> <avatar-uploader v-if="isGroupOwner" :profile="group" :updateMutation="updateGroupMutation">
<profile-avatar :profile="group" class="profile-page-avatar" size="large" /> <profile-avatar :profile="group" class="profile-page-avatar" size="large" />
</avatar-uploader> </avatar-uploader>
<profile-avatar v-else :profile="group" class="profile-page-avatar" size="large" /> <profile-avatar v-else :profile="group" class="profile-page-avatar" size="large" />
@ -187,6 +187,7 @@ import MasonryGridItem from '~/components/MasonryGrid/MasonryGridItem.vue'
import TabNavigation from '~/components/_new/generic/TabNavigation/TabNavigation' import TabNavigation from '~/components/_new/generic/TabNavigation/TabNavigation'
import { profilePagePosts } from '~/graphql/PostQuery' import { profilePagePosts } from '~/graphql/PostQuery'
import { groupQuery } from '~/graphql/groups' import { groupQuery } from '~/graphql/groups'
import { updateGroupMutation } from '~/graphql/groups.js'
import { muteUser, unmuteUser } from '~/graphql/settings/MutedUsers' import { muteUser, unmuteUser } from '~/graphql/settings/MutedUsers'
import { blockUser, unblockUser } from '~/graphql/settings/BlockedUsers' import { blockUser, unblockUser } from '~/graphql/settings/BlockedUsers'
import UpdateQuery from '~/components/utils/UpdateQuery' import UpdateQuery from '~/components/utils/UpdateQuery'
@ -236,6 +237,7 @@ export default {
followedByCountStartValue: 0, followedByCountStartValue: 0,
followedByCount: 7, followedByCount: 7,
followingCount: 7, followingCount: 7,
updateGroupMutation,
} }
}, },
computed: { computed: {
@ -413,7 +415,7 @@ export default {
// }, // },
Group: { Group: {
query() { query() {
// Wolle: return groupQuery(this.$i18n) // language will be needed for lacations // Wolle: return groupQuery(this.$i18n) // language will be needed for locations
return groupQuery return groupQuery
}, },
variables() { variables() {

View File

@ -7,7 +7,7 @@
:class="{ 'disabled-content': user.disabled }" :class="{ 'disabled-content': user.disabled }"
style="position: relative; height: auto; overflow: visible" style="position: relative; height: auto; overflow: visible"
> >
<avatar-uploader v-if="myProfile" :profile="user"> <avatar-uploader v-if="myProfile" :profile="user" :updateMutation="updateUserMutation">
<profile-avatar :profile="user" class="profile-page-avatar" size="large" /> <profile-avatar :profile="user" class="profile-page-avatar" size="large" />
</avatar-uploader> </avatar-uploader>
<profile-avatar v-else :profile="user" class="profile-page-avatar" size="large" /> <profile-avatar v-else :profile="user" class="profile-page-avatar" size="large" />
@ -185,6 +185,7 @@ import MasonryGridItem from '~/components/MasonryGrid/MasonryGridItem.vue'
import TabNavigation from '~/components/_new/generic/TabNavigation/TabNavigation' import TabNavigation from '~/components/_new/generic/TabNavigation/TabNavigation'
import { profilePagePosts } from '~/graphql/PostQuery' import { profilePagePosts } from '~/graphql/PostQuery'
import UserQuery from '~/graphql/User' import UserQuery from '~/graphql/User'
import { updateUserMutation } from '~/graphql/User.js'
import { muteUser, unmuteUser } from '~/graphql/settings/MutedUsers' import { muteUser, unmuteUser } from '~/graphql/settings/MutedUsers'
import { blockUser, unblockUser } from '~/graphql/settings/BlockedUsers' import { blockUser, unblockUser } from '~/graphql/settings/BlockedUsers'
import UpdateQuery from '~/components/utils/UpdateQuery' import UpdateQuery from '~/components/utils/UpdateQuery'
@ -232,6 +233,7 @@ export default {
followedByCountStartValue: 0, followedByCountStartValue: 0,
followedByCount: 7, followedByCount: 7,
followingCount: 7, followingCount: 7,
updateUserMutation: updateUserMutation(),
} }
}, },
computed: { computed: {