Client - add selects to sort users in administration

This commit is contained in:
Sam 2021-10-31 13:27:16 +01:00
parent 80afbe5968
commit 4a5f175053
9 changed files with 189 additions and 26 deletions

View File

@ -54,7 +54,7 @@
</td> </td>
<td class="sport-action"> <td class="sport-action">
<span class="cell-heading"> <span class="cell-heading">
{{ $t('admin.SPORTS.TABLE.ACTION') }} {{ $t('admin.ACTION') }}
</span> </span>
<div class="action-button"> <div class="action-button">
<button <button

View File

@ -6,6 +6,12 @@
<button class="top-button" @click.prevent="$router.push('/admin')"> <button class="top-button" @click.prevent="$router.push('/admin')">
{{ $t('admin.BACK_TO_ADMIN') }} {{ $t('admin.BACK_TO_ADMIN') }}
</button> </button>
<AdminUsersSelects
:sort="sort"
:order_by="order_by"
:query="query"
@updateSelect="reloadUsers"
/>
<div class="responsive-table"> <div class="responsive-table">
<table> <table>
<thead> <thead>
@ -101,35 +107,39 @@
ComputedRef, ComputedRef,
computed, computed,
defineComponent, defineComponent,
reactive,
watch, watch,
capitalize, capitalize,
onBeforeMount, onBeforeMount,
} from 'vue' } from 'vue'
import { useRoute, LocationQuery } from 'vue-router' import { LocationQuery, useRoute, useRouter } from 'vue-router'
import AdminUsersSelects from '@/components/Administration/AdminUsersSelects.vue'
import Pagination from '@/components/Common/Pagination.vue' import Pagination from '@/components/Common/Pagination.vue'
import { ROOT_STORE, USER_STORE, USERS_STORE } from '@/store/constants' import { ROOT_STORE, USER_STORE, USERS_STORE } from '@/store/constants'
import { IPagination, IPaginationPayload } from '@/types/api' import { IPagination, TPaginationPayload } from '@/types/api'
import { IUserProfile } from '@/types/user' import { IUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
export default defineComponent({ export default defineComponent({
name: 'AdminUsers', name: 'AdminUsers',
components: { components: {
AdminUsersSelects,
Pagination, Pagination,
}, },
setup() { setup() {
const store = useStore() const store = useStore()
const route = useRoute() const route = useRoute()
const router = useRouter()
const orders: string[] = ['asc', 'desc'] const sort: string[] = ['asc', 'desc']
const order_types: string[] = [ const order_by: string[] = [
'admin', 'admin',
'created_at', 'created_at',
'username', 'username',
'workouts_count', 'workouts_count',
] ]
let query: IPaginationPayload = getQuery(route.query) let query: TPaginationPayload = reactive(getQuery(route.query))
const authUser: ComputedRef<IUserProfile> = computed( const authUser: ComputedRef<IUserProfile> = computed(
() => store.getters[USER_STORE.GETTERS.AUTH_USER_PROFILE] () => store.getters[USER_STORE.GETTERS.AUTH_USER_PROFILE]
@ -144,7 +154,7 @@
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES] () => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
) )
function loadUsers(queryParams: IPaginationPayload) { function loadUsers(queryParams: TPaginationPayload) {
store.dispatch(USERS_STORE.ACTIONS.GET_USERS, queryParams) store.dispatch(USERS_STORE.ACTIONS.GET_USERS, queryParams)
} }
function getPage(page: string | (string | null)[] | null): number { function getPage(page: string | (string | null)[] | null): number {
@ -156,18 +166,16 @@
: 10 : 10
} }
function getOrder(order: string | (string | null)[] | null): string { function getOrder(order: string | (string | null)[] | null): string {
return order && typeof order === 'string' && orders.includes(order) return order && typeof order === 'string' && sort.includes(order)
? order ? order
: 'asc' : 'asc'
} }
function getOrderBy(order_by: string | (string | null)[] | null): string { function getOrderBy(order: string | (string | null)[] | null): string {
return order_by && return order && typeof order === 'string' && order_by.includes(order)
typeof order_by === 'string' && ? order
order_types.includes(order_by)
? order_by
: 'created_at' : 'created_at'
} }
function getQuery(query: LocationQuery): IPaginationPayload { function getQuery(query: LocationQuery): TPaginationPayload {
return { return {
page: getPage(query.page), page: getPage(query.page),
per_page: getPerPage(query.per_page), per_page: getPerPage(query.per_page),
@ -181,14 +189,24 @@
admin, admin,
}) })
} }
function reloadUsers(queryParam: string, queryValue: string) {
query[queryParam] = queryValue
if (queryParam === 'per_page') {
query.page = 1
}
router.push({ path: '/admin/users', query })
}
onBeforeMount(() => loadUsers(query)) onBeforeMount(() => loadUsers(query))
watch( watch(
() => route.query, () => route.query,
(newQuery) => { (newQuery: LocationQuery) => {
query = getQuery(newQuery) query.page = getPage(newQuery.page)
loadUsers(getQuery(newQuery)) query.per_page = getPerPage(newQuery.per_page)
query.order = getOrder(newQuery.order)
query.order_by = getOrderBy(newQuery.order_by)
loadUsers(query)
} }
) )
@ -196,9 +214,12 @@
authUser, authUser,
errorMessages, errorMessages,
pagination, pagination,
order_by,
query, query,
sort,
users, users,
capitalize, capitalize,
reloadUsers,
updateUser, updateUser,
} }
}, },
@ -225,6 +246,9 @@
display: block; display: block;
margin-bottom: $default-margin * 2; margin-bottom: $default-margin * 2;
} }
.pagination-center {
margin-top: -3 * $default-margin;
}
} }
} }
</style> </style>

View File

@ -0,0 +1,105 @@
<template>
<div class="table-selects">
<label>
{{ $t('admin.USERS.SELECTS.ORDER_BY.LABEL') }}:
<select
name="order_by"
id="order_by"
:value="query.order_by"
@change="onSelectUpdate"
>
<option v-for="order in order_by" :value="order" :key="order">
{{ $t(`admin.USERS.SELECTS.ORDER_BY.${order}`) }}
</option>
</select>
</label>
<label>
{{ $t('admin.USERS.SELECTS.ORDER.LABEL') }}:
<select
name="order"
id="order"
:value="query.order"
@change="onSelectUpdate"
>
<option v-for="order in sort" :value="order" :key="order">
{{ $t(`admin.USERS.SELECTS.ORDER.${order.toUpperCase()}`) }}
</option>
</select>
</label>
<label>
{{ $t('admin.USERS.SELECTS.PER_PAGE.LABEL') }}:
<select
name="per_page"
id="per_page"
:value="query.per_page"
@change="onSelectUpdate"
>
<option v-for="nb in per_page" :value="nb" :key="nb">
{{ nb }}
</option>
</select>
</label>
</div>
</template>
<script lang="ts">
import { PropType, defineComponent } from 'vue'
import { TPaginationPayload } from '@/types/api'
export default defineComponent({
name: 'AdminUsersSelects',
props: {
order_by: {
type: Object as PropType<string[]>,
required: true,
},
query: {
type: Object as PropType<TPaginationPayload>,
required: true,
},
sort: {
type: Object as PropType<string[]>,
required: true,
},
},
emits: ['updateSelect'],
setup(props, { emit }) {
function onSelectUpdate(event: Event & { target: HTMLInputElement }) {
emit('updateSelect', event.target.id, event.target.value)
}
return {
per_page: [10, 50, 100],
onSelectUpdate,
}
},
})
</script>
<style lang="scss" scoped>
@import '~@/scss/base.scss';
.table-selects {
display: flex;
justify-content: space-between;
margin: $default-margin 0;
label {
select {
margin-left: $default-margin;
padding: $default-padding * 0.5;
}
}
@media screen and (max-width: $small-limit) {
flex-wrap: wrap;
label {
margin-bottom: $default-margin;
select {
margin-left: 0;
}
}
}
}
</style>

View File

@ -38,7 +38,7 @@
<script lang="ts"> <script lang="ts">
import { PropType, defineComponent } from 'vue' import { PropType, defineComponent } from 'vue'
import { IPagination, IPaginationPayload } from '@/types/api' import { IPagination, TPaginationPayload } from '@/types/api'
export default defineComponent({ export default defineComponent({
name: 'Pagination', name: 'Pagination',
@ -52,7 +52,7 @@
required: true, required: true,
}, },
query: { query: {
type: Object as PropType<IPaginationPayload>, type: Object as PropType<TPaginationPayload>,
required: true, required: true,
}, },
}, },
@ -60,7 +60,7 @@
function rangePagination(pages: number): number[] { function rangePagination(pages: number): number[] {
return Array.from({ length: pages }, (_, i) => i + 1) return Array.from({ length: pages }, (_, i) => i + 1)
} }
function getQuery(page: number, cursor?: number): IPaginationPayload { function getQuery(page: number, cursor?: number): TPaginationPayload {
const newQuery = Object.assign({}, props.query) const newQuery = Object.assign({}, props.query)
newQuery.page = cursor ? page + cursor : page newQuery.page = cursor ? page + cursor : page
return newQuery return newQuery

View File

@ -31,6 +31,23 @@
"TABLE": { "TABLE": {
"ADD_ADMIN_RIGHTS": "Add admin rights", "ADD_ADMIN_RIGHTS": "Add admin rights",
"REMOVE_ADMIN_RIGHTS": "Remove admin rights" "REMOVE_ADMIN_RIGHTS": "Remove admin rights"
},
"SELECTS": {
"ORDER_BY": {
"LABEL": "order by",
"admin": "admin status",
"created_at": "registration date",
"username": "username",
"workouts_count": "workout count"
},
"ORDER": {
"LABEL": "sort",
"ASC": "ascending",
"DESC": "descending"
},
"PER_PAGE": {
"LABEL": "par page"
}
} }
} }
} }

View File

@ -31,6 +31,23 @@
"TABLE": { "TABLE": {
"ADD_ADMIN_RIGHTS": "Ajouter les drois d'admin", "ADD_ADMIN_RIGHTS": "Ajouter les drois d'admin",
"REMOVE_ADMIN_RIGHTS": "Retirer les drois d'admin" "REMOVE_ADMIN_RIGHTS": "Retirer les drois d'admin"
},
"SELECTS": {
"ORDER_BY": {
"LABEL": "trier par ",
"admin": "status administrateur",
"created_at": "date d'inscription",
"username": "nom d'utilisateur",
"workouts_count": "nombre de séances"
},
"ORDER": {
"LABEL": "tri",
"ASC": "ascendant",
"DESC": "descendant"
},
"PER_PAGE": {
"LABEL": "par page"
}
} }
} }
} }

View File

@ -4,14 +4,14 @@ import authApi from '@/api/authApi'
import { ROOT_STORE, USERS_STORE } from '@/store/constants' import { ROOT_STORE, USERS_STORE } from '@/store/constants'
import { IRootState } from '@/store/modules/root/types' import { IRootState } from '@/store/modules/root/types'
import { IUsersActions, IUsersState } from '@/store/modules/users/types' import { IUsersActions, IUsersState } from '@/store/modules/users/types'
import { IPaginationPayload } from '@/types/api' import { TPaginationPayload } from '@/types/api'
import { IAdminUserPayload } from '@/types/user' import { IAdminUserPayload } from '@/types/user'
import { handleError } from '@/utils' import { handleError } from '@/utils'
export const actions: ActionTree<IUsersState, IRootState> & IUsersActions = { export const actions: ActionTree<IUsersState, IRootState> & IUsersActions = {
[USERS_STORE.ACTIONS.GET_USERS]( [USERS_STORE.ACTIONS.GET_USERS](
context: ActionContext<IUsersState, IRootState>, context: ActionContext<IUsersState, IRootState>,
payload: IPaginationPayload payload: TPaginationPayload
): void { ): void {
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES) context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
context.commit(USERS_STORE.MUTATIONS.UPDATE_USERS_LOADING, true) context.commit(USERS_STORE.MUTATIONS.UPDATE_USERS_LOADING, true)
@ -40,7 +40,6 @@ export const actions: ActionTree<IUsersState, IRootState> & IUsersActions = {
context: ActionContext<IUsersState, IRootState>, context: ActionContext<IUsersState, IRootState>,
payload: IAdminUserPayload payload: IAdminUserPayload
): void { ): void {
console.log('payload', payload)
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES) context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
authApi authApi
.patch(`users/${payload.username}`, { admin: payload.admin }) .patch(`users/${payload.username}`, { admin: payload.admin })

View File

@ -7,7 +7,7 @@ import {
import { USERS_STORE } from '@/store/constants' import { USERS_STORE } from '@/store/constants'
import { IRootState } from '@/store/modules/root/types' import { IRootState } from '@/store/modules/root/types'
import { IPagination, IPaginationPayload } from '@/types/api' import { IPagination, TPaginationPayload } from '@/types/api'
import { IAdminUserPayload, IUserProfile } from '@/types/user' import { IAdminUserPayload, IUserProfile } from '@/types/user'
export interface IUsersState { export interface IUsersState {
@ -19,7 +19,7 @@ export interface IUsersState {
export interface IUsersActions { export interface IUsersActions {
[USERS_STORE.ACTIONS.GET_USERS]( [USERS_STORE.ACTIONS.GET_USERS](
context: ActionContext<IUsersState, IRootState>, context: ActionContext<IUsersState, IRootState>,
payload: IPaginationPayload payload: TPaginationPayload
): void ): void
[USERS_STORE.ACTIONS.UPDATE_USER]( [USERS_STORE.ACTIONS.UPDATE_USER](
context: ActionContext<IUsersState, IRootState>, context: ActionContext<IUsersState, IRootState>,

View File

@ -6,7 +6,8 @@ export interface IPagination {
total: number total: number
} }
export interface IPaginationPayload { export type TPaginationPayload = {
[key: string]: string | number
order: string order: string
order_by: string order_by: string
per_page: number per_page: number