Client - filter on username in administration
This commit is contained in:
parent
08d412bddf
commit
f241504b8f
@ -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;
|
||||
|
@ -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
|
||||
|
101
fittrackee_client/src/components/Users/UsersNameFilter.vue
Normal file
101
fittrackee_client/src/components/Users/UsersNameFilter.vue
Normal 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>
|
@ -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?",
|
||||
|
@ -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é ?",
|
||||
|
@ -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 {
|
||||
|
@ -45,6 +45,11 @@ export const getQuery = (
|
||||
orderByList,
|
||||
defaultOrderBy
|
||||
)
|
||||
if (typeof locationQuery.q === 'string') {
|
||||
query.q = locationQuery.q
|
||||
} else {
|
||||
delete query.q
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user