diff --git a/fittrackee_client/src/components/Administration/AdminUsers.vue b/fittrackee_client/src/components/Administration/AdminUsers.vue
index bf4a56d6..022f2f07 100644
--- a/fittrackee_client/src/components/Administration/AdminUsers.vue
+++ b/fittrackee_client/src/components/Administration/AdminUsers.vue
@@ -7,8 +7,8 @@
{{ $t('admin.BACK_TO_ADMIN') }}
@@ -135,6 +135,7 @@
import { IPagination, TPaginationPayload } from '@/types/api'
import { IUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
+ import { getQuery, sortList } from '@/utils/api'
import { getDateWithTZ } from '@/utils/dates'
export default defineComponent({
@@ -149,14 +150,16 @@
const route = useRoute()
const router = useRouter()
- const sort: string[] = ['asc', 'desc']
- const order_by: string[] = [
+ const orderByList: string[] = [
'admin',
'created_at',
'username',
'workouts_count',
]
- let query: TPaginationPayload = reactive(getQuery(route.query))
+ const defaultOrderBy = 'created_at'
+ let query: TPaginationPayload = reactive(
+ getQuery(route.query, orderByList, defaultOrderBy)
+ )
const authUser: ComputedRef = computed(
() => store.getters[USER_STORE.GETTERS.AUTH_USER_PROFILE]
@@ -174,32 +177,6 @@
function loadUsers(queryParams: TPaginationPayload) {
store.dispatch(USERS_STORE.ACTIONS.GET_USERS, queryParams)
}
- function getPage(page: string | (string | null)[] | null): number {
- return page && typeof page === 'string' && +page > 0 ? +page : 1
- }
- function getPerPage(perPage: string | (string | null)[] | null): number {
- return perPage && typeof perPage === 'string' && +perPage > 0
- ? +perPage
- : 10
- }
- function getOrder(order: string | (string | null)[] | null): string {
- return order && typeof order === 'string' && sort.includes(order)
- ? order
- : 'asc'
- }
- function getOrderBy(order: string | (string | null)[] | null): string {
- return order && typeof order === 'string' && order_by.includes(order)
- ? order
- : 'created_at'
- }
- function getQuery(query: LocationQuery): TPaginationPayload {
- return {
- page: getPage(query.page),
- per_page: getPerPage(query.per_page),
- order: getOrder(query.order),
- order_by: getOrderBy(query.order_by),
- }
- }
function updateUser(username: string, admin: boolean) {
store.dispatch(USERS_STORE.ACTIONS.UPDATE_USER, {
username,
@@ -219,10 +196,7 @@
watch(
() => route.query,
(newQuery: LocationQuery) => {
- query.page = getPage(newQuery.page)
- query.per_page = getPerPage(newQuery.per_page)
- query.order = getOrder(newQuery.order)
- query.order_by = getOrderBy(newQuery.order_by)
+ query = getQuery(newQuery, orderByList, defaultOrderBy, { query })
loadUsers(query)
}
)
@@ -234,10 +208,10 @@
return {
authUser,
errorMessages,
+ orderByList,
pagination,
- order_by,
query,
- sort,
+ sortList,
users,
capitalize,
format,
diff --git a/fittrackee_client/src/types/api.ts b/fittrackee_client/src/types/api.ts
index 9d78c5e6..853377a8 100644
--- a/fittrackee_client/src/types/api.ts
+++ b/fittrackee_client/src/types/api.ts
@@ -13,3 +13,8 @@ export type TPaginationPayload = {
per_page: number
page: number
}
+
+export interface IQueryOptions {
+ defaultSort?: string
+ query?: TPaginationPayload
+}
diff --git a/fittrackee_client/src/utils/api.ts b/fittrackee_client/src/utils/api.ts
new file mode 100644
index 00000000..b72a6ba3
--- /dev/null
+++ b/fittrackee_client/src/utils/api.ts
@@ -0,0 +1,50 @@
+import { LocationQuery } from 'vue-router'
+
+import { IQueryOptions, TPaginationPayload } from '@/types/api'
+
+export const sortList: string[] = ['asc', 'desc']
+export const defaultPage = 1
+export const defaultPerPage = 10
+
+export const getNumberQueryValue = (
+ queryValue: string | (string | null)[] | null,
+ defaultValue: number
+): number => {
+ return queryValue && typeof queryValue === 'string' && +queryValue > 0
+ ? +queryValue
+ : defaultValue
+}
+
+export const getStringQueryValue = (
+ queryValue: string | (string | null)[] | null,
+ availableValues: string[],
+ defaultValue: string
+): string => {
+ return queryValue &&
+ typeof queryValue === 'string' &&
+ availableValues.includes(queryValue)
+ ? queryValue
+ : defaultValue
+}
+
+export const getQuery = (
+ locationQuery: LocationQuery,
+ orderByList: string[],
+ defaultOrderBy: string,
+ options?: IQueryOptions
+): TPaginationPayload => {
+ const queryOptions = options || {}
+ const defaultSort = queryOptions.defaultSort || 'asc'
+ const query = queryOptions.query || {}
+
+ query.page = getNumberQueryValue(locationQuery.page, defaultPage)
+ query.per_page = getNumberQueryValue(locationQuery.per_page, defaultPerPage)
+ query.order = getStringQueryValue(locationQuery.order, sortList, defaultSort)
+ query.order_by = getStringQueryValue(
+ locationQuery.order_by,
+ orderByList,
+ defaultOrderBy
+ )
+
+ return query
+}
diff --git a/fittrackee_client/tests/unit/utils/api.spec.ts b/fittrackee_client/tests/unit/utils/api.spec.ts
new file mode 100644
index 00000000..6ccc909b
--- /dev/null
+++ b/fittrackee_client/tests/unit/utils/api.spec.ts
@@ -0,0 +1,238 @@
+import { assert } from 'chai'
+
+import {
+ defaultPerPage,
+ defaultPage,
+ sortList,
+ getNumberQueryValue,
+ getStringQueryValue,
+ getQuery,
+} from '@/utils/api'
+
+const orderByList = ['admin', 'created_at', 'username', 'workouts_count']
+const defaultSort = 'desc'
+const defaultOrderBy = 'created_at'
+
+const generateLocationQuery = (
+ query: Record
+): Record => {
+ return query
+}
+
+describe('getNumberQueryValue', () => {
+ const testsParams = [
+ {
+ description: 'returns 2 if input value is 2',
+ inputValue: '2',
+ inputDefaultValue: 2,
+ expectedValue: 2,
+ },
+ {
+ description: 'returns default value if input value is null',
+ inputValue: null,
+ inputDefaultValue: 1,
+ expectedValue: 1,
+ },
+ {
+ description: 'returns default value if input value is negative value',
+ inputValue: '-1',
+ inputDefaultValue: 1,
+ expectedValue: 1,
+ },
+ {
+ description: 'returns default value if input value is not a number',
+ inputValue: 'a',
+ inputDefaultValue: 1,
+ expectedValue: 1,
+ },
+ ]
+
+ testsParams.map((testParams) => {
+ it(testParams.description, () => {
+ assert.equal(
+ getNumberQueryValue(
+ testParams.inputValue,
+ testParams.inputDefaultValue
+ ),
+ testParams.expectedValue
+ )
+ })
+ })
+})
+
+describe('getStringQueryValue', () => {
+ const testsParams = [
+ {
+ description: 'returns input value if input value is in list',
+ inputValue: 'asc',
+ inputDefaultValue: 'asc',
+ expectedValue: 'asc',
+ },
+ {
+ description: 'returns default value if input value is null',
+ inputValue: null,
+ inputDefaultValue: 'asc',
+ expectedValue: 'asc',
+ },
+ {
+ description: 'returns default value if input value is not in list',
+ inputValue: '1',
+ inputDefaultValue: 'asc',
+ expectedValue: 'asc',
+ },
+ ]
+
+ testsParams.map((testParams) => {
+ it(testParams.description, () => {
+ assert.equal(
+ getStringQueryValue(
+ testParams.inputValue,
+ sortList,
+ testParams.inputDefaultValue
+ ),
+ testParams.expectedValue
+ )
+ })
+ })
+})
+
+describe('getQuery', () => {
+ const testsParams = [
+ {
+ description: 'returns default query if location query is an empty object',
+ inputLocationQuery: {},
+ expectedQuery: {
+ page: defaultPage,
+ per_page: defaultPerPage,
+ order: defaultSort,
+ order_by: defaultOrderBy,
+ },
+ },
+ {
+ description: 'returns query with input page',
+ inputLocationQuery: generateLocationQuery({ page: '2' }),
+ expectedQuery: {
+ page: 2,
+ per_page: defaultPerPage,
+ order: defaultSort,
+ order_by: defaultOrderBy,
+ },
+ },
+ {
+ description: 'returns query with input per_page',
+ inputLocationQuery: generateLocationQuery({ per_page: '20' }),
+ expectedQuery: {
+ page: defaultPage,
+ per_page: 20,
+ order: defaultSort,
+ order_by: defaultOrderBy,
+ },
+ },
+ {
+ description: 'returns query with input order',
+ inputLocationQuery: generateLocationQuery({ order: 'asc' }),
+ expectedQuery: {
+ page: defaultPage,
+ per_page: defaultPerPage,
+ order: 'asc',
+ order_by: defaultOrderBy,
+ },
+ },
+ {
+ description: 'returns query with input order_by',
+ inputLocationQuery: generateLocationQuery({ order_by: 'username' }),
+ expectedQuery: {
+ page: defaultPage,
+ per_page: defaultPerPage,
+ order: defaultSort,
+ order_by: 'username',
+ },
+ },
+ {
+ description:
+ 'returns default query with input location query values are invalid',
+ inputLocationQuery: generateLocationQuery({
+ page: '0',
+ per_page: '0',
+ order: 'random',
+ order_by: 'name',
+ }),
+ expectedQuery: {
+ page: defaultPage,
+ per_page: defaultPerPage,
+ order: defaultSort,
+ order_by: defaultOrderBy,
+ },
+ },
+ ]
+
+ testsParams.map((testParams) => {
+ it(testParams.description, () => {
+ assert.deepEqual(
+ getQuery(testParams.inputLocationQuery, orderByList, defaultOrderBy, {
+ defaultSort,
+ }),
+ testParams.expectedQuery
+ )
+ })
+ })
+})
+
+describe('getQuery w/ default values', () => {
+ it('returns default query if location query is an empty object', () => {
+ assert.deepEqual(getQuery({}, orderByList, defaultOrderBy), {
+ page: 1,
+ per_page: 10,
+ order: 'asc',
+ order_by: defaultOrderBy,
+ })
+ })
+})
+
+describe('getQuery w/ default values and input pagination payload', () => {
+ const inputQuery = {
+ page: 2,
+ per_page: 20,
+ order: 'desc',
+ order_by: 'username',
+ }
+
+ it('returns query updated with default values', () => {
+ assert.deepEqual(
+ getQuery({}, orderByList, defaultOrderBy, { query: inputQuery }),
+ {
+ page: 1,
+ per_page: 10,
+ order: 'asc',
+ order_by: defaultOrderBy,
+ }
+ )
+ })
+
+ it('returns query updated with input values', () => {
+ assert.deepEqual(
+ getQuery({}, orderByList, defaultOrderBy, {
+ defaultSort: 'desc',
+ query: inputQuery,
+ }),
+ {
+ page: 1,
+ per_page: 10,
+ order: 'desc',
+ order_by: defaultOrderBy,
+ }
+ )
+ })
+
+ it('returns query updated', () => {
+ assert.deepEqual(
+ getQuery(
+ { page: '3', per_page: '10', order: 'asc', order_by: 'workouts_count' },
+ orderByList,
+ defaultOrderBy,
+ { query: inputQuery }
+ ),
+ { page: 3, per_page: 10, order: 'asc', order_by: 'workouts_count' }
+ )
+ })
+})