Merge branch 'dev' into oauth2

This commit is contained in:
Sam
2022-07-27 16:29:57 +02:00
136 changed files with 1963 additions and 1212 deletions

View File

@ -55,6 +55,11 @@
function getSum(total: any, value: any): number {
return getNumber(total) + getNumber(value)
}
function getUnit(displayedData: string) {
return ['total_ascent', 'total_descent'].includes(displayedData)
? 'm'
: 'km'
}
const chartData: ComputedRef<ChartData<'bar'>> = computed(() => ({
labels: props.labels,
// workaround to avoid dataset modification
@ -88,12 +93,13 @@
props.displayedData,
+value,
props.useImperialUnits,
false
false,
getUnit(props.displayedData)
)
},
},
afterFit: function (scale: LayoutItem) {
scale.width = props.fullStats ? 75 : 60
scale.width = props.fullStats ? 90 : 60
},
},
},
@ -143,7 +149,8 @@
props.displayedData,
total,
props.useImperialUnits,
false
false,
getUnit(props.displayedData)
)
: null
}
@ -172,7 +179,9 @@
label += formatTooltipValue(
props.displayedData,
context.parsed.y,
props.useImperialUnits
props.useImperialUnits,
true,
getUnit(props.displayedData)
)
}
return label
@ -190,7 +199,9 @@
formatTooltipValue(
props.displayedData,
sum,
props.useImperialUnits
props.useImperialUnits,
true,
getUnit(props.displayedData)
)
)
},

View File

@ -14,6 +14,7 @@
<CalendarWorkouts
:workouts="filterWorkouts(day, workouts)"
:sports="sports"
:displayHARecord="displayHARecord"
/>
<div class="calendar-cell-day">
{{ format(day, 'd') }}
@ -34,6 +35,7 @@
interface Props {
currentDay: Date
displayHARecord: boolean
endDate: Date
sports: ISport[]
startDate: Date
@ -45,6 +47,7 @@
const {
currentDay,
displayHARecord,
endDate,
sports,
startDate,

View File

@ -16,9 +16,11 @@
class="fa fa-trophy custom-fa-small"
aria-hidden="true"
:title="
workout.records.map(
(record) => ` ${$t(`workouts.RECORD_${record.record_type}`)}`
)
workout.records
.filter((record) =>
displayHARecord ? true : record.record_type !== 'HA'
)
.map((record) => ` ${$t(`workouts.RECORD_${record.record_type}`)}`)
"
/>
</sup>
@ -30,13 +32,14 @@
import { IWorkout } from '@/types/workouts'
interface Props {
displayHARecord: boolean
workout: IWorkout
sportLabel: string
sportColor: string | null
}
const props = defineProps<Props>()
const { workout, sportLabel, sportColor } = toRefs(props)
const { displayHARecord, workout, sportLabel, sportColor } = toRefs(props)
</script>
<style lang="scss">

View File

@ -8,6 +8,7 @@
<CalendarWorkout
v-for="(workout, index) in workouts.slice(0, displayedWorkoutCount)"
:key="index"
:displayHARecord="displayHARecord"
:workout="workout"
:sportLabel="getSportLabel(workout, sports)"
:sportColor="getSportColor(workout, sports)"
@ -46,12 +47,13 @@
import { getDonutDatasets } from '@/utils/workouts'
interface Props {
displayHARecord: boolean
workouts: IWorkout[]
sports: ISport[]
}
const props = defineProps<Props>()
const { workouts, sports } = toRefs(props)
const { displayHARecord, workouts, sports } = toRefs(props)
const chartDatasets = computed(() => getDonutDatasets(props.workouts))
const colors = computed(() => sportIdColors(props.sports))
const displayedWorkoutCount = 6

View File

@ -13,6 +13,7 @@
/>
<CalendarCells
:currentDay="day"
:displayHARecord="user.display_ascent"
:end-date="calendarDates.end"
:sports="sports"
:start-date="calendarDates.start"

View File

@ -42,7 +42,8 @@
props.user.records,
translateSports(props.sports, t),
props.user.timezone,
props.user.imperial_units
props.user.imperial_units,
props.user.display_ascent
)
)
</script>

View File

@ -8,7 +8,13 @@
<StatCard
icon="road"
:value="totalDistance"
:text="unitTo === 'mi' ? 'miles' : unitTo"
:text="distanceUnitTo === 'mi' ? 'miles' : distanceUnitTo"
/>
<StatCard
v-if="user.display_ascent"
icon="location-arrow"
:value="totalAscent"
:text="ascentUnitTo === 'ft' ? 'feet' : ascentUnitTo"
/>
<StatCard
icon="clock-o"
@ -16,6 +22,7 @@
:text="totalDuration.duration"
/>
<StatCard
v-if="!user.display_ascent"
icon="tags"
:value="user.nb_sports"
:text="$t('workouts.SPORT', user.nb_sports)"
@ -43,15 +50,23 @@
() => props.user.total_duration
)
const totalDuration = computed(() => get_duration(userTotalDuration))
const defaultUnitFrom: TUnit = 'km'
const unitTo: TUnit = user.value.imperial_units
? units[defaultUnitFrom].defaultTarget
: defaultUnitFrom
const distanceUnitFrom: TUnit = 'km'
const distanceUnitTo: TUnit = user.value.imperial_units
? units[distanceUnitFrom].defaultTarget
: distanceUnitFrom
const totalDistance: ComputedRef<number> = computed(() =>
user.value.imperial_units
? convertDistance(user.value.total_distance, defaultUnitFrom, unitTo, 2)
: parseFloat(user.value.total_distance.toFixed(2))
)
? convertDistance(user.value.total_distance, distanceUnitFrom, distanceUnitTo, 2)
: parseFloat(user.value.total_distance.toFixed(2)))
const ascentUnitFrom: TUnit = 'm'
const ascentUnitTo: TUnit = user.value.imperial_units
? units[ascentUnitFrom].defaultTarget
: ascentUnitFrom
const totalAscent: ComputedRef<number> = computed(() =>
user.value.imperial_units
? convertDistance(user.value.total_ascent, ascentUnitFrom, ascentUnitTo, 2)
: parseFloat(user.value.total_ascent.toFixed(2)))
function get_duration(total_duration: ComputedRef<string>) {
const duration = total_duration.value.match(/day/g)

View File

@ -15,6 +15,8 @@
)
}}
</dd>
<dt>{{ $t('user.PROFILE.ASCENT_DATA') }}:</dt>
<dd>{{ $t(`common.${display_ascent}`) }}</dd>
</dl>
<div class="profile-buttons">
<button @click="$router.push('/profile/edit/preferences')">
@ -28,11 +30,11 @@
<script setup lang="ts">
import { computed } from 'vue'
import { IUserProfile } from '@/types/user'
import { IAuthUserProfile } from '@/types/user'
import { languageLabels } from '@/utils/locales'
interface Props {
user: IUserProfile
user: IAuthUserProfile
}
const props = defineProps<Props>()
@ -45,4 +47,7 @@
const timezone = computed(() =>
props.user.timezone ? props.user.timezone : 'Europe/Paris'
)
const display_ascent = computed(() =>
props.user.display_ascent ? 'DISPLAYED' : 'HIDDEN'
)
</script>

View File

@ -23,34 +23,66 @@
@updateTimezone="updateTZ"
/>
</label>
<label class="form-items">
{{ $t('user.PROFILE.FIRST_DAY_OF_WEEK') }}
<select id="weekm" v-model="userForm.weekm" :disabled="loading">
<option
v-for="start in weekStart"
:value="start.value"
:key="start.value"
>
{{ $t(`user.PROFILE.${start.label}`) }}
</option>
</select>
</label>
<label class="form-items">
{{ $t('user.PROFILE.UNITS.LABEL') }}
<select
id="imperial_units"
v-model="userForm.imperial_units"
:disabled="loading"
>
<option
v-for="unit in imperialUnits"
:value="unit.value"
:key="unit.value"
>
{{ $t(`user.PROFILE.UNITS.${unit.label}`) }}
</option>
</select>
</label>
<div class="form-items form-checkboxes">
<span class="checkboxes-label">
{{ $t('user.PROFILE.FIRST_DAY_OF_WEEK') }}
</span>
<div class="checkboxes">
<label v-for="start in weekStart" :key="start.label">
<input
type="radio"
:id="start.label"
:name="start.label"
:checked="start.value === userForm.weekm"
:disabled="loading"
@input="updateWeekM(start.value)"
/>
<span class="checkbox-label">
{{ $t(`user.PROFILE.${start.label}`) }}
</span>
</label>
</div>
</div>
<div class="form-items form-checkboxes">
<span class="checkboxes-label">
{{ $t('user.PROFILE.UNITS.LABEL') }}
</span>
<div class="checkboxes">
<label v-for="unit in imperialUnits" :key="unit.label">
<input
type="radio"
:id="unit.label"
:name="unit.label"
:checked="unit.value === userForm.imperial_units"
:disabled="loading"
@input="updateImperialUnit(unit.value)"
/>
<span class="checkbox-label">
{{ $t(`user.PROFILE.UNITS.${unit.label}`) }}
</span>
</label>
</div>
</div>
<div class="form-items form-checkboxes">
<span class="checkboxes-label">
{{ $t('user.PROFILE.ASCENT_DATA') }}
</span>
<div class="checkboxes">
<label v-for="status in ascentData" :key="status.label">
<input
type="radio"
:id="status.label"
:name="status.label"
:checked="status.value === userForm.display_ascent"
:disabled="loading"
@input="updateAscentDisplay(status.value)"
/>
<span class="checkbox-label">
{{ $t(`common.${status.label}`) }}
</span>
</label>
</div>
</div>
<div class="form-buttons">
<button class="confirm" type="submit">
{{ $t('buttons.SUBMIT') }}
@ -72,40 +104,51 @@
import TimezoneDropdown from '@/components/User/ProfileEdition/TimezoneDropdown.vue'
import { AUTH_USER_STORE, ROOT_STORE } from '@/store/constants'
import { IUserProfile, IUserPreferencesPayload } from '@/types/user'
import { IUserPreferencesPayload, IAuthUserProfile } from '@/types/user'
import { useStore } from '@/use/useStore'
import { availableLanguages } from '@/utils/locales'
interface Props {
user: IUserProfile
user: IAuthUserProfile
}
const props = defineProps<Props>()
const store = useStore()
const userForm: IUserPreferencesPayload = reactive({
display_ascent: true,
imperial_units: false,
language: '',
timezone: 'Europe/Paris',
weekm: false,
})
const weekStart = [
{
label: 'MONDAY',
value: true,
},
{
label: 'SUNDAY',
value: false,
},
{
label: 'MONDAY',
value: true,
},
]
const imperialUnits = [
{
label: 'METRIC',
value: false,
},
{
label: 'IMPERIAL',
value: true,
},
]
const ascentData = [
{
label: 'METRIC',
label: 'DISPLAYED',
value: true,
},
{
label: 'HIDDEN',
value: false,
},
]
@ -122,7 +165,8 @@
}
})
function updateUserForm(user: IUserProfile) {
function updateUserForm(user: IAuthUserProfile) {
userForm.display_ascent = user.display_ascent
userForm.imperial_units = user.imperial_units ? user.imperial_units : false
userForm.language = user.language ? user.language : 'en'
userForm.timezone = user.timezone ? user.timezone : 'Europe/Paris'
@ -134,8 +178,43 @@
function updateTZ(value: string) {
userForm.timezone = value
}
function updateAscentDisplay(value: boolean) {
userForm.display_ascent = value
}
function updateImperialUnit(value: boolean) {
userForm.imperial_units = value
}
function updateWeekM(value: boolean) {
userForm.weekm = value
}
onUnmounted(() => {
store.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
})
</script>
<style lang="scss" scoped>
@import '~@/scss/vars.scss';
#user-preferences-edition {
.form-items {
padding-top: $default-padding * 0.5;
}
.form-checkboxes {
.checkboxes-label {
font-weight: bold;
}
.checkboxes {
display: flex;
gap: $default-padding;
flex-wrap: wrap;
.checkbox-label {
padding-left: $default-padding * 0.5;
}
label {
font-weight: normal;
}
}
}
}
</style>

View File

@ -32,11 +32,13 @@ export const htmlLegendPlugin = {
legendItems.forEach((item: LegendItem) => {
const li = document.createElement('li')
li.onclick = () => {
chart.setDatasetVisibility(
item.datasetIndex,
!chart.isDatasetVisible(item.datasetIndex)
)
chart.update()
if (item.datasetIndex) {
chart.setDatasetVisibility(
item.datasetIndex,
!chart.isDatasetVisible(item.datasetIndex)
)
chart.update()
}
}
const checkBox = document.createElement('input')

View File

@ -84,7 +84,13 @@
unitFrom="m"
:strong="true"
:useImperialUnits="useImperialUnits"
/><br />
/>
<WorkoutRecord
v-if="displayHARecord"
:workoutObject="workoutObject"
recordType="HA"
/>
<br />
<span class="label"> {{ $t('workouts.DESCENT') }} </span>:
<Distance
:distance="workoutObject.descent"
@ -110,10 +116,11 @@
interface Props {
workoutObject: IWorkoutObject
useImperialUnits: boolean
displayHARecord: boolean
}
const props = defineProps<Props>()
const { workoutObject, useImperialUnits } = toRefs(props)
const { displayHARecord, workoutObject, useImperialUnits } = toRefs(props)
const withPause = computed(
() =>
props.workoutObject.pauses !== '0:00:00' &&

View File

@ -23,6 +23,7 @@
<WorkoutData
:workoutObject="workoutObject"
:useImperialUnits="authUser.imperial_units"
:displayHARecord="authUser.display_ascent"
/>
</template>
</Card>