Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Admins should be able to filter and sort users #709

Draft
wants to merge 10 commits into
base: develop
Choose a base branch
from
83 changes: 65 additions & 18 deletions pages/admin/settings/users.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
<template>
<div class="flex flex-col max-w-md gap-2 mx-auto">
<div class="flex flex-col gap-2">
<div class="pl-0.5 flex flex-wrap gap-2">
<input
v-model="searchQuery"
name="search"
type="text"
class="h-8 border-2 input input-bordered rounded-2xl placeholder-neutral-content"
:placeholder="`Filter by username`"
>
<div class="pl-0.5 flex flex-col gap-2">
<div class="flex gap-2">
<TorrustSelect
v-model:selected="filters"
:options="filteringOptions.map(entry => ({ name: entry.name, value: entry.value }))"
label="Filter by"
:multiple="true"
/>
<TorrustSelect
v-model:selected="selectedSorting"
:options="sortingOptions"
label="Sort by"
/>

</div>
<div class="flex flex-col w-full gap-2">
<input
v-model="searchQuery"
name="search"
type="text"
class="h-8 w-full border-2 input input-bordered rounded-2xl placeholder-neutral-content"
:placeholder="`Filter by username`"
>
</div>
<UserTable :user-profiles="userProfiles" />
<Pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:total-results="userProfilesTotal"
/>
</div>
<UserTable :user-profiles="userProfiles" />
<Pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :total-results="userProfilesTotal" />
</div>
</div>
</template>
Expand All @@ -23,6 +42,20 @@ import { notify } from "notiwind-ts";
import type { UserProfile } from "torrust-index-types-lib";
import { onMounted, ref, watch } from "#imports";
import { useRestApi } from "~/composables/states";
import type { TorrustSelectOption } from "components/TorrustSelect.vue";

const filteringOptions: Array<TorrustSelectOption> = [
{ name: "Email verified", value: "EmailVerified" },
{ name: "Email not verified", value: "EmailNotVerified" },
{ name: "Torrent uploader", value: "TorrentUploader" }
];

const sortingOptions: Array<TorrustSelectOption> = [
{ name: "Registration date (Newest first)", value: "DateRegisteredNewest" },
{ name: "Registration date (Oldest first)", value: "DateRegisteredOldest" },
{ name: "Username (A to Z)", value: "UsernameAZ" },
{ name: "Username (Z to A)", value: "UsernameZA" }
];

const route = useRoute();
const router = useRouter();
Expand All @@ -35,17 +68,26 @@ const userProfiles: Ref<Array<UserProfile>> = ref([]);
const userProfilesTotal = ref(0);
const currentPage: Ref<number> = ref(Number(route.query?.page as string) || 1);
const searchQuery: Ref<string> = ref(null);
const queryFilters = route.query?.filters as string[] || [];
const filters: Ref<string[]> = ref(Array.isArray(queryFilters) ? queryFilters : [queryFilters]);
const itemsSorting: Ref<string> = ref(route.query?.sorting as string || sortingOptions[0].value);

watch(() => route.fullPath, () => {
searchQuery.value = route.query.search as string ?? null;
currentPage.value = isNaN(route.query.page) ? 1 : parseInt(route.query.page);
pageSize.value = isNaN(route.query.pageSize) ? defaultPageSize : parseInt(route.query.pageSize);
const selectedSorting = computed({
get () {
return [itemsSorting.value];
},
set (value) {
itemsSorting.value = value[0];
currentPage.value = 1;
}
});

watch(currentPage, () => {
router.push({
router.replace({
query: {
search: searchQuery.value,
filters: filters.value.length > 0 ? filters.value : [],
sorting: itemsSorting.value ? itemsSorting.value : sortingOptions[0].value,
pageSize: pageSize.value,
page: currentPage.value
}
Expand All @@ -54,11 +96,12 @@ watch(currentPage, () => {
loadUserProfiles();
});

// Resets the current page value to 1 when the page size is changed to display results correctly
watch([pageSize, searchQuery], () => {
router.push({
watch([pageSize, searchQuery, filters, itemsSorting], () => {
router.replace({
query: {
search: searchQuery.value,
filters: filters.value.length > 0 ? filters.value : [],
sorting: itemsSorting.value ? itemsSorting.value : sortingOptions[0].value,
pageSize: pageSize.value,
page: 1
}
Expand All @@ -69,6 +112,8 @@ watch([pageSize, searchQuery], () => {

onActivated(() => {
searchQuery.value = route.query.search as string ?? null;
filters.value = route.query.filters as string[] ?? null;
itemsSorting.value = route.query.sorting as string ?? sortingOptions[0].value;
pageSize.value = route.query.pageSize as number ?? defaultPageSize;
currentPage.value = route.query.page as number ?? 1;
});
Expand All @@ -81,6 +126,8 @@ onMounted(() => {
function loadUserProfiles () {
rest.value.user.getUserProfiles(
{
filters: filters.value,
sorting: itemsSorting.value,
pageSize: pageSize.value,
page: currentPage.value,
searchQuery: searchQuery.value
Expand Down