Client - get workouts ordered by distance, duration or average speed
This commit is contained in:
parent
05b22e6f72
commit
e8350abf55
@ -9,7 +9,7 @@
|
|||||||
@change="onSelectUpdate"
|
@change="onSelectUpdate"
|
||||||
>
|
>
|
||||||
<option v-for="order in order_by" :value="order" :key="order">
|
<option v-for="order in order_by" :value="order" :key="order">
|
||||||
{{ $t(`${message}.${order}`) }}
|
{{ $t(`${message}.${order.toUpperCase()}`) }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
@ -157,9 +157,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, ComputedRef, defineComponent, PropType } from 'vue'
|
import { computed, ComputedRef, defineComponent, PropType, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { LocationQuery, useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
import { ISport } from '@/types/sports'
|
import { ISport } from '@/types/sports'
|
||||||
import { IUserProfile } from '@/types/user'
|
import { IUserProfile } from '@/types/user'
|
||||||
@ -180,12 +180,13 @@
|
|||||||
emits: ['filter'],
|
emits: ['filter'],
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const translatedSports: ComputedRef<ISport[]> = computed(() =>
|
const translatedSports: ComputedRef<ISport[]> = computed(() =>
|
||||||
translateSports(props.sports, t)
|
translateSports(props.sports, t)
|
||||||
)
|
)
|
||||||
const params: Record<string, string> = {}
|
let params: LocationQuery = Object.assign({}, route.query)
|
||||||
|
|
||||||
function handleFilterChange(event: Event & { target: HTMLInputElement }) {
|
function handleFilterChange(event: Event & { target: HTMLInputElement }) {
|
||||||
if (event.target.value === '') {
|
if (event.target.value === '') {
|
||||||
@ -199,6 +200,13 @@
|
|||||||
router.push({ path: '/workouts', query: params })
|
router.push({ path: '/workouts', query: params })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.query,
|
||||||
|
(newQuery) => {
|
||||||
|
params = Object.assign({}, newQuery)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return { translatedSports, onFilter, handleFilterChange }
|
return { translatedSports, onFilter, handleFilterChange }
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="workouts-list">
|
<div class="workouts-list">
|
||||||
<div class="box" :class="{ 'empty-table': workouts.length === 0 }">
|
<div class="box" :class="{ 'empty-table': workouts.length === 0 }">
|
||||||
|
<FilterSelects
|
||||||
|
:sort="sortList"
|
||||||
|
:order_by="orderByList"
|
||||||
|
:query="query"
|
||||||
|
message="workouts"
|
||||||
|
@updateSelect="reloadWorkouts"
|
||||||
|
/>
|
||||||
<div class="workouts-table responsive-table">
|
<div class="workouts-table responsive-table">
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@ -103,26 +110,28 @@
|
|||||||
PropType,
|
PropType,
|
||||||
computed,
|
computed,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
ref,
|
|
||||||
watch,
|
watch,
|
||||||
capitalize,
|
capitalize,
|
||||||
onBeforeMount,
|
onBeforeMount,
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { LocationQuery, useRoute } from 'vue-router'
|
import { LocationQuery, useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
import FilterSelects from '@/components/Common/FilterSelects.vue'
|
||||||
import StaticMap from '@/components/Common/StaticMap.vue'
|
import StaticMap from '@/components/Common/StaticMap.vue'
|
||||||
import NoWorkouts from '@/components/Workouts/NoWorkouts.vue'
|
import NoWorkouts from '@/components/Workouts/NoWorkouts.vue'
|
||||||
import { WORKOUTS_STORE } from '@/store/constants'
|
import { WORKOUTS_STORE } from '@/store/constants'
|
||||||
import { ITranslatedSport } from '@/types/sports'
|
import { ITranslatedSport } from '@/types/sports'
|
||||||
import { IUserProfile } from '@/types/user'
|
import { IUserProfile } from '@/types/user'
|
||||||
import { IWorkout } from '@/types/workouts'
|
import { IWorkout, TWorkoutsPayload } from '@/types/workouts'
|
||||||
import { useStore } from '@/use/useStore'
|
import { useStore } from '@/use/useStore'
|
||||||
|
import { getQuery, sortList, workoutsPayloadKeys } from '@/utils/api'
|
||||||
import { getDateWithTZ } from '@/utils/dates'
|
import { getDateWithTZ } from '@/utils/dates'
|
||||||
import { defaultOrder } from '@/utils/workouts'
|
import { defaultOrder } from '@/utils/workouts'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'WorkoutsList',
|
name: 'WorkoutsList',
|
||||||
components: {
|
components: {
|
||||||
|
FilterSelects,
|
||||||
NoWorkouts,
|
NoWorkouts,
|
||||||
StaticMap,
|
StaticMap,
|
||||||
},
|
},
|
||||||
@ -138,39 +147,70 @@
|
|||||||
setup() {
|
setup() {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const orderByList: string[] = [
|
||||||
|
'ave_speed',
|
||||||
|
'distance',
|
||||||
|
'duration',
|
||||||
|
'workout_date',
|
||||||
|
]
|
||||||
const workouts: ComputedRef<IWorkout[]> = computed(
|
const workouts: ComputedRef<IWorkout[]> = computed(
|
||||||
() => store.getters[WORKOUTS_STORE.GETTERS.USER_WORKOUTS]
|
() => store.getters[WORKOUTS_STORE.GETTERS.USER_WORKOUTS]
|
||||||
)
|
)
|
||||||
const per_page = 10
|
let query: TWorkoutsPayload = getWorkoutsQuery(route.query)
|
||||||
const page = ref(1)
|
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
loadWorkouts(route.query)
|
loadWorkouts(query)
|
||||||
})
|
})
|
||||||
|
|
||||||
function loadWorkouts(newQuery: LocationQuery) {
|
function loadWorkouts(payload: TWorkoutsPayload) {
|
||||||
page.value = 1
|
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_USER_WORKOUTS, payload)
|
||||||
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_USER_WORKOUTS, {
|
}
|
||||||
page: page.value,
|
function reloadWorkouts(queryParam: string, queryValue: string) {
|
||||||
per_page,
|
const newQuery: LocationQuery = Object.assign({}, route.query)
|
||||||
...defaultOrder,
|
newQuery[queryParam] = queryValue
|
||||||
...newQuery,
|
if (queryParam === 'per_page') {
|
||||||
|
newQuery['page'] = '1'
|
||||||
|
}
|
||||||
|
query = getWorkoutsQuery(newQuery)
|
||||||
|
router.push({ path: '/workouts', query })
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWorkoutsQuery(newQuery: LocationQuery): TWorkoutsPayload {
|
||||||
|
query = getQuery(newQuery, orderByList, defaultOrder.order_by, {
|
||||||
|
defaultSort: defaultOrder.order,
|
||||||
|
query,
|
||||||
})
|
})
|
||||||
|
Object.keys(newQuery)
|
||||||
|
.filter((k) => workoutsPayloadKeys.includes(k))
|
||||||
|
.map((k) => {
|
||||||
|
if (typeof newQuery[k] === 'string') {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
query[k] = newQuery[k]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.query,
|
() => route.query,
|
||||||
async (newQuery) => {
|
async (newQuery) => {
|
||||||
loadWorkouts(newQuery)
|
query = getWorkoutsQuery(newQuery)
|
||||||
|
loadWorkouts(query)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
query,
|
||||||
|
orderByList,
|
||||||
|
sortList,
|
||||||
workouts,
|
workouts,
|
||||||
capitalize,
|
capitalize,
|
||||||
format,
|
format,
|
||||||
getDateWithTZ,
|
getDateWithTZ,
|
||||||
|
reloadWorkouts,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -36,10 +36,10 @@
|
|||||||
},
|
},
|
||||||
"SELECTS": {
|
"SELECTS": {
|
||||||
"ORDER_BY": {
|
"ORDER_BY": {
|
||||||
"admin": "admin status",
|
"ADMIN": "admin status",
|
||||||
"created_at": "registration date",
|
"CREATED_AT": "registration date",
|
||||||
"username": "username",
|
"USERNAME": "username",
|
||||||
"workouts_count": "workout count"
|
"WORKOUTS_COUNT": "workout count"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,10 +36,10 @@
|
|||||||
},
|
},
|
||||||
"SELECTS": {
|
"SELECTS": {
|
||||||
"ORDER_BY": {
|
"ORDER_BY": {
|
||||||
"admin": "status administrateur",
|
"ADMIN": "status administrateur",
|
||||||
"created_at": "date d'inscription",
|
"CREATED_AT": "date d'inscription",
|
||||||
"username": "nom d'utilisateur",
|
"USERNAME": "nom d'utilisateur",
|
||||||
"workouts_count": "nombre de séances"
|
"WORKOUTS_COUNT": "nombre de séances"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { TWorkoutsPayload } from '@/types/workouts'
|
||||||
|
|
||||||
export interface IPagination {
|
export interface IPagination {
|
||||||
has_next: boolean
|
has_next: boolean
|
||||||
has_prev: boolean
|
has_prev: boolean
|
||||||
|
@ -48,3 +48,17 @@ export const getQuery = (
|
|||||||
|
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const workoutsPayloadKeys = [
|
||||||
|
'from',
|
||||||
|
'to',
|
||||||
|
'ave_speed_from',
|
||||||
|
'ave_speed_to',
|
||||||
|
'max_speed_from',
|
||||||
|
'max_speed_to',
|
||||||
|
'distance_from',
|
||||||
|
'distance_to',
|
||||||
|
'duration_from',
|
||||||
|
'duration_to',
|
||||||
|
'sport_id',
|
||||||
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user