mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2026-01-20 20:01:25 +00:00
Merge pull request #5652 from Ocelot-Social-Community/search-users-to-add-to-group
feat(webapp): 🍰 Search Users To Add To Group
This commit is contained in:
commit
41813eeab8
179
webapp/components/Group/AddGroupMember.vue
Normal file
179
webapp/components/Group/AddGroupMember.vue
Normal file
@ -0,0 +1,179 @@
|
||||
<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"
|
||||
v-model="query"
|
||||
:id="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: '',
|
||||
user: {},
|
||||
isOpen: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
startSearch() {
|
||||
return this.query && this.query.length > 3
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
cancelModal() {
|
||||
this.clear()
|
||||
this.isOpen = false
|
||||
},
|
||||
closeModal() {
|
||||
this.clear()
|
||||
this.isOpen = false
|
||||
},
|
||||
confirmModal() {
|
||||
this.addMemberToGroup()
|
||||
this.isOpen = false
|
||||
this.clear()
|
||||
},
|
||||
onFocus() {},
|
||||
onBlur() {
|
||||
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
|
||||
if (this.groupMembers.find((member) => member.id === this.user.id)) {
|
||||
this.$toast.error(this.$t('group.errors.userAlreadyMember', { name: this.user.name }))
|
||||
this.clear()
|
||||
return
|
||||
}
|
||||
this.isOpen = true
|
||||
},
|
||||
onEnter() {},
|
||||
async addMemberToGroup() {
|
||||
const newRole = 'usual'
|
||||
const username = this.user.name
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: { groupId: this.groupId, userId: this.user.id, roleInGroup: newRole },
|
||||
})
|
||||
this.$toast.success(
|
||||
this.$t('group.addMemberToGroupSuccess', {
|
||||
role: this.$t(`group.roles.${newRole}`),
|
||||
name: username,
|
||||
}),
|
||||
)
|
||||
this.$emit('loadGroupMembers')
|
||||
} 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: $space-base;
|
||||
}
|
||||
</style>
|
||||
@ -1,41 +1,7 @@
|
||||
<template>
|
||||
<div class="group-member">
|
||||
<base-card>
|
||||
<h2 class="title">{{ $t('group.addUser') }}</h2>
|
||||
<ds-form v-model="form" @submit="submit">
|
||||
<ds-flex gutter="small">
|
||||
<ds-flex-item width="90%">
|
||||
<ds-input
|
||||
name="query"
|
||||
model="query"
|
||||
:placeholder="$t('group.addUserPlaceholder')"
|
||||
icon="search"
|
||||
/>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item width="30px">
|
||||
<!-- <base-button filled circle type="submit" icon="search" :loading="$apollo.loading" /> -->
|
||||
<base-button filled circle type="submit" icon="search" />
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</ds-form>
|
||||
<div v-if="noSlug">Kein User mit diesem Slug gefunden!</div>
|
||||
<div v-if="slugUser.length > 0">
|
||||
<ds-space margin="base" />
|
||||
<ds-flex>
|
||||
<ds-flex-item>
|
||||
<ds-avatar online size="small" :name="slugUser[0].name"></ds-avatar>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item>{{ slugUser[0].name }}</ds-flex-item>
|
||||
<ds-flex-item>{{ slugUser[0].slug }}</ds-flex-item>
|
||||
<ds-flex-item>
|
||||
<ds-button size="small" primary @click="addMemberToGroup(slugUser)">
|
||||
{{ $t('group.addMemberToGroup') }}
|
||||
</ds-button>
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
<ds-space margin="base" />
|
||||
</div>
|
||||
</base-card>
|
||||
<h2 class="title">{{ $t('group.membersListTitle') }}</h2>
|
||||
<ds-space margin-bottom="small" />
|
||||
<ds-table :fields="tableFields" :data="groupMembers" condensed>
|
||||
<template #avatar="scope">
|
||||
<nuxt-link
|
||||
@ -90,7 +56,7 @@
|
||||
<ds-button v-if="scope.row.myRoleInGroup !== 'owner'" size="small" primary disabled>
|
||||
<!-- TODO: implement removal of group members -->
|
||||
<!-- :disabled="scope.row.myRoleInGroup === 'owner'"
|
||||
-->
|
||||
-->
|
||||
{{ $t('group.removeMemberButton') }}
|
||||
</ds-button>
|
||||
</template>
|
||||
@ -98,19 +64,18 @@
|
||||
<!-- TODO: implement removal of group members -->
|
||||
<!-- TODO: change to ocelot.social modal -->
|
||||
<!-- <ds-modal
|
||||
v-if="isOpen"
|
||||
v-model="isOpen"
|
||||
:title="`${$t('group.removeMember')}`"
|
||||
force
|
||||
extended
|
||||
:confirm-label="$t('group.removeMember')"
|
||||
:cancel-label="$t('actions.cancel')"
|
||||
@confirm="deleteMember(memberId)"
|
||||
/> -->
|
||||
v-if="isOpen"
|
||||
v-model="isOpen"
|
||||
:title="`${$t('group.removeMember')}`"
|
||||
force
|
||||
extended
|
||||
:confirm-label="$t('group.removeMember')"
|
||||
:cancel-label="$t('actions.cancel')"
|
||||
@confirm="deleteMember(memberId)"
|
||||
/> -->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { minimisedUserQuery } from '~/graphql/User'
|
||||
import { changeGroupMemberRoleMutation } from '~/graphql/groups.js'
|
||||
|
||||
export default {
|
||||
@ -127,13 +92,10 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isOpen: false,
|
||||
memberId: null,
|
||||
noSlug: false,
|
||||
slugUser: [],
|
||||
form: {
|
||||
query: '',
|
||||
},
|
||||
id: 'search-user-to-add-to-group',
|
||||
query: '',
|
||||
searchProcess: null,
|
||||
user: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -177,50 +139,6 @@ export default {
|
||||
this.$toast.error(error.message)
|
||||
}
|
||||
},
|
||||
async addMemberToGroup() {
|
||||
const newRole = 'usual'
|
||||
if (this.groupMembers.find((member) => member.id === this.slugUser[0].id)) {
|
||||
this.$toast.error(
|
||||
this.$t('group.errors.userAlreadyMember', { slug: this.slugUser[0].slug }),
|
||||
)
|
||||
return
|
||||
}
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: { groupId: this.groupId, userId: this.slugUser[0].id, roleInGroup: newRole },
|
||||
})
|
||||
this.$emit('loadGroupMembers')
|
||||
this.slugUser = []
|
||||
this.form.query = ''
|
||||
this.$toast.success(
|
||||
this.$t('group.changeMemberRole', { role: this.$t(`group.roles.${newRole}`) }),
|
||||
)
|
||||
} catch (error) {
|
||||
this.$toast.error(error.message)
|
||||
}
|
||||
},
|
||||
async submit() {
|
||||
try {
|
||||
const {
|
||||
data: { User },
|
||||
} = await this.$apollo.query({
|
||||
query: minimisedUserQuery(),
|
||||
variables: {
|
||||
slug: this.form.query,
|
||||
},
|
||||
})
|
||||
if (User.length === 0) {
|
||||
this.noSlug = true
|
||||
} else {
|
||||
this.noSlug = false
|
||||
this.slugUser = User
|
||||
}
|
||||
} catch (error) {
|
||||
this.noSlug = true
|
||||
} finally {
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -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"> </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 },
|
||||
|
||||
@ -405,8 +405,10 @@
|
||||
},
|
||||
"actionRadius": "Aktionsradius",
|
||||
"addMemberToGroup": "Zur Gruppe hinzufügen",
|
||||
"addMemberToGroupSuccess": "„{name}“ wurde der Gruppe mit der Rolle „{role}“ hinzugefügt!",
|
||||
"addUser": "Benutzer hinzufügen",
|
||||
"addUserPlaceholder": "eindeutiger Benutzername > @slug-from-user",
|
||||
"addUserNoOptions": "Keine Nutzer gefunden!",
|
||||
"addUserPlaceholder": "Benutzername",
|
||||
"allGroups": "Alle Gruppen",
|
||||
"categories": "Thema ::: Themen",
|
||||
"changeMemberRole": "Die Rolle wurde auf „{role}“ geändert!",
|
||||
@ -423,7 +425,7 @@
|
||||
"title": "Meine Gruppe ändern"
|
||||
},
|
||||
"errors": {
|
||||
"userAlreadyMember": "Nutzer @{slug} ist bereits Mitglied"
|
||||
"userAlreadyMember": "Benutzer „{name}“ ist bereits Mitglied!"
|
||||
},
|
||||
"follow": "Folge",
|
||||
"foundation": "Gründung",
|
||||
@ -451,6 +453,12 @@
|
||||
"membersCount": "Mitglied ::: Mitglieder",
|
||||
"membersListTitle": "Gruppenmitglieder",
|
||||
"membersListTitleNotAllowedSeeingGroupMembers": "Gruppenmitglieder unsichtbar",
|
||||
"modal": {
|
||||
"cancel": "Abbrechen",
|
||||
"confirm": "Bestätigen",
|
||||
"confirmAddGroupMemberText": "Nutzer „{name}“ zur Gruppe hinzufügen?",
|
||||
"confirmAddGroupMemberTitle": "Bestätigen"
|
||||
},
|
||||
"myGroups": "Meine Gruppen",
|
||||
"name": "Gruppenname",
|
||||
"radius": "Radius",
|
||||
|
||||
@ -405,8 +405,10 @@
|
||||
},
|
||||
"actionRadius": "Action radius",
|
||||
"addMemberToGroup": "Add to group",
|
||||
"addMemberToGroupSuccess": "“{name}” was added to the group with the role “{role}”!",
|
||||
"addUser": "Add User",
|
||||
"addUserPlaceholder": "unique username > @slug-from-user",
|
||||
"addUserNoOptions": "No users found!",
|
||||
"addUserPlaceholder": " Username",
|
||||
"allGroups": "All Groups",
|
||||
"categories": "Topic ::: Topics",
|
||||
"changeMemberRole": "The role has been changed to “{role}”!",
|
||||
@ -423,7 +425,7 @@
|
||||
"title": "Edit My Group"
|
||||
},
|
||||
"errors": {
|
||||
"userAlreadyMember": "User @{slug} is already a member"
|
||||
"userAlreadyMember": "User “{name}” is already a member!"
|
||||
},
|
||||
"follow": "Follow",
|
||||
"foundation": "Foundation",
|
||||
@ -451,6 +453,12 @@
|
||||
"membersCount": "Member ::: Members",
|
||||
"membersListTitle": "Group Members",
|
||||
"membersListTitleNotAllowedSeeingGroupMembers": "Group Members invisible",
|
||||
"modal": {
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"confirmAddGroupMemberText": "Add user “{name}” to group?",
|
||||
"confirmAddGroupMemberTitle": "Confirm"
|
||||
},
|
||||
"myGroups": "My Groups",
|
||||
"name": "Group name",
|
||||
"radius": "Radius",
|
||||
|
||||
@ -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: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user