Files
web-frontend/app/pages/clients/index.vue
2026-04-06 16:12:54 +07:00

105 lines
2.8 KiB
Vue

<script setup lang="ts">
import { useQuery } from '@vue/apollo-composable';
import { ManagerUsersDocument } from '~/composables/graphql/generated';
import { messengerConnectionAvatarSrc } from '~/composables/useMessengerConnectionPresentation';
definePageMeta({
middleware: ['manager-only'],
path: '/admin/orders/clients',
alias: ['/clients'],
});
const search = ref('');
const usersQuery = useQuery(ManagerUsersDocument);
const filteredUsers = computed(() => {
const items = usersQuery.result.value?.managerUsers ?? [];
const query = search.value.trim().toLowerCase();
return items.filter((item) => {
if (!query) {
return true;
}
return [
item.fullName,
item.email,
item.companyName || '',
]
.join(' ')
.toLowerCase()
.includes(query);
});
});
const {
canLoadMore: canLoadMoreUsers,
loadMore: loadMoreUsers,
loadMoreSentinel: loadMoreUsersSentinel,
remainingCount: remainingUsersCount,
visibleItems: visibleUsers,
} = useIncrementalList(filteredUsers, {
pageSize: 24,
resetKeys: [search],
});
function userInitials(fullName: string) {
const parts = fullName
.trim()
.split(/\s+/)
.filter(Boolean)
.slice(0, 2);
if (!parts.length) {
return 'FR';
}
return parts.map((part) => part[0]?.toUpperCase() ?? '').join('');
}
</script>
<template>
<section class="space-y-6">
<UiSectionSearchHero
v-model="search"
title="Клиенты"
search-placeholder="Имя, компания или email"
>
<template #controls>
<NuxtLink to="/admin/orders/clients/invite" class="btn btn-primary border-0">
Пригласить
</NuxtLink>
</template>
</UiSectionSearchHero>
<div v-if="usersQuery.loading.value" class="manager-empty-state">
Загружаем пользователей...
</div>
<div v-else-if="filteredUsers.length === 0" class="manager-empty-state">
Пользователи по текущему запросу не найдены.
</div>
<div v-else class="space-y-4">
<div class="grid gap-4 sm:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-6">
<UsersGridCard
v-for="user in visibleUsers"
:key="user.id"
:to="`/admin/orders/clients/${user.id}`"
:full-name="user.fullName"
:avatar-src="messengerConnectionAvatarSrc(user.telegramConnection)"
:initials="userInitials(user.fullName)"
/>
</div>
<div
v-if="canLoadMoreUsers"
ref="loadMoreUsersSentinel"
class="flex justify-center"
>
<button class="btn btn-outline border-[#d7e9de] bg-white" @click="loadMoreUsers">
Показать ещё {{ Math.min(remainingUsersCount, 24) }}
</button>
</div>
</div>
</section>
</template>