Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 🍰 Implement Group Profile #5197

Merged
merged 22 commits into from
Sep 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
91d797d
Copy profile Vue pages for the group profile
Tirokk Aug 22, 2022
e1f4609
!!! Temp !!!
Tirokk Aug 23, 2022
623af5f
Query for group 'id' directly in resolver
Tirokk Aug 29, 2022
3948777
Implement group profile, first step
Tirokk Aug 29, 2022
23512c6
Merge branch '5059-groups/5190-group-profile' of github.com:Ocelot-So…
Tirokk Aug 29, 2022
6280fa9
Merge branch 'master' of github.com:Ocelot-Social-Community/Ocelot-So…
Tirokk Aug 29, 2022
f678dad
Fix linting
Tirokk Aug 29, 2022
d1b940b
Implement 'groupSince' and 'groupGoal' in group profile
Tirokk Aug 29, 2022
ac0aacf
Rename 'hc-upload' or 'Upload' to AvatarUploader and moved 'ImageUplo…
Tirokk Aug 29, 2022
a9c52bf
Renamed 'AvatarUploader' property from 'user' to 'profile'
Tirokk Aug 29, 2022
2fc84f9
Rename class 'profile-avatar' to 'profile-page-avatar'
Tirokk Aug 29, 2022
077a63a
Rename class 'user-avatar' to 'profile-avatar'
Tirokk Aug 29, 2022
615ee29
Rename Component from 'UserAvatar' as 'user-avatar' to 'ProfileAvatar…
Tirokk Aug 29, 2022
5f43a51
Rename prop 'user' of 'profile-avatar' to 'profile'
Tirokk Aug 29, 2022
aa09ac2
Fix tests
Tirokk Aug 29, 2022
b9e59ba
Add avatar to group page
Tirokk Aug 30, 2022
b96dfa8
Merge branch '5059-groups/5131-implement-update-group-resolver' of gi…
Tirokk Sep 5, 2022
9b83b37
Upload group avatar on group profile page
Tirokk Sep 6, 2022
d11b512
Merge branch '5059-epic-groups' of github.com:Ocelot-Social-Community…
Tirokk Sep 7, 2022
fa79c25
Implement join button on Group profile, a start
Tirokk Sep 7, 2022
ee770aa
Cleanup
Tirokk Sep 7, 2022
99b1a16
Remove testing of group profile for now
Tirokk Sep 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions backend/src/db/graphql/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,17 @@ export const groupQuery = gql`
description
groupType
actionRadius
myRole
categories {
id
slug
name
icon
}
# avatar # test this as result
avatar {
url
}
# locationName # test this as result
myRole
}
}
`
Expand Down
5 changes: 4 additions & 1 deletion backend/src/middleware/sluggifyMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@ export default {
return resolve(root, args, context, info)
},
UpdateGroup: async (resolve, root, args, context, info) => {
args.slug = args.slug || (await uniqueSlug(args.name, isUniqueFor(context, 'Group')))
if (args.name) {
args.slug = args.slug || (await uniqueSlug(args.name, isUniqueFor(context, 'Group')))
}
return resolve(root, args, context, info)
},
CreatePost: async (resolve, root, args, context, info) => {
args.slug = args.slug || (await uniqueSlug(args.title, isUniqueFor(context, 'Post')))
return 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')))
return resolve(root, args, context, info)
},
Expand Down
4 changes: 4 additions & 0 deletions backend/src/schema/resolvers/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export default {
const { categoryIds } = params
const { id: groupId, avatar: avatarInput } = params
delete params.categoryIds
delete params.avatar
if (CONFIG.CATEGORIES_ACTIVE && categoryIds) {
if (categoryIds.length < CATEGORIES_MIN) {
throw new UserInputError('Too view categories!')
Expand Down Expand Up @@ -270,6 +271,9 @@ export default {
hasMany: {
categories: '-[:CATEGORIZED]->(related:Category)',
},
hasOne: {
avatar: '-[:AVATAR_IMAGE]->(related:Image)',
},
}),
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Then("I should see my comment", () => {
.should("contain", "Ocelot.social rocks")
.get(".user-teaser span.slug")
.should("contain", "@peter-pan") // specific enough
.get(".user-avatar img")
.get(".profile-avatar img")
.should("have.attr", "src")
.and("contain", 'https://') // some url
.get(".user-teaser > .info > .text")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ Then("I cannot upload a picture", () => {
cy.get(".base-card")
.children()
.should("not.have.id", "customdropzone")
.should("have.class", "user-avatar");
.should("have.class", "profile-avatar");
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Then("I should be able to change my profile picture", () => {
{ subjectType: "drag-n-drop", force: true }
);
});
cy.get(".profile-avatar img")
cy.get(".profile-page-avatar img")
.should("have.attr", "src")
.and("contains", "onourjourney");
cy.contains(".iziToast-message", "Upload successful")
Expand Down
4 changes: 2 additions & 2 deletions webapp/components/AvatarMenu/AvatarMenu.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ describe('AvatarMenu.vue', () => {
wrapper = Wrapper()
})

it('renders the UserAvatar component', () => {
it('renders the ProfileAvatar component', () => {
wrapper.find('.avatar-menu-trigger').trigger('click')
expect(wrapper.find('.user-avatar').exists()).toBe(true)
expect(wrapper.find('.profile-avatar').exists()).toBe(true)
})

describe('given a userName', () => {
Expand Down
8 changes: 4 additions & 4 deletions webapp/components/AvatarMenu/AvatarMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"
@click.prevent="toggleMenu"
>
<user-avatar :user="user" size="small" />
<profile-avatar :profile="user" size="small" />
<base-icon class="dropdown-arrow" name="angle-down" />
</a>
</template>
Expand Down Expand Up @@ -50,12 +50,12 @@
<script>
import { mapGetters } from 'vuex'
import Dropdown from '~/components/Dropdown'
import UserAvatar from '~/components/_new/generic/UserAvatar/UserAvatar'
import ProfileAvatar from '~/components/_new/generic/ProfileAvatar/ProfileAvatar'

export default {
components: {
Dropdown,
UserAvatar,
ProfileAvatar,
},
props: {
placement: { type: String, default: 'top-end' },
Expand Down Expand Up @@ -130,7 +130,7 @@ export default {
align-items: center;
padding-left: $space-xx-small;

> .user-avatar {
> .profile-avatar {
margin-right: $space-xx-small;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ContributionForm from './ContributionForm.vue'
import Vuex from 'vuex'
import PostMutations from '~/graphql/PostMutations.js'

import ImageUploader from '~/components/ImageUploader/ImageUploader'
import ImageUploader from '~/components/Uploader/ImageUploader'
import MutationObserver from 'mutation-observer'

global.MutationObserver = MutationObserver
Expand Down
2 changes: 1 addition & 1 deletion webapp/components/ContributionForm/ContributionForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ import { mapGetters } from 'vuex'
import HcEditor from '~/components/Editor/Editor'
import PostMutations from '~/graphql/PostMutations.js'
import CategoriesSelect from '~/components/CategoriesSelect/CategoriesSelect'
import ImageUploader from '~/components/ImageUploader/ImageUploader'
import ImageUploader from '~/components/Uploader/ImageUploader'
import links from '~/constants/links.js'
import PageParamsLink from '~/components/_new/features/PageParamsLink/PageParamsLink.vue'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { shallowMount } from '@vue/test-utils'
import Vue from 'vue'
import Upload from '.'
import AvatarUploader from './AvatarUploader'

const localVue = global.localVue

describe('Upload', () => {
describe('AvatarUploader', () => {
let wrapper

const mocks = {
Expand All @@ -26,14 +26,14 @@ describe('Upload', () => {
}

const propsData = {
user: {
profile: {
avatar: { url: '/api/generic.jpg' },
},
}

beforeEach(() => {
jest.useFakeTimers()
wrapper = shallowMount(Upload, { localVue, propsData, mocks })
wrapper = shallowMount(AvatarUploader, { localVue, propsData, mocks })
})

afterEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
>
<div class="dz-message" @mouseover="hover = true" @mouseleave="hover = false">
<slot></slot>
<div class="hc-attachments-upload-area">
<div class="hc-drag-marker">
<div class="avatar-attachments-upload-area">
<div class="avatar-drag-marker">
<base-icon v-if="hover" name="image" />
</div>
</div>
Expand All @@ -21,14 +21,15 @@
</template>
<script>
import vueDropzone from 'nuxt-dropzone'
import { updateUserMutation } from '~/graphql/User.js'

export default {
name: 'AvatarUploader',
components: {
vueDropzone,
},
props: {
user: { type: Object, default: null },
profile: { type: Object, required: true },
updateMutation: { type: Object, required: true },
},
data() {
return {
Expand All @@ -43,7 +44,7 @@ export default {
},
computed: {
avatarUrl() {
const { avatar } = this.user
const { avatar } = this.profile
return avatar && avatar.url
},
},
Expand All @@ -68,16 +69,16 @@ export default {
const avatarUpload = file[0]
this.$apollo
.mutate({
mutation: updateUserMutation(),
mutation: this.updateMutation,
variables: {
avatar: {
upload: avatarUpload,
},
id: this.user.id,
id: this.profile.id,
},
})
.then(() => {
this.$toast.success(this.$t('user.avatar.submitted'))
this.$toast.success(this.$t('profile.avatar.submitted'))
})
.catch((error) => this.$toast.error(error.message))
},
Expand Down Expand Up @@ -115,19 +116,19 @@ export default {
width: 100%;
}

.hc-attachments-upload-area {
.avatar-attachments-upload-area {
position: relative;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}

.hc-attachments-upload-button {
.avatar-attachments-upload-button {
pointer-events: none;
}

.hc-drag-marker {
.avatar-drag-marker {
position: relative;
width: 122px;
height: 122px;
Expand Down Expand Up @@ -165,7 +166,7 @@ export default {
border-radius: 100%;
border: 1px dashed hsl(0, 0%, 25%);
}
.hc-attachments-upload-area:hover & {
.avatar-attachments-upload-area:hover & {
opacity: 1;
}
}
Expand Down
10 changes: 5 additions & 5 deletions webapp/components/UserTeaser/UserTeaser.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<template>
<div class="user-teaser" v-if="displayAnonymous">
<user-avatar v-if="showAvatar" size="small" />
<profile-avatar v-if="showAvatar" size="small" />
<span class="info anonymous">{{ $t('profile.userAnonym') }}</span>
</div>
<div v-else :class="[{ 'disabled-content': user.disabled }]" placement="top-start">
<nuxt-link :to="userLink" :class="['user-teaser']">
<user-avatar v-if="showAvatar" :user="user" size="small" />
<profile-avatar v-if="showAvatar" :profile="user" size="small" />
<div class="info">
<span class="text">
<span class="slug">{{ userSlug }}</span>
Expand All @@ -26,13 +26,13 @@
import { mapGetters } from 'vuex'

import HcRelativeDateTime from '~/components/RelativeDateTime'
import UserAvatar from '~/components/_new/generic/UserAvatar/UserAvatar'
import ProfileAvatar from '~/components/_new/generic/ProfileAvatar/ProfileAvatar'

export default {
name: 'UserTeaser',
components: {
HcRelativeDateTime,
UserAvatar,
ProfileAvatar,
},
props: {
user: { type: Object, default: null },
Expand Down Expand Up @@ -88,7 +88,7 @@ export default {
display: flex;
flex-wrap: nowrap;

> .user-avatar {
> .profile-avatar {
flex-shrink: 0;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { mount } from '@vue/test-utils'
import UserAvatar from './UserAvatar.vue'
import ProfileAvatar from './ProfileAvatar'
import BaseIcon from '~/components/_new/generic/BaseIcon/BaseIcon'

const localVue = global.localVue

describe('UserAvatar.vue', () => {
describe('ProfileAvatar', () => {
let propsData, wrapper
beforeEach(() => {
propsData = {}
wrapper = Wrapper()
})

const Wrapper = () => {
return mount(UserAvatar, { propsData, localVue })
return mount(ProfileAvatar, { propsData, localVue })
}

it('renders no image', () => {
Expand All @@ -23,39 +23,39 @@ describe('UserAvatar.vue', () => {
expect(wrapper.find(BaseIcon).exists()).toBe(true)
})

describe('given a user', () => {
describe('given a profile', () => {
describe('with no image', () => {
beforeEach(() => {
propsData = {
user: {
profile: {
name: 'Matt Rider',
},
}
wrapper = Wrapper()
})

describe('no user name', () => {
describe('no profile name', () => {
it('renders an icon', () => {
propsData = { user: { name: null } }
propsData = { profile: { name: null } }
wrapper = Wrapper()
expect(wrapper.find(BaseIcon).exists()).toBe(true)
})
})

describe("user name is 'Anonymous'", () => {
describe("profile name is 'Anonymous'", () => {
it('renders an icon', () => {
propsData = { user: { name: 'Anonymous' } }
propsData = { profile: { name: 'Anonymous' } }
wrapper = Wrapper()
expect(wrapper.find(BaseIcon).exists()).toBe(true)
})
})

it('displays user initials', () => {
it('displays profile initials', () => {
expect(wrapper.find('.initials').text()).toEqual('MR')
})

it('displays no more than 3 initials', () => {
propsData = { user: { name: 'Ana Paula Nunes Marques' } }
propsData = { profile: { name: 'Ana Paula Nunes Marques' } }
wrapper = Wrapper()
expect(wrapper.find('.initials').text()).toEqual('APN')
})
Expand All @@ -64,7 +64,7 @@ describe('UserAvatar.vue', () => {
describe('with a relative avatar url', () => {
beforeEach(() => {
propsData = {
user: {
profile: {
name: 'Not Anonymous',
avatar: {
url: '/avatar.jpg',
Expand All @@ -82,7 +82,7 @@ describe('UserAvatar.vue', () => {
describe('with an absolute avatar url', () => {
beforeEach(() => {
propsData = {
user: {
profile: {
name: 'Not Anonymous',
avatar: {
url: 'https://s3.amazonaws.com/uifaces/faces/twitter/sawalazar/128.jpg',
Expand Down
Loading