Client - filter on username in administration

This commit is contained in:
Sam 2022-03-13 10:52:10 +01:00
parent 08d412bddf
commit f241504b8f
7 changed files with 137 additions and 5 deletions

View File

@ -6,6 +6,7 @@
<button class="top-button" @click.prevent="$router.push('/admin')">
{{ $t('admin.BACK_TO_ADMIN') }}
</button>
<UsersNameFilter @filterOnUsername="searchUsers" />
<FilterSelects
:sort="sortList"
:order_by="orderByList"
@ -13,7 +14,10 @@
message="admin.USERS.SELECTS.ORDER_BY"
@updateSelect="reloadUsers"
/>
<div class="responsive-table">
<div class="no-users" v-if="users.length === 0">
{{ $t('user.NO_USERS_FOUND') }}
</div>
<div class="responsive-table" v-else>
<table>
<thead>
<tr>
@ -119,6 +123,7 @@
import { format } from 'date-fns'
import {
ComputedRef,
Ref,
computed,
reactive,
watch,
@ -131,6 +136,7 @@
import FilterSelects from '@/components/Common/FilterSelects.vue'
import Pagination from '@/components/Common/Pagination.vue'
import UserPicture from '@/components/User/UserPicture.vue'
import UsersNameFilter from '@/components/Users/UsersNameFilter.vue'
import { AUTH_USER_STORE, ROOT_STORE, USERS_STORE } from '@/store/constants'
import { IPagination, TPaginationPayload } from '@/types/api'
import { IAuthUserProfile, IUserProfile } from '@/types/user'
@ -170,6 +176,10 @@
function loadUsers(queryParams: TPaginationPayload) {
store.dispatch(USERS_STORE.ACTIONS.GET_USERS, queryParams)
}
function searchUsers(username: Ref<string>) {
reloadUsers('q', username.value)
}
function updateUser(username: string, admin: boolean) {
store.dispatch(USERS_STORE.ACTIONS.UPDATE_USER, {
username,
@ -203,6 +213,14 @@
.top-button {
display: none;
}
.no-users {
display: flex;
justify-content: center;
padding: $default-padding * 2 0;
font-weight: bold;
}
table {
td {
font-size: 1.1em;

View File

@ -45,20 +45,23 @@
<script setup lang="ts">
import { toRefs } from 'vue'
import { IPagination } from '@/types/api'
import { IPagination, TPaginationPayload } from '@/types/api'
import { TWorkoutsPayload } from '@/types/workouts'
import { rangePagination } from '@/utils/api'
interface Props {
pagination: IPagination
path: string
query: TWorkoutsPayload
query: TWorkoutsPayload | TPaginationPayload
}
const props = defineProps<Props>()
const { pagination, path, query } = toRefs(props)
function getQuery(page: number, cursor?: number): TWorkoutsPayload {
function getQuery(
page: number,
cursor?: number
): TWorkoutsPayload | TPaginationPayload {
const newQuery = Object.assign({}, query.value)
newQuery.page = cursor ? page + cursor : page
return newQuery

View File

@ -0,0 +1,101 @@
<template>
<div class="users-filters">
<div class="search-username">
<input
id="username"
name="username"
v-model.trim="username"
@keyup.enter="searchUsers"
:placeholder="$t('user.FILTER_ON_USERNAME')"
/>
<i
v-if="username !== ''"
class="fa fa-times"
aria-hidden="true"
@click="resetFilter"
/>
</div>
<i
class="fa fa-search"
:class="{ 'fa-disabled': username === '' }"
aria-hidden="true"
@click="searchUsers"
/>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const username = ref(route.query.q ? route.query.q : '')
const emit = defineEmits(['filterOnUsername'])
function searchUsers() {
if (username.value !== '') {
emit('filterOnUsername', username)
}
}
function resetFilter() {
username.value = ''
emit('filterOnUsername', username.value)
}
</script>
<style lang="scss" scoped>
@import '~@/scss/vars.scss';
.users-filters {
display: flex;
align-items: center;
padding: $default-padding 0;
gap: $default-padding;
.fa {
font-size: 1.5em;
}
.fa-disabled {
color: var(--disabled-color);
}
.search-username {
display: flex;
align-items: center;
justify-content: space-between;
gap: $default-padding;
border: solid 1px var(--card-border-color);
border-radius: $border-radius;
color: var(--info-color);
width: 45%;
input {
border: none;
height: 12px;
width: 90%;
}
input:focus {
outline: none;
}
.fa-times {
padding-right: 10px;
}
}
}
@media screen and (max-width: $small-limit) {
.users-filters {
.search-username {
width: 400px;
}
}
}
@media screen and (max-width: $x-small-limit) {
.users-filters {
.search-username {
width: 90%;
}
}
}
</style>

View File

@ -6,6 +6,7 @@
"EMAIL": "Email",
"EMAIL_INFO": "Enter a valid email address.",
"ENTER_PASSWORD": "Enter a password",
"FILTER_ON_USERNAME": "Filter on username",
"HIDE_PASSWORD": "hide password",
"INVALID_TOKEN": "Invalid token, please request a new password reset.",
"LANGUAGE": "Language",
@ -13,6 +14,7 @@
"LOGIN": "Login",
"LOGOUT": "Logout",
"NEW_PASSWORD": "New password",
"NO_USERS_FOUND": "No users found.",
"PASSWORD": "Password",
"PASSWORD_INFO": "At least 8 characters required.",
"PASSWORD_FORGOTTEN": "Forgot password?",

View File

@ -6,6 +6,7 @@
"EMAIL": "Email",
"EMAIL_INFO": "Saisir une adresse email valide.",
"ENTER_PASSWORD": "Saisir un mot de passe",
"FILTER_ON_USERNAME": "Filtrer sur le nom d'utilisateur",
"HIDE_PASSWORD": "masquer le mot de passe",
"INVALID_TOKEN": "Jeton invalide, veuillez demander une nouvelle réinitialisation de mot de passe.",
"LANGUAGE": "Langue",
@ -13,6 +14,7 @@
"LOGIN": "Se connecter",
"LOGOUT": "Se déconnecter",
"NEW_PASSWORD": "Nouveau mot de passe",
"NO_USERS_FOUND": "Aucun utilisateur trouvé.",
"PASSWORD": "Mot de passe",
"PASSWORD_INFO": "8 caractères minimum.",
"PASSWORD_FORGOTTEN": "Mot de passe oublié ?",

View File

@ -7,11 +7,12 @@ export interface IPagination {
}
export type TPaginationPayload = {
[key: string]: string | number
[key: string]: string | number | undefined
order: string
order_by: string
per_page: number
page: number
q?: string
}
export interface IQueryOptions {

View File

@ -45,6 +45,11 @@ export const getQuery = (
orderByList,
defaultOrderBy
)
if (typeof locationQuery.q === 'string') {
query.q = locationQuery.q
} else {
delete query.q
}
return query
}