Client - add user sports preferences

+ minor refactor
This commit is contained in:
Sam
2021-11-12 18:52:08 +01:00
parent 7afdd04d7d
commit 7c49fd31ad
67 changed files with 500 additions and 101 deletions

View File

@ -35,6 +35,7 @@
<SportImage
:title="sport.translatedLabel"
:sport-label="sport.label"
:color="sport.color"
/>
</td>
<td class="sport-label">
@ -127,9 +128,6 @@
font-style: italic;
padding: 0 $default-padding;
}
.text-left {
text-align: left;
}
.sport-action {
padding-left: $default-padding * 4;
}

View File

@ -1,7 +1,7 @@
<template>
<div
class="sport-img"
:style="{ fill: sportColors[sportLabel] }"
:style="{ fill: color ? color : sportColors[sportLabel] }"
:title="title ? title : $t(`sports.${sportLabel}.LABEL`)"
>
<CyclingSport v-if="sportLabel === 'Cycling (Sport)'" />
@ -37,12 +37,13 @@
interface Props {
sportLabel: string
color: string | null
title?: string
}
const props = withDefaults(defineProps<Props>(), {
title: '',
})
const { sportLabel, title } = toRefs(props)
const { color, sportLabel, title } = toRefs(props)
const sportColors = inject('sportColors')
</script>

View File

@ -5,7 +5,11 @@
$router.push({ name: 'Workout', params: { workoutId: workout.id } })
"
>
<SportImage :sport-label="sportLabel" :title="workout.title" />
<SportImage
:sport-label="sportLabel"
:title="workout.title"
:color="sportColor"
/>
<sup>
<i
v-if="workout.records.length > 0"
@ -28,6 +32,7 @@
interface Props {
workout: IWorkout
sportLabel: string
sportColor: string | null
}
const props = defineProps<Props>()

View File

@ -10,6 +10,7 @@
:key="index"
:workout="workout"
:sportLabel="getSportLabel(workout, sports)"
:sportColor="getSportColor(workout, sports)"
/>
</div>
<div v-else class="donut-display">
@ -41,7 +42,7 @@
import CalendarWorkoutsChart from '@/components/Dashboard/UserCalendar/CalendarWorkoutsChart.vue'
import { ISport } from '@/types/sports'
import { IWorkout } from '@/types/workouts'
import { getSportLabel, sportIdColors } from '@/utils/sports'
import { getSportColor, getSportLabel, sportIdColors } from '@/utils/sports'
import { getDonutDatasets } from '@/utils/workouts'
interface Props {

View File

@ -2,7 +2,7 @@
<div class="records-card">
<Card>
<template #title>
<SportImage :sport-label="records.label" />
<SportImage :sport-label="records.label" :color="records.color" />
{{ sportTranslatedLabel }}
</template>
<template #content>

View File

@ -13,7 +13,7 @@
:checked="selectedSportIds.includes(sport.id)"
@input="updateSelectedSportIds(sport.id)"
/>
<SportImage :sport-label="sport.label" />
<SportImage :sport-label="sport.label" :color="sport.color" />
<span class="sport-label">{{ sport.translatedLabel }}</span>
</label>
</div>

View File

@ -91,9 +91,5 @@
.user-bio {
white-space: pre-wrap;
}
.profile-buttons {
display: flex;
gap: $default-padding;
}
}
</style>

View File

@ -38,13 +38,3 @@
props.user.timezone ? props.user.timezone : 'Europe/Paris'
)
</script>
<style lang="scss" scoped>
@import '~@/scss/base.scss';
#user-preferences {
.profile-buttons {
display: flex;
gap: $default-padding;
}
}
</style>

View File

@ -22,7 +22,7 @@
const props = defineProps<Props>()
const { user, tab } = toRefs(props)
const tabs = ['PROFILE', 'PREFERENCES']
const tabs = ['PROFILE', 'PREFERENCES', 'SPORTS']
</script>
<style lang="scss" scoped>

View File

@ -34,7 +34,7 @@
const store = useStore()
const { user, tab } = toRefs(props)
const tabs = ['PROFILE', 'PICTURE', 'PREFERENCES']
const tabs = ['PROFILE', 'PICTURE', 'PREFERENCES', 'SPORTS']
const loading = computed(
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
)

View File

@ -38,7 +38,10 @@
case 'PICTURE':
return '/profile/edit/picture'
case 'PREFERENCES':
return `/profile${props.edition ? '/edit' : ''}/preferences`
case 'SPORTS':
return `/profile${
props.edition ? '/edit' : ''
}/${tab.toLocaleLowerCase()}`
default:
case 'PROFILE':
return `/profile${props.edition ? '/edit' : ''}`

View File

@ -0,0 +1,280 @@
<template>
<div id="user-sport-preferences">
<div class="responsive-table" v-if="sports.length > 0">
<div class="mobile-display">
<div v-if="isEdition" class="profile-buttons mobile-display">
<button
class="cancel"
@click.prevent="$router.push('/profile/sports')"
>
{{ $t('buttons.BACK') }}
</button>
</div>
<div v-else class="profile-buttons">
<button @click="$router.push('/profile/edit/sports')">
{{ $t('user.PROFILE.EDIT_SPORTS_PREFERENCES') }}
</button>
<button @click="$router.push('/')">{{ $t('common.HOME') }}</button>
</div>
</div>
<table>
<thead>
<tr>
<th>{{ $t('user.PROFILE.SPORT.COLOR') }}</th>
<th class="text-left">{{ $t('workouts.SPORT', 0) }}</th>
<th>{{ $t('user.PROFILE.SPORT.IS_ACTIVE') }}</th>
<th>{{ $t('user.PROFILE.SPORT.STOPPED_SPEED_THRESHOLD') }}</th>
<th v-if="isEdition">{{ $t('user.PROFILE.SPORT.ACTION') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="sport in translatedSports" :key="sport.id">
<td>
<span class="cell-heading">
{{ $t('user.PROFILE.SPORT.COLOR') }}
</span>
<input
v-if="isSportInEdition(sport.id)"
class="sport-color"
type="color"
:value="sportPayload.color"
@input="updateColor"
/>
<SportImage
v-else
:title="sport.translatedLabel"
:sport-label="sport.label"
:color="sport.color ? sport.color : sportColors[sport.label]"
/>
</td>
<td class="sport-label">
<span class="cell-heading">
{{ $t('user.PROFILE.SPORT.LABEL') }}
</span>
{{ sport.translatedLabel }}
<i
v-if="loading && isSportInEdition(sport.id)"
class="fa fa-refresh fa-spin fa-fw"
/>
<ErrorMessage
:message="errorMessages"
v-if="errorMessages && sportPayload.sport_id === sport.id"
/>
</td>
<td class="text-center">
<span class="cell-heading">
{{ $t('user.PROFILE.SPORT.IS_ACTIVE') }}
</span>
<input
v-if="isSportInEdition(sport.id)"
type="checkbox"
:checked="sport.is_active_for_user"
@change="updateIsActive"
/>
<i
v-else
:class="`fa fa${
sport.is_active_for_user ? '-check' : ''
}-square-o`"
aria-hidden="true"
/>
</td>
<td class="text-center">
<span class="cell-heading">
{{ $t('user.PROFILE.SPORT.STOPPED_SPEED_THRESHOLD') }}
</span>
<input
class="threshold-input"
v-if="isSportInEdition(sport.id)"
type="number"
min="0"
step="0.1"
:value="sportPayload.stopped_speed_threshold"
@input="updateThreshold"
/>
<span v-else>
{{ sport.stopped_speed_threshold }}
</span>
</td>
<td v-if="isEdition" class="action-buttons">
<span class="cell-heading">
{{ $t('user.PROFILE.SPORT.ACTION') }}
</span>
<button
v-if="sportPayload.sport_id === 0"
@click="updateSportInEdition(sport)"
>
{{ $t('buttons.EDIT') }}
</button>
<div v-if="isSportInEdition(sport.id)" class="edition-buttons">
<button :disabled="loading" @click="updateSport">
{{ $t('buttons.SUBMIT') }}
</button>
<button :disabled="loading" @click="updateSportInEdition(null)">
{{ $t('buttons.CANCEL') }}
</button>
</div>
</td>
</tr>
</tbody>
</table>
<div v-if="isEdition" class="profile-buttons">
<button class="cancel" @click.prevent="$router.push('/profile/sports')">
{{ $t('buttons.BACK') }}
</button>
</div>
<div v-else class="profile-buttons">
<button @click="$router.push('/profile/edit/sports')">
{{ $t('user.PROFILE.EDIT_SPORTS_PREFERENCES') }}
</button>
<button @click="$router.push('/')">{{ $t('common.HOME') }}</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ComputedRef, computed, inject, reactive, toRefs, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { AUTH_USER_STORE, ROOT_STORE, SPORTS_STORE } from '@/store/constants'
import { ISport, ITranslatedSport } from '@/types/sports'
import { IUserSportPreferencesPayload } from '@/types/user'
import { useStore } from '@/use/useStore'
import { translateSports } from '@/utils/sports'
interface Props {
isEdition: boolean
}
const props = defineProps<Props>()
const store = useStore()
const { t } = useI18n()
const { isEdition } = toRefs(props)
const sportColors = inject('sportColors')
const sports: ComputedRef<ISport[]> = computed(
() => store.getters[SPORTS_STORE.GETTERS.SPORTS]
)
const translatedSports: ComputedRef<ITranslatedSport[]> = computed(() =>
translateSports(sports.value, t)
)
const loading = computed(
() => store.getters[AUTH_USER_STORE.GETTERS.USER_LOADING]
)
const errorMessages: ComputedRef<string | string[] | null> = computed(
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
)
const sportPayload: IUserSportPreferencesPayload = reactive({
sport_id: 0,
color: null,
is_active: true,
stopped_speed_threshold: 1,
})
function updateSportInEdition(sport: ISport | null) {
if (sport !== null) {
sportPayload.sport_id = sport.id
sportPayload.color = sport.color ? sport.color : sportColors[sport.label]
sportPayload.is_active = sport.is_active_for_user
sportPayload.stopped_speed_threshold = sport.stopped_speed_threshold
} else {
resetSportPayload()
}
}
function isSportInEdition(sportId: number) {
return sportPayload.sport_id === sportId
}
function updateColor(event: Event & { target: HTMLInputElement }) {
sportPayload.color = event.target.value
}
function updateThreshold(event: Event & { target: HTMLInputElement }) {
sportPayload.stopped_speed_threshold = parseFloat(event.target.value)
}
function updateIsActive(event: Event & { target: HTMLInputElement }) {
sportPayload.is_active = event.target.checked
}
function resetSportPayload() {
sportPayload.sport_id = 0
sportPayload.color = null
sportPayload.is_active = true
sportPayload.stopped_speed_threshold = 1
store.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
}
function updateSport(event: Event) {
event.preventDefault()
store.dispatch(
AUTH_USER_STORE.ACTIONS.UPDATE_USER_SPORT_PREFERENCES,
sportPayload
)
}
watch(
() => loading.value,
(newIsLoading) => {
if (!newIsLoading && !errorMessages.value) {
resetSportPayload()
}
}
)
</script>
<style lang="scss" scoped>
@import '~@/scss/base.scss';
#user-sport-preferences {
.sport-img {
height: 35px;
width: 35px;
margin: 0 auto;
}
.sport-color {
border: none;
margin: 6px 1px 6px 0;
padding: 0;
width: 40px;
}
.sport-label {
width: 170px;
}
.action-buttons {
width: 70px;
}
.edition-buttons {
display: flex;
flex-wrap: wrap;
gap: $default-padding * 0.5;
line-height: 1.3em;
button {
text-align: center;
min-width: 80px;
}
}
.threshold-input {
padding: $default-padding * 0.5;
width: 50px;
}
.mobile-display {
display: none;
}
div.error-message {
margin: 0;
}
@media screen and (max-width: $small-limit) {
.sport-label {
width: 100%;
}
.action-buttons {
width: 100%;
}
.edition-buttons {
justify-content: center;
}
.mobile-display {
display: flex;
margin: $default-margin * 2 0 $default-margin;
}
}
}
</style>

View File

@ -75,7 +75,11 @@
"
>
<div class="img">
<SportImage v-if="sport.label" :sport-label="sport.label" />
<SportImage
v-if="sport.label"
:sport-label="sport.label"
:color="sport.color"
/>
</div>
<div class="data">
<i class="fa fa-clock-o" aria-hidden="true" />

View File

@ -17,7 +17,7 @@
<i class="fa fa-chevron-left" aria-hidden="true" />
</div>
<div class="workout-card-title">
<SportImage :sport-label="sport.label" />
<SportImage :sport-label="sport.label" :color="sport.color" />
<div class="workout-title-date">
<div class="workout-title" v-if="workoutObject.type === 'WORKOUT'">
{{ workoutObject.title }}

View File

@ -46,7 +46,7 @@
v-model="workoutForm.sport_id"
>
<option
v-for="sport in translatedSports.filter((s) => s.is_active)"
v-for="sport in translatedSports"
:value="sport.id"
:key="sport.id"
>
@ -259,7 +259,7 @@
const { workout, isCreation, loading } = toRefs(props)
const translatedSports: ComputedRef<ISport[]> = computed(() =>
translateSports(props.sports, t)
translateSports(props.sports, t, true)
)
const appConfig: ComputedRef<TAppConfig> = computed(
() => store.getters[ROOT_STORE.GETTERS.APP_CONFIG]

View File

@ -52,6 +52,9 @@
:sport-label="
sports.filter((s) => s.id === workout.sport_id)[0].label
"
:color="
sports.filter((s) => s.id === workout.sport_id)[0].color
"
/>
</td>
<td

View File

@ -23,6 +23,7 @@
"BIRTH_DATE": "Birth date",
"EDIT": "Edit profile",
"EDIT_PREFERENCES": "Edit preferences",
"EDIT_SPORTS_PREFERENCES": "Edit sports preferences",
"FIRST_NAME": "First name",
"FIRST_DAY_OF_WEEK": "First day of week",
"LANGUAGE": "Language",
@ -36,11 +37,20 @@
"PREFERENCES_EDITION": "Preferences edition",
"PROFILE_EDITION": "Profile edition",
"REGISTRATION_DATE": "Registration date",
"SPORTS_EDITION": "Sports preferences edition",
"SUNDAY": "Sunday",
"TABS": {
"PICTURE": "picture",
"PREFERENCES": "preferences",
"PROFILE": "profile"
"PROFILE": "profile",
"SPORTS": "sports"
},
"SPORT": {
"ACTION": "action",
"COLOR": "color",
"IS_ACTIVE": "active",
"LABEL": "label",
"STOPPED_SPEED_THRESHOLD": "stopped speed threshold"
},
"TIMEZONE": "Timezone"
},

View File

@ -23,6 +23,7 @@
"BIRTH_DATE": "Date de naissance",
"EDIT": "Modifier le profil",
"EDIT_PREFERENCES": "Modifier les préférences",
"EDIT_SPORTS_PREFERENCES": "Modifier les préférences des sports",
"FIRST_DAY_OF_WEEK": "Premier jour de la semaine",
"FIRST_NAME": "Prénom",
"LANGUAGE": "Langue",
@ -36,11 +37,20 @@
"PREFERENCES_EDITION": "Mise à jour des préférences",
"PROFILE_EDITION": "Mise à jour du profil",
"REGISTRATION_DATE": "Date d'inscription",
"SPORTS_EDITION": "Mise à jour des préférences des sports",
"SUNDAY": "Dimanche",
"TABS": {
"PICTURE": "image",
"PREFERENCES": "préférences",
"PROFILE": "profil"
"PROFILE": "profil",
"SPORTS": "sports"
},
"SPORT": {
"ACTION": "action",
"COLOR": "couleur",
"IS_ACTIVE": "actif",
"LABEL": "label",
"STOPPED_SPEED_THRESHOLD": "seuil de vitesse arrêtée"
},
"TIMEZONE": "Fuseau horaire"
},
@ -49,4 +59,4 @@
"RESET_PASSWORD": "Réinitialiser votre mot de passe",
"USER_PICTURE": "photo de l'utilisateur",
"USERNAME": "Nom d'utilisateur"
}
}

View File

@ -11,6 +11,7 @@ import ProfileEdition from '@/components/User/ProfileEdition/index.vue'
import UserInfosEdition from '@/components/User/ProfileEdition/UserInfosEdition.vue'
import UserPictureEdition from '@/components/User/ProfileEdition/UserPictureEdition.vue'
import UserPreferencesEdition from '@/components/User/ProfileEdition/UserPreferencesEdition.vue'
import UserSportPreferences from '@/components/User/UserSportPreferences.vue'
import store from '@/store'
import { AUTH_USER_STORE } from '@/store/constants'
@ -101,6 +102,12 @@ const routes: Array<RouteRecordRaw> = [
name: 'UserPreferences',
component: UserPreferences,
},
{
path: 'sports',
name: 'UserSportPreferences',
component: UserSportPreferences,
props: { isEdition: false },
},
],
},
{
@ -126,6 +133,12 @@ const routes: Array<RouteRecordRaw> = [
name: 'UserPreferencesEdition',
component: UserPreferencesEdition,
},
{
path: 'sports',
name: 'UserSportPreferencesEdition',
component: UserSportPreferences,
props: { isEdition: true },
},
],
},
],

View File

@ -254,9 +254,12 @@ button {
}
}
.center-text {
.text-center {
text-align: center;
}
.text-left {
text-align: left;
}
.responsive-table {
margin-bottom: 15px;
@ -337,3 +340,14 @@ button {
}
}
}
.profile-buttons {
display: flex;
gap: $default-padding;
}
.medium-sport-img {
height: 35px;
width: 35px;
margin: 0 auto;
}

View File

@ -25,6 +25,7 @@ import {
IUserPayload,
IUserPicturePayload,
IUserPreferencesPayload,
IUserSportPreferencesPayload,
} from '@/types/user'
import { handleError } from '@/utils'
@ -172,6 +173,26 @@ export const actions: ActionTree<IAuthUserState, IRootState> &
context.commit(AUTH_USER_STORE.MUTATIONS.UPDATE_USER_LOADING, false)
)
},
[AUTH_USER_STORE.ACTIONS.UPDATE_USER_SPORT_PREFERENCES](
context: ActionContext<IAuthUserState, IRootState>,
payload: IUserSportPreferencesPayload
): void {
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
context.commit(AUTH_USER_STORE.MUTATIONS.UPDATE_USER_LOADING, true)
authApi
.post('auth/profile/edit/sports', payload)
.then((res) => {
if (res.data.status === 'success') {
context.dispatch(SPORTS_STORE.ACTIONS.GET_SPORTS)
} else {
handleError(context, null)
}
})
.catch((error) => {
handleError(context, error)
context.commit(AUTH_USER_STORE.MUTATIONS.UPDATE_USER_LOADING, false)
})
},
[AUTH_USER_STORE.ACTIONS.UPDATE_USER_PICTURE](
context: ActionContext<IAuthUserState, IRootState>,
payload: IUserPicturePayload

View File

@ -10,6 +10,7 @@ export enum AuthUserActions {
UPDATE_USER_PICTURE = 'UPDATE_USER_PICTURE',
UPDATE_USER_PROFILE = 'UPDATE_USER_PROFILE',
UPDATE_USER_PREFERENCES = 'UPDATE_USER_PREFERENCES',
UPDATE_USER_SPORT_PREFERENCES = 'UPDATE_USER_SPORT_PREFERENCES',
}
export enum AuthUserGetters {

View File

@ -16,6 +16,7 @@ import {
IUserPayload,
IUserPicturePayload,
IUserPreferencesPayload,
IUserSportPreferencesPayload,
} from '@/types/user'
export interface IAuthUserState {
@ -52,6 +53,11 @@ export interface IAuthUserActions {
payload: IUserPreferencesPayload
): void
[AUTH_USER_STORE.ACTIONS.UPDATE_USER_SPORT_PREFERENCES](
context: ActionContext<IAuthUserState, IRootState>,
payload: IUserSportPreferencesPayload
): void
[AUTH_USER_STORE.ACTIONS.UPDATE_USER_PICTURE](
context: ActionContext<IAuthUserState, IRootState>,
payload: IUserPicturePayload

View File

@ -1,7 +1,7 @@
import { ActionContext, ActionTree } from 'vuex'
import authApi from '@/api/authApi'
import { ROOT_STORE, SPORTS_STORE } from '@/store/constants'
import { AUTH_USER_STORE, ROOT_STORE, SPORTS_STORE } from '@/store/constants'
import { IRootState } from '@/store/modules/root/types'
import { ISportsActions, ISportsState } from '@/store/modules/sports/types'
import { ISportPayload } from '@/types/sports'
@ -20,6 +20,7 @@ export const actions: ActionTree<ISportsState, IRootState> & ISportsActions = {
SPORTS_STORE.MUTATIONS.SET_SPORTS,
res.data.data.sports
)
context.commit(AUTH_USER_STORE.MUTATIONS.UPDATE_USER_LOADING, false)
} else {
handleError(context, null)
}

View File

@ -1,9 +1,12 @@
export interface ISport {
color: string | null
has_workouts: boolean
id: number
img: string
is_active: boolean
is_active_for_user: boolean
label: string
stopped_speed_threshold: number
}
export interface ITranslatedSport extends ISport {

View File

@ -45,6 +45,13 @@ export interface IUserPreferencesPayload {
weekm: boolean
}
export interface IUserSportPreferencesPayload {
sport_id: number
color: string | null
is_active: boolean
stopped_speed_threshold: number
}
export interface IUserPicturePayload {
picture: File
}

View File

@ -27,8 +27,9 @@ export interface IRecord {
}
export interface IRecordsBySport {
[key: string]: string | Record<string, string | number>[]
[key: string]: string | Record<string, string | number>[] | null
label: string
color: string | null
records: Record<string, string | number>[]
}

View File

@ -44,6 +44,7 @@ export const getRecordsBySports = (
if (sportList[sport.translatedLabel] === void 0) {
sportList[sport.translatedLabel] = {
label: sport.label,
color: sport.color,
records: [],
}
}

View File

@ -38,7 +38,7 @@ export const translateSports = (
onlyActive = false
): ITranslatedSport[] =>
sports
.filter((sport) => (onlyActive ? sport.is_active : true))
.filter((sport) => (onlyActive ? sport.is_active_for_user : true))
.map((sport) => ({
...sport,
translatedLabel: t(`sports.${sport.label}.LABEL`),
@ -50,3 +50,12 @@ export const getSportLabel = (workout: IWorkout, sports: ISport[]): string => {
.filter((sport) => sport.id === workout.sport_id)
.map((sport) => sport.label)[0]
}
export const getSportColor = (
workout: IWorkout,
sports: ISport[]
): string | null => {
return sports
.filter((sport) => sport.id === workout.sport_id)
.map((sport) => sport.color)[0]
}

View File

@ -1,6 +1,7 @@
<template>
<div id="profile" class="container view" v-if="authUser.username">
<router-view :user="authUser"></router-view>
<div id="bottom" />
</div>
</template>

View File

@ -5,25 +5,34 @@ import { translateSports } from '@/utils/sports'
const { t } = createI18n.global
export const sports: ISport[] = [
{
color: null,
has_workouts: false,
id: 1,
img: '/img/sports/cycling-sport.png',
is_active: true,
is_active_for_user: true,
label: 'Cycling (Sport)',
stopped_speed_threshold: 1,
},
{
color: '#000000',
has_workouts: false,
id: 2,
img: '/img/sports/cycling-transport.png',
is_active: false,
is_active_for_user: false,
label: 'Cycling (Transport)',
stopped_speed_threshold: 1,
},
{
color: null,
has_workouts: true,
id: 3,
img: '/img/sports/hiking.png',
is_active: true,
is_active_for_user: false,
label: 'Hiking',
stopped_speed_threshold: 0.1,
},
]

View File

@ -157,6 +157,7 @@ describe('getRecordsBySports', () => {
},
expected: {
'Cycling (Sport)': {
color: null,
label: 'Cycling (Sport)',
records: [
{
@ -206,6 +207,7 @@ describe('getRecordsBySports', () => {
},
expected: {
'Cycling (Sport)': {
color: null,
label: 'Cycling (Sport)',
records: [
{
@ -225,6 +227,7 @@ describe('getRecordsBySports', () => {
],
},
'Cycling (Transport)': {
color: '#000000',
label: 'Cycling (Transport)',
records: [
{

View File

@ -18,27 +18,36 @@ describe('sortSports', () => {
},
expected: [
{
color: null,
has_workouts: false,
id: 1,
img: '/img/sports/cycling-sport.png',
is_active: true,
is_active_for_user: true,
label: 'Cycling (Sport)',
stopped_speed_threshold: 1,
translatedLabel: 'Cycling (Sport)',
},
{
color: '#000000',
has_workouts: false,
id: 2,
img: '/img/sports/cycling-transport.png',
is_active: false,
is_active_for_user: false,
label: 'Cycling (Transport)',
stopped_speed_threshold: 1,
translatedLabel: 'Cycling (Transport)',
},
{
color: null,
has_workouts: true,
id: 3,
img: '/img/sports/hiking.png',
is_active: true,
is_active_for_user: false,
label: 'Hiking',
stopped_speed_threshold: 0.1,
translatedLabel: 'Hiking',
},
],
@ -53,21 +62,16 @@ describe('sortSports', () => {
},
expected: [
{
color: null,
has_workouts: false,
id: 1,
img: '/img/sports/cycling-sport.png',
is_active: true,
is_active_for_user: true,
label: 'Cycling (Sport)',
stopped_speed_threshold: 1,
translatedLabel: 'Cycling (Sport)',
},
{
has_workouts: true,
id: 3,
img: '/img/sports/hiking.png',
is_active: true,
label: 'Hiking',
translatedLabel: 'Hiking',
},
],
},
{
@ -88,27 +92,36 @@ describe('sortSports', () => {
},
expected: [
{
color: null,
has_workouts: true,
id: 3,
img: '/img/sports/hiking.png',
is_active: true,
is_active_for_user: false,
label: 'Hiking',
stopped_speed_threshold: 0.1,
translatedLabel: 'Randonnée',
},
{
color: null,
has_workouts: false,
id: 1,
img: '/img/sports/cycling-sport.png',
is_active: true,
is_active_for_user: true,
label: 'Cycling (Sport)',
stopped_speed_threshold: 1,
translatedLabel: 'Vélo (Sport)',
},
{
color: '#000000',
has_workouts: false,
id: 2,
img: '/img/sports/cycling-transport.png',
is_active: false,
is_active_for_user: false,
label: 'Cycling (Transport)',
stopped_speed_threshold: 1,
translatedLabel: 'Vélo (Transport)',
},
],
@ -123,19 +136,14 @@ describe('sortSports', () => {
},
expected: [
{
has_workouts: true,
id: 3,
img: '/img/sports/hiking.png',
is_active: true,
label: 'Hiking',
translatedLabel: 'Randonnée',
},
{
color: null,
has_workouts: false,
id: 1,
img: '/img/sports/cycling-sport.png',
is_active: true,
is_active_for_user: true,
label: 'Cycling (Sport)',
stopped_speed_threshold: 1,
translatedLabel: 'Vélo (Sport)',
},
],