mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-22 00:03:51 +02:00
refactor
This commit is contained in:
242
src/components/dialogs/GroupDialog/GroupDialogMembersTab.vue
Normal file
242
src/components/dialogs/GroupDialog/GroupDialogMembersTab.vue
Normal file
@@ -0,0 +1,242 @@
|
||||
<template>
|
||||
<template v-if="groupDialog.visible">
|
||||
<span
|
||||
v-if="hasGroupPermission(groupDialog.ref, 'group-members-viewall')"
|
||||
style="font-weight: bold; font-size: 16px"
|
||||
>{{ t('dialog.group.members.all_members') }}</span
|
||||
>
|
||||
<span v-else style="font-weight: bold; font-size: 16px">{{ t('dialog.group.members.friends_only') }}</span>
|
||||
<div style="margin-top: 8px">
|
||||
<Button
|
||||
class="rounded-full h-6 w-6"
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
:loading="isGroupMembersLoading"
|
||||
circle
|
||||
@click="loadAllGroupMembers">
|
||||
<Spinner v-if="isGroupMembersLoading" /><RefreshCcw v-else
|
||||
/></Button>
|
||||
<Button
|
||||
class="rounded-full h-6 w-6 ml-2"
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
style="margin-left: 6px"
|
||||
@click="downloadAndSaveJson(`${groupDialog.id}_members`, groupDialog.members)">
|
||||
<Download class="h-4 w-4" />
|
||||
</Button>
|
||||
<span v-if="groupDialog.memberSearch.length" style="font-size: 14px; margin-left: 6px; margin-right: 6px"
|
||||
>{{ groupDialog.memberSearchResults.length }}/{{ groupDialog.ref.memberCount }}</span
|
||||
>
|
||||
<span v-else style="font-size: 14px; margin-left: 6px; margin-right: 6px"
|
||||
>{{ groupDialog.members.length }}/{{ groupDialog.ref.memberCount }}</span
|
||||
>
|
||||
<div
|
||||
v-if="hasGroupPermission(groupDialog.ref, 'group-members-manage')"
|
||||
style="float: right"
|
||||
class="flex items-center">
|
||||
<span style="margin-right: 6px">{{ t('dialog.group.members.sort_by') }}</span>
|
||||
<Select
|
||||
v-model="groupDialogMemberSortValue"
|
||||
:disabled="isGroupMembersLoading || groupDialog.memberSearch.length > 0">
|
||||
<SelectTrigger class="h-8 w-45 mr-1">
|
||||
<SelectValue :placeholder="t('dialog.group.members.sort_by')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem v-for="item in groupDialogSortingOptions" :key="item.value" :value="item.value">
|
||||
{{ t(item.name) }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span class="ml-2 mr-1">{{ t('dialog.group.members.filter') }}</span>
|
||||
<div style="display: inline-block; width: 220px">
|
||||
<VirtualCombobox
|
||||
v-model="groupDialogMemberFilterKey"
|
||||
:groups="groupDialogMemberFilterGroups"
|
||||
:disabled="isGroupMembersLoading || groupDialog.memberSearch.length > 0"
|
||||
:placeholder="t('dialog.group.members.filter')"
|
||||
:search-placeholder="t('dialog.group.members.search')"
|
||||
:clearable="false"
|
||||
:close-on-select="true">
|
||||
<template #trigger="{ text }">
|
||||
<span class="truncate">
|
||||
{{ text || t('dialog.group.members.filter') }}
|
||||
</span>
|
||||
</template>
|
||||
</VirtualCombobox>
|
||||
</div>
|
||||
</div>
|
||||
<InputGroupField
|
||||
v-model="groupDialog.memberSearch"
|
||||
:disabled="!hasGroupPermission(groupDialog.ref, 'group-members-manage')"
|
||||
clearable
|
||||
size="sm"
|
||||
:placeholder="t('dialog.group.members.search')"
|
||||
style="margin-top: 8px; margin-bottom: 8px"
|
||||
@input="groupMembersSearch" />
|
||||
</div>
|
||||
<div
|
||||
v-if="groupDialog.memberSearch.length"
|
||||
class="flex flex-wrap items-start"
|
||||
style="margin-top: 8px; overflow: auto; max-height: 250px; min-width: 130px">
|
||||
<div
|
||||
v-for="user in groupDialog.memberSearchResults"
|
||||
:key="user.id"
|
||||
class="box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]"
|
||||
@click="showUserDialog(user.userId)">
|
||||
<div class="relative inline-block flex-none size-9 mr-2.5">
|
||||
<img class="size-full rounded-full object-cover" :src="userImage(user.user)" loading="lazy" />
|
||||
</div>
|
||||
<div class="flex-1 overflow-hidden">
|
||||
<span
|
||||
class="block truncate font-medium leading-[18px]"
|
||||
:style="{ color: user.user?.$userColour }"
|
||||
v-text="user.user?.displayName" />
|
||||
<span class="block truncate text-xs">
|
||||
<template v-if="hasGroupPermission(groupDialog.ref, 'group-members-manage')">
|
||||
<TooltipWrapper
|
||||
v-if="user.isRepresenting"
|
||||
side="top"
|
||||
:content="t('dialog.group.members.representing')">
|
||||
<Tag style="margin-right: 6px" />
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper v-if="user.visibility !== 'visible'" side="top">
|
||||
<template #content>
|
||||
<span>{{ t('dialog.group.members.visibility') }} {{ user.visibility }}</span>
|
||||
</template>
|
||||
<Eye style="margin-right: 6px" />
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper
|
||||
v-if="!user.isSubscribedToAnnouncements"
|
||||
side="top"
|
||||
:content="t('dialog.group.members.unsubscribed_announcements')">
|
||||
<MessageSquare style="margin-right: 6px" />
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper v-if="user.managerNotes" side="top">
|
||||
<template #content>
|
||||
<span>{{ t('dialog.group.members.manager_notes') }}</span>
|
||||
<br />
|
||||
<span>{{ user.managerNotes }}</span>
|
||||
</template>
|
||||
<Pencil style="margin-right: 6px" />
|
||||
</TooltipWrapper>
|
||||
</template>
|
||||
<template v-for="roleId in user.roleIds" :key="roleId">
|
||||
<template v-for="role in groupDialog.ref.roles" :key="role.id + roleId"
|
||||
><span v-if="role.id === roleId" v-text="role.name" /></template
|
||||
><template v-if="user.roleIds.indexOf(roleId) < user.roleIds.length - 1"
|
||||
><span>, </span></template
|
||||
>
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul
|
||||
v-else-if="groupDialog.members.length > 0"
|
||||
class="infinite-list flex flex-wrap items-start"
|
||||
style="margin-top: 8px; overflow: auto; max-height: 250px; min-width: 130px">
|
||||
<li
|
||||
v-for="user in groupDialog.members"
|
||||
:key="user.id"
|
||||
class="infinite-list-item box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]"
|
||||
@click="showUserDialog(user.userId)">
|
||||
<div class="relative inline-block flex-none size-9 mr-2.5">
|
||||
<img class="size-full rounded-full object-cover" :src="userImage(user.user)" loading="lazy" />
|
||||
</div>
|
||||
<div class="flex-1 overflow-hidden">
|
||||
<span
|
||||
class="block truncate font-medium leading-[18px]"
|
||||
:style="{ color: user.user?.$userColour }"
|
||||
v-text="user.user?.displayName" />
|
||||
<span class="block truncate text-xs">
|
||||
<template v-if="hasGroupPermission(groupDialog.ref, 'group-members-manage')">
|
||||
<TooltipWrapper
|
||||
v-if="user.isRepresenting"
|
||||
side="top"
|
||||
:content="t('dialog.group.members.representing')">
|
||||
<Tag style="margin-right: 6px" />
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper v-if="user.visibility !== 'visible'" side="top">
|
||||
<template #content>
|
||||
<span>{{ t('dialog.group.members.visibility') }} {{ user.visibility }}</span>
|
||||
</template>
|
||||
<Eye style="margin-right: 6px" />
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper
|
||||
v-if="!user.isSubscribedToAnnouncements"
|
||||
side="top"
|
||||
:content="t('dialog.group.members.unsubscribed_announcements')">
|
||||
<MessageSquare style="margin-right: 6px" />
|
||||
</TooltipWrapper>
|
||||
<TooltipWrapper v-if="user.managerNotes" side="top">
|
||||
<template #content>
|
||||
<span>{{ t('dialog.group.members.manager_notes') }}</span>
|
||||
<br />
|
||||
<span>{{ user.managerNotes }}</span>
|
||||
</template>
|
||||
<Pencil style="margin-right: 6px" />
|
||||
</TooltipWrapper>
|
||||
</template>
|
||||
<template v-for="roleId in user.roleIds" :key="roleId">
|
||||
<template v-for="role in groupDialog.ref.roles" :key="roleId + role.id"
|
||||
><span v-if="role.id === roleId" v-text="role.name" /></template
|
||||
><template v-if="user.roleIds.indexOf(roleId) < user.roleIds.length - 1"
|
||||
><span> </span></template
|
||||
>
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<div
|
||||
v-if="!isGroupMembersDone"
|
||||
class="box-border flex items-center p-1.5 text-[13px] cursor-pointer"
|
||||
style="width: 100%; height: 45px; text-align: center"
|
||||
@click="loadMoreGroupMembers">
|
||||
<div v-if="!isGroupMembersLoading" class="flex-1 overflow-hidden">
|
||||
<span class="block truncate font-medium leading-[18px]">{{
|
||||
t('dialog.group.members.load_more')
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Download, Eye, MessageSquare, Pencil, RefreshCcw, Tag } from 'lucide-vue-next';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { InputGroupField } from '@/components/ui/input-group';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { VirtualCombobox } from '@/components/ui/virtual-combobox';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { downloadAndSaveJson, hasGroupPermission, userImage } from '../../../shared/utils';
|
||||
import { useGroupStore, useUserStore } from '../../../stores';
|
||||
import { groupDialogSortingOptions } from '../../../shared/constants';
|
||||
import { useGroupMembers } from './useGroupMembers';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const { showUserDialog } = useUserStore();
|
||||
const { currentUser } = storeToRefs(useUserStore());
|
||||
const { groupDialog } = storeToRefs(useGroupStore());
|
||||
const { applyGroupMember, handleGroupMember } = useGroupStore();
|
||||
|
||||
const {
|
||||
isGroupMembersDone,
|
||||
isGroupMembersLoading,
|
||||
groupDialogMemberSortValue,
|
||||
groupDialogMemberFilterKey,
|
||||
groupDialogMemberFilterGroups,
|
||||
groupMembersSearch,
|
||||
getGroupDialogGroupMembers,
|
||||
loadMoreGroupMembers,
|
||||
loadAllGroupMembers
|
||||
} = useGroupMembers(groupDialog, { currentUser, applyGroupMember, handleGroupMember, t });
|
||||
|
||||
defineExpose({
|
||||
getGroupDialogGroupMembers
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user