mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-21 07:43:50 +02:00
split user dialog
This commit is contained in:
214
src/components/dialogs/UserDialog/UserDialogWorldsTab.vue
Normal file
214
src/components/dialogs/UserDialog/UserDialogWorldsTab.vue
Normal file
@@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||
<div style="display: flex; align-items: center">
|
||||
<Button
|
||||
class="rounded-full"
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
:disabled="userDialog.isWorldsLoading"
|
||||
@click="refreshUserDialogWorlds()">
|
||||
<Spinner v-if="userDialog.isWorldsLoading" />
|
||||
<RefreshCw v-else />
|
||||
</Button>
|
||||
<span style="margin-left: 6px">{{
|
||||
t('dialog.user.worlds.total_count', { count: userDialog.worlds.length })
|
||||
}}</span>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center">
|
||||
<span class="mr-1">{{ t('dialog.user.worlds.sort_by') }}</span>
|
||||
<Select
|
||||
:model-value="userDialogWorldSortingKey"
|
||||
:disabled="userDialog.isWorldsLoading"
|
||||
@update:modelValue="setUserDialogWorldSortingByKey">
|
||||
<SelectTrigger size="sm" @click.stop>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem
|
||||
v-for="(item, key) in userDialogWorldSortingOptions"
|
||||
:key="String(key)"
|
||||
:value="String(key)">
|
||||
{{ t(item.name) }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span class="ml-2 mr-1">{{ t('dialog.user.worlds.order_by') }}</span>
|
||||
<Select
|
||||
:model-value="userDialogWorldOrderKey"
|
||||
:disabled="userDialog.isWorldsLoading"
|
||||
@update:modelValue="setUserDialogWorldOrderByKey">
|
||||
<SelectTrigger size="sm" @click.stop>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem
|
||||
v-for="(item, key) in userDialogWorldOrderOptions"
|
||||
:key="String(key)"
|
||||
:value="String(key)">
|
||||
{{ t(item.name) }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-start" style="margin-top: 8px; min-height: 60px">
|
||||
<template v-if="userDialog.worlds.length">
|
||||
<div
|
||||
v-for="world in userDialog.worlds"
|
||||
:key="world.id"
|
||||
class="box-border flex items-center p-1.5 text-[13px] cursor-pointer w-[167px] hover:rounded-[25px_5px_5px_25px]"
|
||||
@click="showWorldDialog(world.id)">
|
||||
<div class="relative inline-block flex-none size-9 mr-2.5">
|
||||
<img class="size-full rounded-full object-cover" :src="world.thumbnailImageUrl" loading="lazy" />
|
||||
</div>
|
||||
<div class="flex-1 overflow-hidden">
|
||||
<span class="block truncate font-medium leading-[18px]" v-text="world.name"></span>
|
||||
<span v-if="world.occupants" class="block truncate text-xs">({{ world.occupants }})</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div
|
||||
v-else-if="!userDialog.isWorldsLoading"
|
||||
style="display: flex; justify-content: center; align-items: center; min-height: 120px; width: 100%">
|
||||
<DataTableEmpty type="nodata" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { DataTableEmpty } from '@/components/ui/data-table';
|
||||
import { RefreshCw } from 'lucide-vue-next';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { useUserStore, useWorldStore } from '../../../stores';
|
||||
import { userDialogWorldOrderOptions, userDialogWorldSortingOptions } from '../../../shared/constants/';
|
||||
import { useOptionKeySelect } from '../../../composables/useOptionKeySelect';
|
||||
import { worldRequest } from '../../../api';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const userStore = useUserStore();
|
||||
const { userDialog, currentUser } = storeToRefs(userStore);
|
||||
const { cachedWorlds, showWorldDialog } = useWorldStore();
|
||||
|
||||
const userDialogWorldsRequestId = ref(0);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param userId
|
||||
*/
|
||||
function setUserDialogWorlds(userId) {
|
||||
const worlds = [];
|
||||
for (const ref of cachedWorlds.values()) {
|
||||
if (ref.authorId === userId) {
|
||||
worlds.push(ref);
|
||||
}
|
||||
}
|
||||
userDialog.value.worlds = worlds;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function refreshUserDialogWorlds() {
|
||||
const D = userDialog.value;
|
||||
if (D.isWorldsLoading) {
|
||||
return;
|
||||
}
|
||||
const requestId = ++userDialogWorldsRequestId.value;
|
||||
D.isWorldsLoading = true;
|
||||
const params = {
|
||||
n: 50,
|
||||
offset: 0,
|
||||
sort: userDialog.value.worldSorting.value,
|
||||
order: userDialog.value.worldOrder.value,
|
||||
// user: 'friends',
|
||||
userId: D.id,
|
||||
releaseStatus: 'public'
|
||||
};
|
||||
if (params.userId === currentUser.value.id) {
|
||||
params.user = 'me';
|
||||
params.releaseStatus = 'all';
|
||||
}
|
||||
const worlds = [];
|
||||
const worldIds = new Set();
|
||||
(async () => {
|
||||
try {
|
||||
let offset = 0;
|
||||
while (true) {
|
||||
const args = await worldRequest.getCachedWorlds({
|
||||
...params,
|
||||
offset
|
||||
});
|
||||
if (requestId !== userDialogWorldsRequestId.value || D.id !== params.userId) {
|
||||
return;
|
||||
}
|
||||
for (const world of args.json) {
|
||||
if (!worldIds.has(world.id)) {
|
||||
worldIds.add(world.id);
|
||||
worlds.push(world);
|
||||
}
|
||||
}
|
||||
if (args.json.length < params.n) {
|
||||
break;
|
||||
}
|
||||
offset += params.n;
|
||||
}
|
||||
if (requestId === userDialogWorldsRequestId.value && D.id === params.userId) {
|
||||
userDialog.value.worlds = worlds;
|
||||
}
|
||||
} finally {
|
||||
if (requestId === userDialogWorldsRequestId.value) {
|
||||
D.isWorldsLoading = false;
|
||||
}
|
||||
}
|
||||
})().catch((err) => {
|
||||
console.error('refreshUserDialogWorlds failed', err);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sortOrder
|
||||
*/
|
||||
async function setUserDialogWorldSorting(sortOrder) {
|
||||
const D = userDialog.value;
|
||||
if (D.worldSorting.value === sortOrder.value) {
|
||||
return;
|
||||
}
|
||||
D.worldSorting = sortOrder;
|
||||
refreshUserDialogWorlds();
|
||||
}
|
||||
|
||||
const { selectedKey: userDialogWorldSortingKey, selectByKey: setUserDialogWorldSortingByKey } = useOptionKeySelect(
|
||||
userDialogWorldSortingOptions,
|
||||
() => userDialog.value.worldSorting,
|
||||
setUserDialogWorldSorting
|
||||
);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param order
|
||||
*/
|
||||
async function setUserDialogWorldOrder(order) {
|
||||
const D = userDialog.value;
|
||||
if (D.worldOrder.value === order.value) {
|
||||
return;
|
||||
}
|
||||
D.worldOrder = order;
|
||||
refreshUserDialogWorlds();
|
||||
}
|
||||
|
||||
const { selectedKey: userDialogWorldOrderKey, selectByKey: setUserDialogWorldOrderByKey } = useOptionKeySelect(
|
||||
userDialogWorldOrderOptions,
|
||||
() => userDialog.value.worldOrder,
|
||||
setUserDialogWorldOrder
|
||||
);
|
||||
|
||||
defineExpose({ setUserDialogWorlds, refreshUserDialogWorlds });
|
||||
</script>
|
||||
Reference in New Issue
Block a user