mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-24 09:13:50 +02:00
307 lines
12 KiB
Vue
307 lines
12 KiB
Vue
<template>
|
|
<el-dialog
|
|
:z-index="inviteGroupDialogIndex"
|
|
v-model="inviteGroupDialog.visible"
|
|
:title="t('dialog.invite_to_group.header')"
|
|
width="450px"
|
|
append-to-body>
|
|
<div v-if="inviteGroupDialog.visible" v-loading="inviteGroupDialog.loading">
|
|
<span>{{ t('dialog.invite_to_group.description') }}</span>
|
|
<br />
|
|
|
|
<div style="margin-top: 15px; width: 100%">
|
|
<VirtualCombobox
|
|
v-model="inviteGroupDialog.groupId"
|
|
:groups="groupPickerGroups"
|
|
:disabled="inviteGroupDialog.loading"
|
|
:placeholder="t('dialog.invite_to_group.choose_group_placeholder')"
|
|
:search-placeholder="t('dialog.invite_to_group.choose_group_placeholder')"
|
|
:clearable="true"
|
|
:close-on-select="true"
|
|
:deselect-on-reselect="true">
|
|
<template #item="{ item, selected }">
|
|
<div class="x-friend-item flex w-full items-center">
|
|
<div class="avatar">
|
|
<img :src="item.iconUrl" loading="lazy" />
|
|
</div>
|
|
<div class="detail">
|
|
<span class="name" v-text="item.label"></span>
|
|
</div>
|
|
<CheckIcon :class="['ml-auto size-4', selected ? 'opacity-100' : 'opacity-0']" />
|
|
</div>
|
|
</template>
|
|
</VirtualCombobox>
|
|
</div>
|
|
|
|
<div style="width: 100%; margin-top: 15px">
|
|
<VirtualCombobox
|
|
v-model="inviteGroupDialog.userIds"
|
|
:groups="friendPickerGroups"
|
|
multiple
|
|
:disabled="inviteGroupDialog.loading"
|
|
:placeholder="t('dialog.invite_to_group.choose_friends_placeholder')"
|
|
:search-placeholder="t('dialog.invite_to_group.choose_friends_placeholder')"
|
|
:clearable="true">
|
|
<template #item="{ item, selected }">
|
|
<div class="x-friend-item flex w-full items-center">
|
|
<template v-if="item.user">
|
|
<div class="avatar" :class="userStatusClass(item.user)">
|
|
<img :src="userImage(item.user)" loading="lazy" />
|
|
</div>
|
|
<div class="detail">
|
|
<span
|
|
class="name"
|
|
:style="{ color: item.user.$userColour }"
|
|
v-text="item.user.displayName"></span>
|
|
</div>
|
|
</template>
|
|
<template v-else>
|
|
<span v-text="item.label"></span>
|
|
</template>
|
|
|
|
<CheckIcon :class="['ml-auto size-4', selected ? 'opacity-100' : 'opacity-0']" />
|
|
</div>
|
|
</template>
|
|
</VirtualCombobox>
|
|
</div>
|
|
</div>
|
|
<template #footer>
|
|
<el-button
|
|
type="primary"
|
|
:disabled="inviteGroupDialog.loading || !inviteGroupDialog.userIds.length || !inviteGroupDialog.groupId"
|
|
@click="sendGroupInvite">
|
|
{{ t('dialog.invite_to_group.invite') }}
|
|
</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, nextTick, ref, watch } from 'vue';
|
|
import { Check as CheckIcon } from 'lucide-vue-next';
|
|
import { ElMessageBox } from 'element-plus';
|
|
import { storeToRefs } from 'pinia';
|
|
import { toast } from 'vue-sonner';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
import { hasGroupPermission, userImage, userStatusClass } from '../../shared/utils';
|
|
import { groupRequest, userRequest } from '../../api';
|
|
import { useFriendStore, useGroupStore } from '../../stores';
|
|
import { VirtualCombobox } from '../ui/virtual-combobox';
|
|
import { getNextDialogIndex } from '../../shared/utils/base/ui';
|
|
|
|
import configRepository from '../../service/config';
|
|
|
|
const { vipFriends, onlineFriends, activeFriends, offlineFriends } = storeToRefs(useFriendStore());
|
|
const { currentUserGroups, inviteGroupDialog } = storeToRefs(useGroupStore());
|
|
const { applyGroup } = useGroupStore();
|
|
const { t } = useI18n();
|
|
|
|
watch(
|
|
() => inviteGroupDialog.value.visible,
|
|
async (value) => {
|
|
if (value) {
|
|
inviteGroupDialog.value.groupId = await configRepository.getString('inviteGroupLastGroup', '');
|
|
initDialog();
|
|
} else {
|
|
await configRepository.setString('inviteGroupLastGroup', inviteGroupDialog.value.groupId);
|
|
}
|
|
}
|
|
);
|
|
|
|
const inviteGroupDialogIndex = ref(2000);
|
|
|
|
const groupsWithInvitePermission = computed(() => {
|
|
return Array.from(currentUserGroups.value.values()).filter((group) =>
|
|
hasGroupPermission(group, 'group-invites-manage')
|
|
);
|
|
});
|
|
|
|
const groupPickerGroups = computed(() => [
|
|
{
|
|
key: 'groupsWithInvitePermission',
|
|
label: t('dialog.invite_to_group.groups_with_invite_permission'),
|
|
items: groupsWithInvitePermission.value.map((group) => ({
|
|
value: String(group.id),
|
|
label: group.name,
|
|
search: group.name,
|
|
iconUrl: group.iconUrl
|
|
}))
|
|
}
|
|
]);
|
|
|
|
const friendById = computed(() => {
|
|
const map = new Map();
|
|
for (const friend of vipFriends.value) map.set(friend.id, friend);
|
|
for (const friend of onlineFriends.value) map.set(friend.id, friend);
|
|
for (const friend of activeFriends.value) map.set(friend.id, friend);
|
|
for (const friend of offlineFriends.value) map.set(friend.id, friend);
|
|
return map;
|
|
});
|
|
|
|
function resolveUserDisplayName(userId) {
|
|
const D = inviteGroupDialog.value;
|
|
if (D?.userObject?.id && D.userObject.id === userId) {
|
|
return D.userObject.displayName;
|
|
}
|
|
const friend = friendById.value.get(userId);
|
|
return friend?.ref?.displayName ?? friend?.name ?? String(userId);
|
|
}
|
|
|
|
const friendPickerGroups = computed(() => {
|
|
const D = inviteGroupDialog.value;
|
|
|
|
const groups = [];
|
|
|
|
if (D?.userId) {
|
|
const selectedUser = D.userObject?.id
|
|
? {
|
|
value: String(D.userObject.id),
|
|
label: D.userObject.displayName,
|
|
search: D.userObject.displayName,
|
|
user: D.userObject
|
|
}
|
|
: {
|
|
value: String(D.userId),
|
|
label: String(D.userId),
|
|
search: String(D.userId)
|
|
};
|
|
|
|
groups.push({
|
|
key: 'selectedUsers',
|
|
label: t('dialog.invite_to_group.selected_users'),
|
|
items: [selectedUser]
|
|
});
|
|
}
|
|
|
|
const addFriendGroup = (key, label, friends) => {
|
|
if (!friends?.length) return;
|
|
groups.push({
|
|
key,
|
|
label,
|
|
items: friends.map((friend) => {
|
|
const user = friend?.ref ?? null;
|
|
const displayName = resolveUserDisplayName(friend.id);
|
|
return {
|
|
value: String(friend.id),
|
|
label: displayName,
|
|
search: displayName,
|
|
user
|
|
};
|
|
})
|
|
});
|
|
};
|
|
|
|
addFriendGroup('vip', t('side_panel.favorite'), vipFriends.value);
|
|
addFriendGroup('online', t('side_panel.online'), onlineFriends.value);
|
|
addFriendGroup('active', t('side_panel.active'), activeFriends.value);
|
|
addFriendGroup('offline', t('side_panel.offline'), offlineFriends.value);
|
|
|
|
return groups;
|
|
});
|
|
|
|
watch(
|
|
() => inviteGroupDialog.value.groupId,
|
|
(groupId) => {
|
|
if (!inviteGroupDialog.value.visible) {
|
|
return;
|
|
}
|
|
if (!groupId) {
|
|
inviteGroupDialog.value.groupName = '';
|
|
return;
|
|
}
|
|
groupRequest
|
|
.getCachedGroup({ groupId })
|
|
.then((args) => {
|
|
inviteGroupDialog.value.groupName = args.ref.name;
|
|
})
|
|
.catch(() => {
|
|
inviteGroupDialog.value.groupId = '';
|
|
});
|
|
isAllowedToInviteToGroup();
|
|
}
|
|
);
|
|
|
|
function initDialog() {
|
|
nextTick(() => {
|
|
inviteGroupDialogIndex.value = getNextDialogIndex();
|
|
});
|
|
const D = inviteGroupDialog.value;
|
|
if (D.groupId) {
|
|
groupRequest
|
|
.getCachedGroup({
|
|
groupId: D.groupId
|
|
})
|
|
.then((args) => {
|
|
D.groupName = args.ref.name;
|
|
})
|
|
.catch(() => {
|
|
D.groupId = '';
|
|
});
|
|
isAllowedToInviteToGroup();
|
|
}
|
|
|
|
if (D.userId) {
|
|
userRequest.getCachedUser({ userId: D.userId }).then((args) => {
|
|
D.userObject = args.ref;
|
|
D.userIds = [D.userId];
|
|
});
|
|
}
|
|
}
|
|
function isAllowedToInviteToGroup() {
|
|
const D = inviteGroupDialog.value;
|
|
const groupId = D.groupId;
|
|
if (!groupId) {
|
|
return;
|
|
}
|
|
inviteGroupDialog.value.loading = true;
|
|
groupRequest
|
|
.getGroup({ groupId })
|
|
.then((args) => {
|
|
const ref = applyGroup(args.json);
|
|
if (hasGroupPermission(ref, 'group-invites-manage')) {
|
|
return args;
|
|
}
|
|
// not allowed to invite
|
|
inviteGroupDialog.value.groupId = '';
|
|
toast.error('You are not allowed to invite to this group');
|
|
return args;
|
|
})
|
|
.finally(() => {
|
|
inviteGroupDialog.value.loading = false;
|
|
});
|
|
}
|
|
function sendGroupInvite() {
|
|
ElMessageBox.confirm('Continue? Invite User(s) To Group', 'Confirm', {
|
|
confirmButtonText: 'Confirm',
|
|
cancelButtonText: 'Cancel',
|
|
type: 'info'
|
|
})
|
|
.then((action) => {
|
|
const D = inviteGroupDialog.value;
|
|
if (action !== 'confirm' || D.loading === true) {
|
|
return;
|
|
}
|
|
D.loading = true;
|
|
const inviteLoop = () => {
|
|
if (D.userIds.length === 0) {
|
|
D.loading = false;
|
|
return;
|
|
}
|
|
const receiverUserId = D.userIds.shift();
|
|
groupRequest
|
|
.sendGroupInvite({
|
|
groupId: D.groupId,
|
|
userId: receiverUserId
|
|
})
|
|
.then(inviteLoop)
|
|
.catch(() => {
|
|
D.loading = false;
|
|
});
|
|
};
|
|
inviteLoop();
|
|
})
|
|
.catch(() => {});
|
|
}
|
|
</script>
|