add modal to add group member confrimation

This commit is contained in:
Moriz Wahl 2022-11-22 12:24:02 +01:00
parent 9ef44ed23c
commit 0d160c0280
4 changed files with 188 additions and 98 deletions

View File

@ -0,0 +1,170 @@
<template>
<div class="add-group-member">
<h2 class="title">{{ $t('group.addUser') }}</h2>
<ds-space margin-bottom="small" />
<ds-space>
<ds-select
type="search"
icon="search"
label-prop="id"
:icon-right="null"
:options="users"
:loading="$apollo.queries.searchUsers.loading"
:filter="(item) => item"
:no-options-available="$t('group.addUserNoOptions')"
:auto-reset-search="true"
:placeholder="$t('group.addUserPlaceholder')"
@focus.capture.native="onFocus"
@input.native="handleInput"
@keyup.enter.native="onEnter"
@keyup.delete.native="onDelete"
@keyup.esc.native="clear"
@blur.capture.native="onBlur"
@input.exact="onSelect"
>
<template #option="{ option }">
<p>
<user-teaser :user="option" :showPopover="false" :linkToProfile="false" />
</p>
</template>
</ds-select>
<ds-modal v-if="isOpen"
force
extended
:confirm-label="$t('group.modal.confirm')"
:cancel-label="$t('group.modal.cancel')"
:title="$t('group.modal.confirmAddGroupMemberTitle')"
v-model="isOpen"
@close="closeModal"
@confirm="confirmModal"
@cancel="cancelModal"
>
<ds-text size="large">{{ $t('group.modal.confirmAddGroupMemberText', { name: user.name }) }}</ds-text>
</ds-modal>
</ds-space>
</div>
</template>
<script>
import { changeGroupMemberRoleMutation } from '~/graphql/groups.js'
import { searchUsers } from '~/graphql/Search.js'
import UserTeaser from '~/components/UserTeaser/UserTeaser.vue'
import { isEmpty } from 'lodash'
export default {
name: 'AddGroupMember',
components: {
UserTeaser,
},
props: {
groupId: {
type: String,
required: true,
},
groupMembers: {
type: Array,
required: false,
},
},
data() {
return {
users: [],
id: 'search-user-to-add-to-group',
query: '',
searchProcess: null,
user: {},
isOpen: false,
}
},
computed: {
startSearch() {
return this.query && this.query.length > 3
},
},
methods: {
cancelModal() {
this.user = {}
this.isOpen = false
},
closeModal() {
this.isOpen = false
},
confirmModal(item) {
this.addMemberToGroup()
item = null
this.clear()
this.isOpen = false
},
onFocus(event) {},
onBlur(event) {
this.query = ''
},
handleInput(event) {
this.query = event.target ? event.target.value.trim() : ''
},
onDelete(event) {
const value = event.target ? event.target.value.trim() : ''
if (isEmpty(value)) {
this.clear()
} else {
this.handleInput(event)
}
},
clear() {
this.query = ''
this.user = {}
this.users = []
},
onSelect(item) {
this.user = item
this.isOpen = true
},
onEnter() {},
async addMemberToGroup() {
const newRole = 'usual'
if (this.groupMembers.find((member) => member.id === this.user.id)) {
this.$toast.error(this.$t('group.errors.userAlreadyMember', { slug: this.user.slug }))
return
}
try {
await this.$apollo.mutate({
mutation: changeGroupMemberRoleMutation(),
variables: { groupId: this.groupId, userId: this.user.id, roleInGroup: newRole },
})
this.$emit('loadGroupMembers')
this.$toast.success(
this.$t('group.changeMemberRole', { role: this.$t(`group.roles.${newRole}`) }),
)
} catch (error) {
this.$toast.error(error.message)
}
},
},
apollo: {
searchUsers: {
query() {
return searchUsers
},
variables() {
return {
query: this.query,
firstUsers: 5,
usersOffset: 0,
}
},
skip() {
return !this.startSearch
},
update({ searchUsers }) {
this.users = searchUsers.users
},
fetchPolicy: 'cache-and-network',
},
},
}
</script>
<style lang="scss">
.add-group-member {
background-color: white;
padding: 24px;
}
</style>

View File

@ -1,39 +1,6 @@
<template>
<div class="group-member">
<h3 class="title">{{ $t('group.addUser') }}</h3>
<ds-space margin-bottom="small" />
<ds-space margin-bottom="small">
<ds-select
type="search"
icon="search"
v-model="query"
label-prop="id"
:icon-right="null"
:options="users"
:loading="$apollo.queries.searchUsers.loading"
:filter="(item) => item"
:no-options-available="$t('group.addUserPlaceholder')"
:auto-reset-search="!startSearch"
:placeholder="$t('group.addUserPlaceholder')"
@focus.capture.native="onFocus"
@input.native="handleInput"
@keyup.enter.native="onEnter"
@keyup.delete.native="onDelete"
@keyup.esc.native="clear"
@blur.capture.native="onBlur"
@input.exact="onSelect"
>
<template #option="{ option }">
<p>
<!-- ToDo: Avoid redirect to user profile when clicking on slug -->
<user-teaser :user="option" :showPopover="false" />
</p>
</template>
</ds-select>
</ds-space>
<ds-space margin-bottom="large" />
<h3 class="title">{{ $t('group.membersListTitle') }}</h3>
<h2 class="title">{{ $t('group.membersListTitle') }}</h2>
<ds-space margin-bottom="small" />
<ds-table :fields="tableFields" :data="groupMembers" condensed>
<template #avatar="scope">
@ -110,15 +77,9 @@
</template>
<script>
import { changeGroupMemberRoleMutation } from '~/graphql/groups.js'
import { searchUsers } from '~/graphql/Search.js'
import { isEmpty } from 'lodash'
import UserTeaser from '~/components/UserTeaser/UserTeaser.vue'
export default {
name: 'GroupMember',
components: {
UserTeaser,
},
props: {
groupId: {
type: String,
@ -131,9 +92,6 @@ export default {
},
data() {
return {
// isOpen: false,
// memberId: null,
users: [],
id: 'search-user-to-add-to-group',
query: '',
searchProcess: null,
@ -165,37 +123,8 @@ export default {
},
}
},
startSearch() {
return this.query && this.query.length > 3
},
},
methods: {
onFocus(event) {},
onBlur(event) {
this.query = ''
},
handleInput(event) {
this.query = event.target ? event.target.value.trim() : ''
},
onDelete(event) {
const value = event.target ? event.target.value.trim() : ''
if (isEmpty(value)) {
this.clear()
} else {
this.handleInput(event)
}
},
clear() {
this.query = ''
this.user = {}
this.users = []
},
onSelect(item) {
this.user = item
this.addMemberToGroup()
this.clear()
},
onEnter() {},
async changeMemberRole(id, event) {
const newRole = event.target.value
try {
@ -230,27 +159,6 @@ export default {
}
},
},
apollo: {
searchUsers: {
query() {
return searchUsers
},
variables() {
return {
query: this.query,
firstUsers: 5,
usersOffset: 0,
}
},
skip() {
return !this.startSearch
},
update({ searchUsers }) {
this.users = searchUsers.users
},
fetchPolicy: 'cache-and-network',
},
},
}
</script>
<style scoped>

View File

@ -5,17 +5,22 @@
</div>
<div v-else :class="[{ 'disabled-content': user.disabled }]" placement="top-start">
<div :class="['user-teaser']">
<nuxt-link :to="userLink" data-test="avatarUserLink">
<profile-avatar v-if="showAvatar" :profile="user" size="small" />
<nuxt-link v-if="linkToProfile && showAvatar" :to="userLink" data-test="avatarUserLink">
<profile-avatar :profile="user" size="small" />
</nuxt-link>
<profile-avatar v-else-if="showAvatar" :profile="user" size="small" />
<div class="info flex-direction-column">
<div :class="wide ? 'flex-direction-row' : 'flex-direction-column'">
<nuxt-link :to="userLink">
<nuxt-link v-if="linkToProfile" :to="userLink">
<span class="text">
<span class="slug">{{ userSlug }}</span>
<span v-if="!userOnly" class="name">{{ userName }}</span>
</span>
</nuxt-link>
<span v-else class="text">
<span class="slug">{{ userSlug }}</span>
<span v-if="!userOnly" class="name">{{ userName }}</span>
</span>
<span v-if="wide">&nbsp;</span>
<span v-if="group">
<span class="text">
@ -53,6 +58,7 @@ export default {
ProfileAvatar,
},
props: {
linkToProfile: { type: Boolean, default: true },
user: { type: Object, default: null },
group: { type: Object, default: null },
wide: { type: Boolean, default: false },

View File

@ -1,8 +1,12 @@
<template>
<div>
<add-group-member
:groupId="group.id"
:groupMembers="groupMembers"
@loadGroupMembers="loadGroupMembers"
/>
<ds-space margin-bottom="small" />
<base-card>
<ds-heading tag="h3">{{ $t('group.members') }}</ds-heading>
<ds-space margin="large" />
<group-member
:groupId="group.id"
:groupMembers="groupMembers"
@ -14,11 +18,13 @@
<script>
import GroupMember from '~/components/Group/GroupMember'
import AddGroupMember from '~/components/Group/AddGroupMember'
import { groupMembersQuery } from '~/graphql/groups.js'
export default {
components: {
GroupMember,
AddGroupMember,
},
props: {
group: {