Client - fix type errors

This commit is contained in:
Sam 2023-11-11 20:16:18 +01:00
parent b6d6a91549
commit 473d0aca53
48 changed files with 228 additions and 118 deletions

View File

@ -28,6 +28,9 @@ jobs:
- name: Lint - name: Lint
working-directory: ${{env.working-directory}} working-directory: ${{env.working-directory}}
run: yarn lint run: yarn lint
- name: Type check
working-directory: ${{env.working-directory}}
run: yarn type-check
- name: Tests - name: Tests
working-directory: ${{env.working-directory}} working-directory: ${{env.working-directory}}
run: yarn test:unit run: yarn test:unit

View File

@ -37,8 +37,9 @@
import NoConfig from '@/components/NoConfig.vue' import NoConfig from '@/components/NoConfig.vue'
import { ROOT_STORE } from '@/store/constants' import { ROOT_STORE } from '@/store/constants'
import type { TAppConfig } from '@/types/application' import type { TAppConfig } from '@/types/application'
import type { TLanguage } from '@/types/locales'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { localeFromLanguage } from '@/utils/locales' import { isLanguageSupported } from '@/utils/locales'
const store = useStore() const store = useStore()
@ -82,10 +83,10 @@
}, 300) }, 300)
} }
function initLanguage() { function initLanguage() {
let language = 'en' let language: TLanguage = 'en'
try { try {
const navigatorLanguage = navigator.language.split('-')[0] const navigatorLanguage = navigator.language.split('-')[0]
if (navigatorLanguage in localeFromLanguage) { if (isLanguageSupported(navigatorLanguage)) {
language = navigatorLanguage language = navigatorLanguage
} }
} catch (e) { } catch (e) {

View File

@ -37,7 +37,7 @@
const { appStatistics } = toRefs(props) const { appStatistics } = toRefs(props)
const uploadDirSize = computed(() => const uploadDirSize = computed(() =>
getReadableFileSize(appStatistics.value.uploads_dir_size, false) getReadableFileSize(appStatistics.value.uploads_dir_size)
) )
</script> </script>

View File

@ -33,8 +33,8 @@
const text = ref('') const text = ref('')
function updateText(event: Event & { target: HTMLInputElement }) { function updateText(event: Event) {
emit('updateValue', event.target.value) emit('updateValue', (event.target as HTMLInputElement).value)
} }
watch( watch(

View File

@ -60,8 +60,12 @@
const { order_by, query, sort, message } = toRefs(props) const { order_by, query, sort, message } = toRefs(props)
const perPage = [10, 25, 50, 100] const perPage = [10, 25, 50, 100]
function onSelectUpdate(event: Event & { target: HTMLInputElement }) { function onSelectUpdate(event: Event) {
emit('updateSelect', event.target.id, event.target.value) emit(
'updateSelect',
(event.target as HTMLInputElement).id,
(event.target as HTMLInputElement).value
)
} }
</script> </script>

View File

@ -26,7 +26,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { inject, toRefs, withDefaults } from 'vue' import { inject, toRefs } from 'vue'
import CyclingSport from '@/components/Common/Images/SportImage/CyclingSport.vue' import CyclingSport from '@/components/Common/Images/SportImage/CyclingSport.vue'
import CyclingTransport from '@/components/Common/Images/SportImage/CyclingTransport.vue' import CyclingTransport from '@/components/Common/Images/SportImage/CyclingTransport.vue'
@ -55,5 +55,5 @@
}) })
const { color, sportLabel, title } = toRefs(props) const { color, sportLabel, title } = toRefs(props)
const sportColors = inject('sportColors') const sportColors = inject('sportColors') as Record<string, string>
</script> </script>

View File

@ -50,7 +50,7 @@
strongMessage?: string | null strongMessage?: string | null
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
strongMessage: () => null, strongMessage: () => '',
}) })
const emit = defineEmits(['cancelAction', 'confirmAction']) const emit = defineEmits(['cancelAction', 'confirmAction'])
@ -63,7 +63,7 @@
) )
let confirmButton: HTMLElement | null = null let confirmButton: HTMLElement | null = null
let cancelButton: HTMLElement | null = null let cancelButton: HTMLElement | null = null
let previousFocusedElement: Element | null = null let previousFocusedElement: HTMLInputElement | null = null
function focusTrap(e: KeyboardEvent) { function focusTrap(e: KeyboardEvent) {
if (e.key === 'Tab' || e.keyCode === 9) { if (e.key === 'Tab' || e.keyCode === 9) {
@ -77,7 +77,7 @@
} }
onMounted(() => { onMounted(() => {
previousFocusedElement = document.activeElement previousFocusedElement = document.activeElement as HTMLInputElement | null
cancelButton = document.getElementById('cancel-button') cancelButton = document.getElementById('cancel-button')
confirmButton = document.getElementById('confirm-button') confirmButton = document.getElementById('confirm-button')
if (cancelButton) { if (cancelButton) {

View File

@ -50,6 +50,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { toRefs } from 'vue' import { toRefs } from 'vue'
import type { LocationQuery } from 'vue-router'
import type { IPagination, TPaginationPayload } from '@/types/api' import type { IPagination, TPaginationPayload } from '@/types/api'
import type { IOauth2ClientsPayload } from '@/types/oauth' import type { IOauth2ClientsPayload } from '@/types/oauth'
@ -65,13 +66,10 @@
const { pagination, path, query } = toRefs(props) const { pagination, path, query } = toRefs(props)
function getQuery( function getQuery(page: number, cursor?: number): LocationQuery {
page: number,
cursor?: number
): TPaginationPayload | IOauth2ClientsPayload {
const newQuery = Object.assign({}, query.value) const newQuery = Object.assign({}, query.value)
newQuery.page = cursor ? page + cursor : page newQuery.page = cursor ? page + cursor : page
return newQuery return newQuery as LocationQuery
} }
</script> </script>

View File

@ -62,8 +62,8 @@
function togglePassword() { function togglePassword() {
showPassword.value = !showPassword.value showPassword.value = !showPassword.value
} }
function updatePassword(event: Event & { target: HTMLInputElement }) { function updatePassword(event: Event) {
emit('updatePassword', event.target.value) emit('updatePassword', (event.target as HTMLInputElement).value)
} }
function invalidPassword() { function invalidPassword() {
emit('passwordError') emit('passwordError')

View File

@ -163,12 +163,9 @@
params: apiParams, params: apiParams,
}) })
} }
function updateDisplayData( function updateDisplayData(event: Event) {
event: Event & { displayedData.value = (event.target as HTMLInputElement)
target: HTMLInputElement & { name: TStatisticsDatasetKeys } .name as TStatisticsDatasetKeys
}
) {
displayedData.value = event.target.name
} }
function getApiParams( function getApiParams(
chartParams: IStatisticsDateParams, chartParams: IStatisticsDateParams,

View File

@ -40,14 +40,14 @@
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 type { ISport } from '@/types/sports' import type { ISport } from '@/types/sports'
import type { IUserProfile } from '@/types/user' import type { IAuthUserProfile } from '@/types/user'
import type { IWorkout } from '@/types/workouts' import type { IWorkout } from '@/types/workouts'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { defaultOrder } from '@/utils/workouts' import { defaultOrder } from '@/utils/workouts'
interface Props { interface Props {
sports: ISport[] sports: ISport[]
user: IUserProfile user: IAuthUserProfile
} }
const props = defineProps<Props>() const props = defineProps<Props>()

View File

@ -16,7 +16,7 @@
} }
const props = defineProps<Props>() const props = defineProps<Props>()
const days = [] const days: Date[] = []
for (let i = 0; i < 7; i++) { for (let i = 0; i < 7; i++) {
days.push(addDays(props.startDate, i)) days.push(addDays(props.startDate, i))
} }

View File

@ -20,7 +20,9 @@
.filter((record) => .filter((record) =>
displayHARecord ? true : record.record_type !== 'HA' displayHARecord ? true : record.record_type !== 'HA'
) )
.map((record) => ` ${$t(`workouts.RECORD_${record.record_type}`)}`) .map(
(record) => ` ${$t(`workouts.RECORD_${record.record_type}`)}`
)[0]
" "
/> />
</sup> </sup>

View File

@ -20,6 +20,7 @@
:sports="sports" :sports="sports"
:datasets="chartDatasets" :datasets="chartDatasets"
:colors="colors" :colors="colors"
:displayHARecord="displayHARecord"
/> />
</div> </div>
</div> </div>
@ -30,6 +31,7 @@
:sports="sports" :sports="sports"
:datasets="chartDatasets" :datasets="chartDatasets"
:colors="colors" :colors="colors"
:displayHARecord="displayHARecord"
/> />
</div> </div>
</div> </div>

View File

@ -14,6 +14,7 @@
<CalendarWorkout <CalendarWorkout
v-for="(workout, index) in workouts" v-for="(workout, index) in workouts"
:key="index" :key="index"
:displayHARecord="displayHARecord"
:workout="workout" :workout="workout"
:sportLabel="getSportLabel(workout, sports)" :sportLabel="getSportLabel(workout, sports)"
:sportColor="getSportColor(workout, sports)" :sportColor="getSportColor(workout, sports)"
@ -37,13 +38,14 @@
datasets: Record<number, Record<string, number>> datasets: Record<number, Record<string, number>>
sports: ISport[] sports: ISport[]
workouts: IWorkout[] workouts: IWorkout[]
displayHARecord: boolean
} }
const props = defineProps<Props>() const props = defineProps<Props>()
const { colors, datasets, sports, workouts } = toRefs(props) const { colors, datasets, sports, workouts } = toRefs(props)
const isHidden = ref(true) const isHidden = ref(true)
function togglePane(event: Event & { target: HTMLElement }) { function togglePane(event: Event) {
event.stopPropagation() event.stopPropagation()
isHidden.value = !isHidden.value isHidden.value = !isHidden.value
} }

View File

@ -21,11 +21,11 @@
import StatChart from '@/components/Common/StatsChart/index.vue' import StatChart from '@/components/Common/StatsChart/index.vue'
import type { ISport } from '@/types/sports' import type { ISport } from '@/types/sports'
import type { IUserProfile } from '@/types/user' import type { IAuthUserProfile } from '@/types/user'
interface Props { interface Props {
sports: ISport[] sports: ISport[]
user: IUserProfile user: IAuthUserProfile
} }
const props = defineProps<Props>() const props = defineProps<Props>()

View File

@ -35,11 +35,11 @@
import { toRefs } from 'vue' import { toRefs } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import type { ICardRecord, IRecord, IRecordsBySports } from '@/types/workouts' import type { ICardRecord, IRecord, IRecordsBySport } from '@/types/workouts'
import { sortRecords } from '@/utils/records' import { sortRecords } from '@/utils/records'
interface Props { interface Props {
records: IRecordsBySports records: IRecordsBySport
sportTranslatedLabel: string sportTranslatedLabel: string
} }
const props = defineProps<Props>() const props = defineProps<Props>()

View File

@ -99,6 +99,7 @@
import UserPicture from '@/components/User/UserPicture.vue' import UserPicture from '@/components/User/UserPicture.vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants' import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import type { IDropdownOption } from '@/types/forms' import type { IDropdownOption } from '@/types/forms'
import type { TLanguage } from '@/types/locales'
import type { IAuthUserProfile } from '@/types/user' import type { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { availableLanguages } from '@/utils/locales' import { availableLanguages } from '@/utils/locales'
@ -130,7 +131,7 @@
function updateLanguage(option: IDropdownOption) { function updateLanguage(option: IDropdownOption) {
store.dispatch( store.dispatch(
ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE, ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE,
option.value.toString() option.value as TLanguage
) )
} }
function logout() { function logout() {

View File

@ -39,7 +39,7 @@
const { t } = useI18n() const { t } = useI18n()
const sportColors: Record<string, string> | undefined = inject('sportColors') const sportColors = inject('sportColors') as Record<string, string>
const { selectedSportIds } = toRefs(props) const { selectedSportIds } = toRefs(props)
const translatedSports: ComputedRef<ITranslatedSport[]> = computed(() => const translatedSports: ComputedRef<ITranslatedSport[]> = computed(() =>
translateSports(props.userSports, t) translateSports(props.userSports, t)

View File

@ -125,6 +125,7 @@
import { AUTH_USER_STORE, ROOT_STORE, USERS_STORE } from '@/store/constants' import { AUTH_USER_STORE, ROOT_STORE, USERS_STORE } from '@/store/constants'
import type { TAppConfig } from '@/types/application' import type { TAppConfig } from '@/types/application'
import type { TLanguage } from '@/types/locales'
import type { IAuthUserProfile, IUserProfile } from '@/types/user' import type { IAuthUserProfile, IUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { formatDate, getDateFormat } from '@/utils/dates' import { formatDate, getDateFormat } from '@/utils/dates'
@ -141,7 +142,7 @@
const store = useStore() const store = useStore()
const { user, fromAdmin } = toRefs(props) const { user, fromAdmin } = toRefs(props)
const language: ComputedRef<string> = computed( const language: ComputedRef<TLanguage> = computed(
() => store.getters[ROOT_STORE.GETTERS.LANGUAGE] () => store.getters[ROOT_STORE.GETTERS.LANGUAGE]
) )
const authUser: ComputedRef<IAuthUserProfile> = computed( const authUser: ComputedRef<IAuthUserProfile> = computed(

View File

@ -60,6 +60,7 @@
import type { ComputedRef } from 'vue' import type { ComputedRef } from 'vue'
import { ROOT_STORE } from '@/store/constants' import { ROOT_STORE } from '@/store/constants'
import type { TLanguage } from '@/types/locales'
import type { IAuthUserProfile } from '@/types/user' import type { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { getDateFormat } from '@/utils/dates' import { getDateFormat } from '@/utils/dates'
@ -72,7 +73,7 @@
const store = useStore() const store = useStore()
const appLanguage: ComputedRef<string> = computed( const appLanguage: ComputedRef<TLanguage> = computed(
() => store.getters[ROOT_STORE.GETTERS.LANGUAGE] () => store.getters[ROOT_STORE.GETTERS.LANGUAGE]
) )
const userLanguage = computed(() => const userLanguage = computed(() =>

View File

@ -60,16 +60,16 @@
isOpen.value = false isOpen.value = false
emit('updateTimezone', value) emit('updateTimezone', value)
} }
function onEnter(event: Event & { target: HTMLInputElement }) { function onEnter(event: Event) {
event.preventDefault() event.preventDefault()
if (tzList.value?.firstElementChild?.innerHTML) { if (tzList.value?.firstElementChild?.innerHTML) {
onUpdateTimezone(tzList.value?.firstElementChild?.innerHTML) onUpdateTimezone(tzList.value?.firstElementChild?.innerHTML)
} }
} }
function openDropdown(event: Event & { target: HTMLInputElement }) { function openDropdown(event: Event) {
event.preventDefault() event.preventDefault()
isOpen.value = true isOpen.value = true
timezone.value = event.target.value.trim() timezone.value = (event.target as HTMLInputElement).value.trim()
} }
watch( watch(

View File

@ -87,7 +87,7 @@
> >
<i class="fa fa-download" aria-hidden="true" /> <i class="fa fa-download" aria-hidden="true" />
{{ $t('user.EXPORT_REQUEST.DOWNLOAD_ARCHIVE') }} {{ $t('user.EXPORT_REQUEST.DOWNLOAD_ARCHIVE') }}
({{ getReadableFileSize(exportRequest.file_size) }}) ({{ getReadableFileSizeAsText(exportRequest.file_size) }})
</span> </span>
<span v-else> <span v-else>
{{ $t(`user.EXPORT_REQUEST.STATUS.${exportRequest.status}`) }} {{ $t(`user.EXPORT_REQUEST.STATUS.${exportRequest.status}`) }}
@ -126,7 +126,7 @@
} from '@/types/user' } from '@/types/user'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { formatDate } from '@/utils/dates' import { formatDate } from '@/utils/dates'
import { getReadableFileSize } from '@/utils/files' import { getReadableFileSizeAsText } from '@/utils/files'
interface Props { interface Props {
user: IAuthUserProfile user: IAuthUserProfile

View File

@ -41,7 +41,7 @@
import type { TAppConfig } from '@/types/application' import type { TAppConfig } from '@/types/application'
import type { IUserProfile } from '@/types/user' import type { IUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { getReadableFileSize } from '@/utils/files' import { getReadableFileSizeAsText } from '@/utils/files'
interface Props { interface Props {
user: IUserProfile user: IUserProfile
@ -58,16 +58,18 @@
() => store.getters[ROOT_STORE.GETTERS.APP_CONFIG] () => store.getters[ROOT_STORE.GETTERS.APP_CONFIG]
) )
const fileSizeLimit = appConfig.value.max_single_file_size const fileSizeLimit = appConfig.value.max_single_file_size
? getReadableFileSize(appConfig.value.max_single_file_size) ? getReadableFileSizeAsText(appConfig.value.max_single_file_size)
: '' : ''
const pictureFile: Ref<File | null> = ref(null) const pictureFile: Ref<File | null> = ref(null)
function deleteUserPicture() { function deleteUserPicture() {
store.dispatch(AUTH_USER_STORE.ACTIONS.DELETE_PICTURE) store.dispatch(AUTH_USER_STORE.ACTIONS.DELETE_PICTURE)
} }
function updatePictureFile(event: Event & { target: HTMLInputElement }) { function updatePictureFile(event: Event) {
if (event.target.files) { if ((event.target as HTMLInputElement).files !== null) {
pictureFile.value = event.target.files[0] pictureFile.value = (
(event.target as HTMLInputElement).files as FileList
)[0]
} }
} }
function updateUserPicture() { function updateUserPicture() {

View File

@ -185,10 +185,12 @@
const userForm: IUserPreferencesPayload = reactive({ const userForm: IUserPreferencesPayload = reactive({
display_ascent: true, display_ascent: true,
imperial_units: false, imperial_units: false,
language: '', language: 'en',
timezone: 'Europe/Paris', timezone: 'Europe/Paris',
date_format: 'dd/MM/yyyy', date_format: 'dd/MM/yyyy',
weekm: false, weekm: false,
start_elevation_at_zero: false,
use_raw_gpx_speed: false,
}) })
const weekStart = [ const weekStart = [
{ {

View File

@ -104,6 +104,7 @@
client_name: '', client_name: '',
client_uri: '', client_uri: '',
client_description: '', client_description: '',
description: '',
redirect_uri: '', redirect_uri: '',
}) })
const scopes: string[] = reactive([]) const scopes: string[] = reactive([])

View File

@ -122,8 +122,8 @@
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { OAUTH2_STORE, ROOT_STORE } from '@/store/constants' import { OAUTH2_STORE, ROOT_STORE } from '@/store/constants'
import { IOAuth2Client } from '@/types/oauth' import type { IOAuth2Client } from '@/types/oauth'
import { IAuthUserProfile } from '@/types/user' import type { IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { formatDate } from '@/utils/dates' import { formatDate } from '@/utils/dates'
@ -145,7 +145,7 @@
() => store.getters[OAUTH2_STORE.GETTERS.REVOCATION_SUCCESSFUL] () => store.getters[OAUTH2_STORE.GETTERS.REVOCATION_SUCCESSFUL]
) )
const displayModal: Ref<boolean> = ref(false) const displayModal: Ref<boolean> = ref(false)
const messageToDisplay: Ref<string | null> = ref(null) const messageToDisplay: Ref<string> = ref('')
const idCopied: Ref<boolean> = ref(false) const idCopied: Ref<boolean> = ref(false)
const secretCopied: Ref<boolean> = ref(false) const secretCopied: Ref<boolean> = ref(false)
const clipboardSupport: Ref<boolean> = ref(false) const clipboardSupport: Ref<boolean> = ref(false)
@ -176,7 +176,7 @@
function updateDisplayModal(value: boolean) { function updateDisplayModal(value: boolean) {
displayModal.value = value displayModal.value = value
if (!value) { if (!value) {
messageToDisplay.value = null messageToDisplay.value = ''
} }
} }
function confirmAction(clientId: number) { function confirmAction(clientId: number) {

View File

@ -186,7 +186,7 @@
const { isEdition, user } = toRefs(props) const { isEdition, user } = toRefs(props)
const defaultColor = '#838383' const defaultColor = '#838383'
const sportColors: Record<string, string> | undefined = inject('sportColors') const sportColors = inject('sportColors') as Record<string, string>
const sports: ComputedRef<ISport[]> = computed( const sports: ComputedRef<ISport[]> = computed(
() => store.getters[SPORTS_STORE.GETTERS.SPORTS] () => store.getters[SPORTS_STORE.GETTERS.SPORTS]
) )
@ -223,14 +223,16 @@
function isSportInEdition(sportId: number) { function isSportInEdition(sportId: number) {
return sportPayload.sport_id === sportId return sportPayload.sport_id === sportId
} }
function updateColor(event: Event & { target: HTMLInputElement }) { function updateColor(event: Event) {
sportPayload.color = event.target.value sportPayload.color = (event.target as HTMLInputElement).value
} }
function updateThreshold(event: Event & { target: HTMLInputElement }) { function updateThreshold(event: Event) {
sportPayload.stopped_speed_threshold = parseFloat(event.target.value) sportPayload.stopped_speed_threshold = parseFloat(
(event.target as HTMLInputElement).value
)
} }
function updateIsActive(event: Event & { target: HTMLInputElement }) { function updateIsActive(event: Event) {
sportPayload.is_active = event.target.checked sportPayload.is_active = (event.target as HTMLInputElement).checked
} }
function resetSportPayload() { function resetSportPayload() {
sportPayload.sport_id = 0 sportPayload.sport_id = 0

View File

@ -73,7 +73,7 @@
> >
<div class="img"> <div class="img">
<SportImage <SportImage
v-if="sport.label" v-if="sport?.label"
:sport-label="sport.label" :sport-label="sport.label"
:color="sport.color" :color="sport.color"
/> />
@ -147,16 +147,16 @@
import UserPicture from '@/components/User/UserPicture.vue' import UserPicture from '@/components/User/UserPicture.vue'
import { ROOT_STORE } from '@/store/constants' import { ROOT_STORE } from '@/store/constants'
import type { ISport } from '@/types/sports' import type { ISport } from '@/types/sports'
import type { IUserProfile } from '@/types/user' import type { IAuthUserProfile } from '@/types/user'
import type { IWorkout } from '@/types/workouts' import type { IWorkout } from '@/types/workouts'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { formatDate } from '@/utils/dates' import { formatDate } from '@/utils/dates'
interface Props { interface Props {
user: IUserProfile user: IAuthUserProfile
useImperialUnits: boolean useImperialUnits: boolean
workout?: IWorkout workout?: IWorkout
sport?: ISport sport?: ISport | null
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
workout: () => ({}) as IWorkout, workout: () => ({}) as IWorkout,

View File

@ -24,7 +24,7 @@
notes?: string | null notes?: string | null
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
notes: () => null, notes: () => '',
}) })
const { notes } = toRefs(props) const { notes } = toRefs(props)

View File

@ -11,6 +11,7 @@
<Card> <Card>
<template #title> <template #title>
<WorkoutCardTitle <WorkoutCardTitle
v-if="sport"
:sport="sport" :sport="sport"
:workoutObject="workoutObject" :workoutObject="workoutObject"
@displayModal="updateDisplayModal(true)" @displayModal="updateDisplayModal(true)"
@ -84,7 +85,7 @@
? props.sports.find( ? props.sports.find(
(sport) => sport.id === props.workoutData.workout.sport_id (sport) => sport.id === props.workoutData.workout.sport_id
) )
: {} : ({} as ISport)
) )
const workoutObject = computed(() => const workoutObject = computed(() =>
getWorkoutObject(workout.value, segment.value) getWorkoutObject(workout.value, segment.value)

View File

@ -281,12 +281,12 @@
import { ROOT_STORE, WORKOUTS_STORE } from '@/store/constants' import { ROOT_STORE, WORKOUTS_STORE } from '@/store/constants'
import type { TAppConfig } from '@/types/application' import type { TAppConfig } from '@/types/application'
import type { ISport } from '@/types/sports' import type { ISport, ITranslatedSport } from '@/types/sports'
import type { IAuthUserProfile } from '@/types/user' import type { IAuthUserProfile } from '@/types/user'
import type { IWorkout, IWorkoutForm } from '@/types/workouts' import type { IWorkout, IWorkoutForm } from '@/types/workouts'
import { useStore } from '@/use/useStore' import { useStore } from '@/use/useStore'
import { formatWorkoutDate, getDateWithTZ } from '@/utils/dates' import { formatWorkoutDate, getDateWithTZ } from '@/utils/dates'
import { getReadableFileSize } from '@/utils/files' import { getReadableFileSizeAsText } from '@/utils/files'
import { translateSports } from '@/utils/sports' import { translateSports } from '@/utils/sports'
import { convertDistance } from '@/utils/units' import { convertDistance } from '@/utils/units'
@ -308,7 +308,7 @@
const router = useRouter() const router = useRouter()
const { authUser, workout, isCreation, loading } = toRefs(props) const { authUser, workout, isCreation, loading } = toRefs(props)
const translatedSports: ComputedRef<ISport[]> = computed(() => const translatedSports: ComputedRef<ITranslatedSport[]> = computed(() =>
translateSports( translateSports(
props.sports, props.sports,
t, t,
@ -320,11 +320,11 @@
() => store.getters[ROOT_STORE.GETTERS.APP_CONFIG] () => store.getters[ROOT_STORE.GETTERS.APP_CONFIG]
) )
const fileSizeLimit = appConfig.value.max_single_file_size const fileSizeLimit = appConfig.value.max_single_file_size
? getReadableFileSize(appConfig.value.max_single_file_size) ? getReadableFileSizeAsText(appConfig.value.max_single_file_size)
: '' : ''
const gpx_limit_import = appConfig.value.gpx_limit_import const gpx_limit_import = appConfig.value.gpx_limit_import
const zipSizeLimit = appConfig.value.max_zip_file_size const zipSizeLimit = appConfig.value.max_zip_file_size
? getReadableFileSize(appConfig.value.max_zip_file_size) ? getReadableFileSizeAsText(appConfig.value.max_zip_file_size)
: '' : ''
const errorMessages: ComputedRef<string | string[] | null> = computed( const errorMessages: ComputedRef<string | string[] | null> = computed(
() => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES] () => store.getters[ROOT_STORE.GETTERS.ERROR_MESSAGES]
@ -369,9 +369,9 @@
withGpx.value = !withGpx.value withGpx.value = !withGpx.value
formErrors.value = false formErrors.value = false
} }
function updateFile(event: Event & { target: HTMLInputElement }) { function updateFile(event: Event) {
if (event.target.files) { if ((event.target as HTMLInputElement).files) {
gpxFile = event.target.files[0] gpxFile = ((event.target as HTMLInputElement).files as FileList)[0]
} }
} }
function formatWorkoutForm(workout: IWorkout) { function formatWorkoutForm(workout: IWorkout) {

View File

@ -192,7 +192,7 @@
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import type { LocationQuery } from 'vue-router' import type { LocationQuery } from 'vue-router'
import type { ISport } from '@/types/sports' import type { ISport, ITranslatedSport } from '@/types/sports'
import type { IAuthUserProfile } from '@/types/user' import type { IAuthUserProfile } from '@/types/user'
import { translateSports } from '@/utils/sports' import { translateSports } from '@/utils/sports'
import { units } from '@/utils/units' import { units } from '@/utils/units'
@ -214,7 +214,7 @@
const toUnit = authUser.value.imperial_units const toUnit = authUser.value.imperial_units
? units['km'].defaultTarget ? units['km'].defaultTarget
: 'km' : 'km'
const translatedSports: ComputedRef<ISport[]> = computed(() => const translatedSports: ComputedRef<ITranslatedSport[]> = computed(() =>
translateSports(props.sports, t) translateSports(props.sports, t)
) )
let params: LocationQuery = Object.assign({}, route.query) let params: LocationQuery = Object.assign({}, route.query)
@ -226,11 +226,13 @@
} }
}) })
function handleFilterChange(event: Event & { target: HTMLInputElement }) { function handleFilterChange(event: Event) {
if (event.target.value === '') { const name = (event.target as HTMLInputElement).name
delete params[event.target.name] const value = (event.target as HTMLInputElement).value
if (value === '') {
delete params[name]
} else { } else {
params[event.target.name] = event.target.value params[name] = value
} }
} }
function onFilter() { function onFilter() {

View File

@ -5,7 +5,7 @@
<span class="total-label"> <span class="total-label">
{{ $t('common.TOTAL').toLowerCase() }}: {{ $t('common.TOTAL').toLowerCase() }}:
</span> </span>
<span v-if="pagination.total !== null"> <span v-if="pagination.total">
{{ pagination.total }} {{ pagination.total }}
{{ $t('workouts.WORKOUT', pagination.total) }} {{ $t('workouts.WORKOUT', pagination.total) }}
</span> </span>
@ -47,7 +47,7 @@
<SportImage <SportImage
v-if="sports.length > 0" v-if="sports.length > 0"
:title=" :title="
sports.find((s) => s.id === workout.sport_id) sports.filter((s) => s.id === workout.sport_id)[0]
.translatedLabel .translatedLabel
" "
:sport-label="getSportLabel(workout, sports)" :sport-label="getSportLabel(workout, sports)"

View File

@ -6,6 +6,7 @@ import router from '@/router'
import { ROOT_STORE } from '@/store/constants' import { ROOT_STORE } from '@/store/constants'
import type { IRootActions, IRootState } from '@/store/modules/root/types' import type { IRootActions, IRootState } from '@/store/modules/root/types'
import type { TAppConfigForm } from '@/types/application' import type { TAppConfigForm } from '@/types/application'
import type { TLanguage } from '@/types/locales'
import { handleError } from '@/utils' import { handleError } from '@/utils'
const { locale } = createI18n.global const { locale } = createI18n.global
@ -91,7 +92,7 @@ export const actions: ActionTree<IRootState, IRootState> & IRootActions = {
}, },
[ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE]( [ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE](
context: ActionContext<IRootState, IRootState>, context: ActionContext<IRootState, IRootState>,
language: string language: TLanguage
): void { ): void {
document.querySelector('html')?.setAttribute('lang', language) document.querySelector('html')?.setAttribute('lang', language)
context.commit(ROOT_STORE.MUTATIONS.UPDATE_LANG, language) context.commit(ROOT_STORE.MUTATIONS.UPDATE_LANG, language)

View File

@ -3,6 +3,7 @@ import type { MutationTree } from 'vuex'
import { ROOT_STORE } from '@/store/constants' import { ROOT_STORE } from '@/store/constants'
import type { IRootState, TRootMutations } from '@/store/modules/root/types' import type { IRootState, TRootMutations } from '@/store/modules/root/types'
import type { TAppConfig, IAppStatistics } from '@/types/application' import type { TAppConfig, IAppStatistics } from '@/types/application'
import type { TLanguage } from '@/types/locales'
import { localeFromLanguage } from '@/utils/locales' import { localeFromLanguage } from '@/utils/locales'
export const mutations: MutationTree<IRootState> & TRootMutations = { export const mutations: MutationTree<IRootState> & TRootMutations = {
@ -40,7 +41,7 @@ export const mutations: MutationTree<IRootState> & TRootMutations = {
) { ) {
state.application.statistics = statistics state.application.statistics = statistics
}, },
[ROOT_STORE.MUTATIONS.UPDATE_LANG](state: IRootState, language: string) { [ROOT_STORE.MUTATIONS.UPDATE_LANG](state: IRootState, language: TLanguage) {
state.language = language state.language = language
state.locale = localeFromLanguage[language] state.locale = localeFromLanguage[language]
}, },

View File

@ -13,10 +13,11 @@ import type {
IAppStatistics, IAppStatistics,
TAppConfigForm, TAppConfigForm,
} from '@/types/application' } from '@/types/application'
import type { TLanguage } from '@/types/locales'
export interface IRootState { export interface IRootState {
root: boolean root: boolean
language: string language: TLanguage
locale: Locale locale: Locale
errorMessages: string | string[] | null errorMessages: string | string[] | null
application: IApplication application: IApplication
@ -39,7 +40,7 @@ export interface IRootActions {
): void ): void
[ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE]( [ROOT_STORE.ACTIONS.UPDATE_APPLICATION_LANGUAGE](
context: ActionContext<IRootState, IRootState>, context: ActionContext<IRootState, IRootState>,
langauge: string language: TLanguage
): void ): void
} }
@ -54,7 +55,7 @@ export interface IRootGetters {
state: IRootState state: IRootState
): string | string[] | null ): string | string[] | null
[ROOT_STORE.GETTERS.LANGUAGE](state: IRootState): string [ROOT_STORE.GETTERS.LANGUAGE](state: IRootState): TLanguage
[ROOT_STORE.GETTERS.LOCALE](state: IRootState): Locale [ROOT_STORE.GETTERS.LOCALE](state: IRootState): Locale
} }
@ -81,7 +82,7 @@ export type TRootMutations<S = IRootState> = {
state: S, state: S,
statistics: IAppStatistics statistics: IAppStatistics
): void ): void
[ROOT_STORE.MUTATIONS.UPDATE_LANG](state: S, language: string): void [ROOT_STORE.MUTATIONS.UPDATE_LANG](state: S, language: TLanguage): void
} }
export type TRootStoreModule<S = IRootState> = Omit< export type TRootStoreModule<S = IRootState> = Omit<

View File

@ -37,3 +37,8 @@ export type TAppConfigForm = {
max_zip_file_size: number max_zip_file_size: number
privacy_policy: string privacy_policy: string
} }
export interface IFileSize {
size: string
suffix: string
}

View File

@ -0,0 +1,10 @@
export type TLanguage =
| 'en'
| 'de'
| 'es'
| 'fr'
| 'gl'
| 'it'
| 'nb'
| 'nl'
| 'pl'

View File

@ -1,5 +1,6 @@
import type { LocationQueryValue } from 'vue-router' import type { LocationQueryValue } from 'vue-router'
import type { TLanguage } from '@/types/locales'
import type { IRecord } from '@/types/workouts' import type { IRecord } from '@/types/workouts'
export interface IUserProfile { export interface IUserProfile {
@ -30,7 +31,7 @@ export interface IAuthUserProfile extends IUserProfile {
imperial_units: boolean imperial_units: boolean
start_elevation_at_zero: boolean start_elevation_at_zero: boolean
use_raw_gpx_speed: boolean use_raw_gpx_speed: boolean
language: string | null language: TLanguage | null
timezone: string timezone: string
date_format: string date_format: string
weekm: boolean weekm: boolean
@ -68,7 +69,7 @@ export interface IUserPreferencesPayload {
start_elevation_at_zero: boolean start_elevation_at_zero: boolean
use_raw_gpx_speed: boolean use_raw_gpx_speed: boolean
imperial_units: boolean imperial_units: boolean
language: string language: TLanguage
timezone: string timezone: string
date_format: string date_format: string
weekm: boolean weekm: boolean

View File

@ -34,10 +34,10 @@ export interface IRecord {
} }
export interface IRecordsBySport { export interface IRecordsBySport {
[key: string]: string | Record<string, string | number>[] | null [key: string]: string | IRecord[] | null
label: string label: string
color: string | null color: string | null
records: Record<string, string | number>[] records: IRecord[]
} }
export interface IRecordsBySports { export interface IRecordsBySports {
@ -59,8 +59,8 @@ export interface IWorkout {
bounds: number[] bounds: number[]
creation_date: string creation_date: string
descent: number | null descent: number | null
distance: number | null distance: number
duration: string | null duration: string
id: string id: string
map: string | null map: string | null
max_alt: number | null max_alt: number | null

View File

@ -12,6 +12,7 @@ import {
import { utcToZonedTime } from 'date-fns-tz' import { utcToZonedTime } from 'date-fns-tz'
import createI18n from '@/i18n' import createI18n from '@/i18n'
import type { TLanguage } from '@/types/locales'
import { localeFromLanguage } from '@/utils/locales' import { localeFromLanguage } from '@/utils/locales'
const { locale } = createI18n.global const { locale } = createI18n.global
@ -114,7 +115,7 @@ export const formatDate = (
timezone: string, timezone: string,
dateFormat: string, dateFormat: string,
withTime = true, withTime = true,
language: string | null = null, language: TLanguage | null = null,
withSeconds = false withSeconds = false
): string => { ): string => {
if (!language) { if (!language) {
@ -131,9 +132,9 @@ export const formatDate = (
export const availableDateFormatOptions = ( export const availableDateFormatOptions = (
inputDate: string, inputDate: string,
timezone: string, timezone: string,
language: string | null = null language: TLanguage | null = null
) => { ) => {
const l: string = language ? language : locale.value const l: TLanguage = language ? language : locale.value
const options: Record<string, string>[] = [] const options: Record<string, string>[] = []
availableDateFormats.map((df) => { availableDateFormats.map((df) => {
const dateFormat = getDateFormat(df, l) const dateFormat = getDateFormat(df, l)

View File

@ -1,16 +1,23 @@
import type { IFileSize } from '@/types/application'
const suffixes = ['bytes', 'KB', 'MB', 'GB', 'TB'] const suffixes = ['bytes', 'KB', 'MB', 'GB', 'TB']
export const getReadableFileSize = ( export const getReadableFileSize = (fileSize: number): IFileSize => {
fileSize: number,
asText = true
): string | Record<string, string> => {
const i = Math.floor(Math.log(fileSize) / Math.log(1024))
if (!fileSize) { if (!fileSize) {
return asText ? '0 bytes' : { size: '0', suffix: 'bytes' } return { size: '0', suffix: 'bytes' }
} }
const i = Math.floor(Math.log(fileSize) / Math.log(1024))
const size = (fileSize / Math.pow(1024, i)).toFixed(1) const size = (fileSize / Math.pow(1024, i)).toFixed(1)
const suffix = suffixes[i] const suffix = suffixes[i]
return asText ? `${size}${suffix}` : { size, suffix } return { size, suffix }
}
export const getReadableFileSizeAsText = (fileSize: number): string => {
if (!fileSize) {
return '0 bytes'
}
const readableFileSize = getReadableFileSize(fileSize)
return `${readableFileSize.size}${readableFileSize.suffix}`
} }
export const getFileSizeInMB = (fileSize: number): number => { export const getFileSizeInMB = (fileSize: number): number => {

View File

@ -2,20 +2,37 @@ import type { Locale } from 'date-fns'
import { de, enUS, es, fr, gl, it, nb, nl, pl } from 'date-fns/locale' import { de, enUS, es, fr, gl, it, nb, nl, pl } from 'date-fns/locale'
import createI18n from '@/i18n' import createI18n from '@/i18n'
import type { TLanguage } from '@/types/locales'
export const localeFromLanguage: Record<string, Locale> = { export const isLanguageSupported = (
language: string
): language is TLanguage => {
return (
language === 'de' ||
language === 'en' ||
language === 'es' ||
language === 'fr' ||
language === 'gl' ||
language === 'it' ||
language === 'nb' ||
language === 'nl' ||
language === 'pl'
)
}
export const localeFromLanguage: Record<TLanguage, Locale> = {
de: de, de: de,
en: enUS, en: enUS,
es: es, es: es,
fr: fr, fr: fr,
gl: gl, gl: gl,
it: it, it: it,
pl: pl,
nb: nb, nb: nb,
nl: nl, nl: nl,
pl: pl,
} }
export const languageLabels: Record<string, string> = { export const languageLabels: Record<TLanguage, string> = {
de: 'Deutsch', de: 'Deutsch',
en: 'English', en: 'English',
es: 'Español', es: 'Español',

View File

@ -12,7 +12,7 @@ export const formatRecord = (
tz: string, tz: string,
useImperialUnits: boolean, useImperialUnits: boolean,
date_format: string date_format: string
): Record<string, string | number> => { ): IRecord => {
const distanceUnitFrom: TUnit = 'km' const distanceUnitFrom: TUnit = 'km'
const distanceUnitTo: TUnit = useImperialUnits const distanceUnitTo: TUnit = useImperialUnits
? units[distanceUnitFrom].defaultTarget ? units[distanceUnitFrom].defaultTarget
@ -57,11 +57,13 @@ export const formatRecord = (
) )
} }
return { return {
workout_date: formatDate(record.workout_date, tz, date_format, false),
workout_id: record.workout_id,
id: record.id, id: record.id,
record_type: record.record_type, record_type: record.record_type,
sport_id: record.sport_id,
value: value, value: value,
user: record.user,
workout_date: formatDate(record.workout_date, tz, date_format, false),
workout_id: record.workout_id,
} }
} }

View File

@ -27,7 +27,7 @@
const router = useRouter() const router = useRouter()
const { action } = toRefs(props) const { action } = toRefs(props)
const token = computed(() => route.query.token) const token = computed(() => route.query.token as string)
onBeforeMount(() => { onBeforeMount(() => {
if (props.action === 'reset' && !token.value) { if (props.action === 'reset' && !token.value) {

View File

@ -1,8 +1,12 @@
import { describe, it, expect } from 'vitest' import { describe, it, expect } from 'vitest'
import { getFileSizeInMB, getReadableFileSize } from '@/utils/files' import {
getFileSizeInMB,
getReadableFileSize,
getReadableFileSizeAsText,
} from '@/utils/files'
describe('getReadableFileSize (as text)', () => { describe('getReadableFileSizeAsText', () => {
const testsParams = [ const testsParams = [
{ {
description: 'returns 0 bytes if provided file size is 0', description: 'returns 0 bytes if provided file size is 0',
@ -23,7 +27,7 @@ describe('getReadableFileSize (as text)', () => {
testsParams.map((testParams) => { testsParams.map((testParams) => {
it(testParams.description, () => { it(testParams.description, () => {
expect(getReadableFileSize(testParams.inputFileSize, true)).toStrictEqual( expect(getReadableFileSizeAsText(testParams.inputFileSize)).toStrictEqual(
testParams.expectedReadableFileSize testParams.expectedReadableFileSize
) )
}) })
@ -51,9 +55,9 @@ describe('getReadableFileSize (as object)', () => {
testsParams.map((testParams) => { testsParams.map((testParams) => {
it(testParams.description, () => { it(testParams.description, () => {
expect( expect(getReadableFileSize(testParams.inputFileSize)).toStrictEqual(
getReadableFileSize(testParams.inputFileSize, false) testParams.expectedReadableFileSize
).toStrictEqual(testParams.expectedReadableFileSize) )
}) })
}) })
}) })

View File

@ -24,6 +24,8 @@ describe('formatRecord', () => {
expected: { expected: {
id: 9, id: 9,
record_type: 'AS', record_type: 'AS',
sport_id: 1,
user: 'admin',
value: '18 km/h', value: '18 km/h',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -47,6 +49,8 @@ describe('formatRecord', () => {
expected: { expected: {
id: 10, id: 10,
record_type: 'FD', record_type: 'FD',
sport_id: 1,
user: 'admin',
value: '18 km', value: '18 km',
workout_date: '2019/07/08', workout_date: '2019/07/08',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -70,6 +74,8 @@ describe('formatRecord', () => {
expected: { expected: {
id: 11, id: 11,
record_type: 'LD', record_type: 'LD',
sport_id: 1,
user: 'admin',
value: '1:01:00', value: '1:01:00',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -93,6 +99,8 @@ describe('formatRecord', () => {
expected: { expected: {
id: 12, id: 12,
record_type: 'MS', record_type: 'MS',
sport_id: 1,
user: 'admin',
value: '18 km/h', value: '18 km/h',
workout_date: '08/07/2019', workout_date: '08/07/2019',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -116,6 +124,8 @@ describe('formatRecord', () => {
expected: { expected: {
id: 13, id: 13,
record_type: 'HA', record_type: 'HA',
sport_id: 1,
user: 'admin',
value: '100 m', value: '100 m',
workout_date: 'Jul. 7th, 2019', workout_date: 'Jul. 7th, 2019',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -156,6 +166,8 @@ describe('formatRecord after conversion', () => {
expected: { expected: {
id: 9, id: 9,
record_type: 'AS', record_type: 'AS',
sport_id: 1,
user: 'admin',
value: '11.18 mi/h', value: '11.18 mi/h',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -179,6 +191,8 @@ describe('formatRecord after conversion', () => {
expected: { expected: {
id: 10, id: 10,
record_type: 'FD', record_type: 'FD',
sport_id: 1,
user: 'admin',
value: '11.185 mi', value: '11.185 mi',
workout_date: '2019/08/07', workout_date: '2019/08/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -202,6 +216,8 @@ describe('formatRecord after conversion', () => {
expected: { expected: {
id: 11, id: 11,
record_type: 'LD', record_type: 'LD',
sport_id: 1,
user: 'admin',
value: '1:01:00', value: '1:01:00',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -225,6 +241,8 @@ describe('formatRecord after conversion', () => {
expected: { expected: {
id: 12, id: 12,
record_type: 'MS', record_type: 'MS',
sport_id: 1,
user: 'admin',
value: '11.18 mi/h', value: '11.18 mi/h',
workout_date: '2019/08/07', workout_date: '2019/08/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -248,6 +266,8 @@ describe('formatRecord after conversion', () => {
expected: { expected: {
id: 13, id: 13,
record_type: 'HA', record_type: 'HA',
sport_id: 1,
user: 'admin',
value: '328.08 ft', value: '328.08 ft',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -327,6 +347,8 @@ describe('getRecordsBySports', () => {
{ {
id: 9, id: 9,
record_type: 'AS', record_type: 'AS',
sport_id: 1,
user: 'admin',
value: '18 km/h', value: '18 km/h',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -378,6 +400,8 @@ describe('getRecordsBySports', () => {
{ {
id: 9, id: 9,
record_type: 'AS', record_type: 'AS',
sport_id: 1,
user: 'admin',
value: '18 km/h', value: '18 km/h',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -385,6 +409,8 @@ describe('getRecordsBySports', () => {
{ {
id: 12, id: 12,
record_type: 'MS', record_type: 'MS',
sport_id: 1,
user: 'admin',
value: '18 km/h', value: '18 km/h',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -398,6 +424,8 @@ describe('getRecordsBySports', () => {
{ {
id: 10, id: 10,
record_type: 'FD', record_type: 'FD',
sport_id: 2,
user: 'admin',
value: '18 km', value: '18 km',
workout_date: '2019/08/07', workout_date: '2019/08/07',
workout_id: 'n6JcLPQt3QtZWFfiSnYm4C', workout_id: 'n6JcLPQt3QtZWFfiSnYm4C',
@ -459,6 +487,8 @@ describe('getRecordsBySports after conversion', () => {
{ {
id: 9, id: 9,
record_type: 'AS', record_type: 'AS',
sport_id: 1,
user: 'admin',
value: '11.18 mi/h', value: '11.18 mi/h',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -510,6 +540,8 @@ describe('getRecordsBySports after conversion', () => {
{ {
id: 9, id: 9,
record_type: 'AS', record_type: 'AS',
sport_id: 1,
user: 'admin',
value: '11.18 mi/h', value: '11.18 mi/h',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -517,6 +549,8 @@ describe('getRecordsBySports after conversion', () => {
{ {
id: 12, id: 12,
record_type: 'MS', record_type: 'MS',
sport_id: 1,
user: 'admin',
value: '11.18 mi/h', value: '11.18 mi/h',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',
@ -530,6 +564,8 @@ describe('getRecordsBySports after conversion', () => {
{ {
id: 10, id: 10,
record_type: 'FD', record_type: 'FD',
sport_id: 2,
user: 'admin',
value: '11.185 mi', value: '11.185 mi',
workout_date: '2019/08/07', workout_date: '2019/08/07',
workout_id: 'n6JcLPQt3QtZWFfiSnYm4C', workout_id: 'n6JcLPQt3QtZWFfiSnYm4C',
@ -600,6 +636,8 @@ describe('getRecordsBySports with HA record', () => {
{ {
id: 9, id: 9,
record_type: 'AS', record_type: 'AS',
sport_id: 1,
user: 'admin',
value: '18 km/h', value: '18 km/h',
workout_date: '2019/07/07', workout_date: '2019/07/07',
workout_id: 'hvYBqYBRa7wwXpaStWR4V2', workout_id: 'hvYBqYBRa7wwXpaStWR4V2',