Client - display segment

This commit is contained in:
Sam 2021-09-27 10:01:17 +02:00
parent de32c136b6
commit b7b2eb0daf
12 changed files with 413 additions and 110 deletions

View File

@ -2,44 +2,48 @@
<div id="workout-info">
<div class="workout-data">
<i class="fa fa-clock-o" aria-hidden="true" />
{{ t('workouts.DURATION') }}: <span>{{ workout.moving }}</span>
<WorkoutRecord :workout="workout" record_type="LD" />
{{ t('workouts.DURATION') }}: <span>{{ workoutObject.moving }}</span>
<WorkoutRecord :workoutObject="workoutObject" record_type="LD" />
<div v-if="withPause">
({{ t('workouts.PAUSES') }}: <span>{{ workout.pauses }}</span> -
{{ t('workouts.TOTAL_DURATION') }}: <span>{{ workout.duration }})</span>
({{ t('workouts.PAUSES') }}: <span>{{ workoutObject.pauses }}</span> -
{{ t('workouts.TOTAL_DURATION') }}:
<span>{{ workoutObject.duration }})</span>
</div>
</div>
<div class="workout-data">
<i class="fa fa-road" aria-hidden="true" />
{{ t('workouts.DISTANCE') }}: <span>{{ workout.distance }} km</span>
<WorkoutRecord :workout="workout" record_type="FD" />
{{ t('workouts.DISTANCE') }}: <span>{{ workoutObject.distance }} km</span>
<WorkoutRecord :workoutObject="workoutObject" record_type="FD" />
</div>
<div class="workout-data">
<i class="fa fa-tachometer" aria-hidden="true" />
{{ t('workouts.AVERAGE_SPEED') }}:
<span>{{ workout.ave_speed }} km/h</span
><WorkoutRecord :workout="workout" record_type="AS" /><br />
{{ t('workouts.MAX_SPEED') }}: <span>{{ workout.max_speed }} km/h</span>
<WorkoutRecord :workout="workout" record_type="MS" />
<span>{{ workoutObject.aveSpeed }} km/h</span
><WorkoutRecord :workoutObject="workoutObject" record_type="AS" /><br />
{{ t('workouts.MAX_SPEED') }}:
<span>{{ workoutObject.maxSpeed }} km/h</span>
<WorkoutRecord :workoutObject="workoutObject" record_type="MS" />
</div>
<div
class="workout-data"
v-if="workout.max_alt !== null && workout.min_alt !== null"
v-if="workoutObject.maxAlt !== null && workoutObject.minAlt !== null"
>
<img class="mountains" src="/img/misc/mountains.svg" />
{{ t('workouts.MIN_ALTITUDE') }}: <span>{{ workout.min_alt }} m</span
{{ t('workouts.MIN_ALTITUDE') }}: <span>{{ workoutObject.minAlt }} m</span
><br />
{{ t('workouts.MAX_ALTITUDE') }}: <span>{{ workout.max_alt }} m</span>
{{ t('workouts.MAX_ALTITUDE') }}:
<span>{{ workoutObject.maxAlt }} m</span>
</div>
<div
class="workout-data"
v-if="workout.ascent !== null && workout.descent !== null"
v-if="workoutObject.ascent !== null && workoutObject.descent !== null"
>
<i class="fa fa-location-arrow" aria-hidden="true" />
{{ t('workouts.ASCENT') }}: <span>{{ workout.ascent }} m</span><br />
{{ t('workouts.DESCENT') }}: <span>{{ workout.descent }} m</span>
{{ t('workouts.ASCENT') }}: <span>{{ workoutObject.ascent }} m</span
><br />
{{ t('workouts.DESCENT') }}: <span>{{ workoutObject.descent }} m</span>
</div>
<WorkoutWeather :workout="workout" />
<WorkoutWeather :workoutObject="workoutObject" />
</div>
</template>
@ -49,7 +53,7 @@
import WorkoutRecord from '@/components/Workout/WorkoutDetail/WorkoutRecord.vue'
import WorkoutWeather from '@/components/Workout/WorkoutDetail/WorkoutWeather.vue'
import { IWorkout } from '@/types/workouts'
import { IWorkoutObject } from '@/types/workouts'
export default defineComponent({
name: 'WorkoutData',
components: {
@ -57,8 +61,8 @@
WorkoutWeather,
},
props: {
workout: {
type: Object as PropType<IWorkout>,
workoutObject: {
type: Object as PropType<IWorkoutObject>,
required: true,
},
},
@ -67,7 +71,8 @@
return {
withPause: computed(
() =>
props.workout.pauses !== '0:00:00' && props.workout.pauses !== null
props.workoutObject.pauses !== '0:00:00' &&
props.workoutObject.pauses !== null
),
t,
}

View File

@ -2,8 +2,8 @@
<span
class="workout-record"
v-if="
workout.records &&
workout.records.find((record) => record.record_type === record_type)
workoutObject.records &&
workoutObject.records.find((record) => record.record_type === record_type)
"
>
<sup>
@ -15,12 +15,12 @@
<script lang="ts">
import { defineComponent, PropType } from 'vue'
import { IWorkout } from '@/types/workouts'
import { IWorkoutObject } from '@/types/workouts'
export default defineComponent({
name: 'WorkoutRecord',
props: {
workout: {
type: Object as PropType<IWorkout>,
workoutObject: {
type: Object as PropType<IWorkoutObject>,
required: true,
},
record_type: {

View File

@ -1,5 +1,8 @@
<template>
<div id="workout-weather" v-if="workout.weather_start && workout.weather_end">
<div
id="workout-weather"
v-if="workoutObject.weatherStart && workoutObject.weatherEnd"
>
<table class="weather-table">
<thead>
<tr>
@ -9,12 +12,16 @@
{{ t('workouts.START') }}
<img
class="weather-img"
:src="`/img/weather/${workout.weather_start.icon}.svg`"
:src="`/img/weather/${workoutObject.weatherStart.icon}.svg`"
:alt="
t(`workouts.WEATHER.DARK_SKY.${workout.weather_start.icon}`)
t(
`workouts.WEATHER.DARK_SKY.${workoutObject.weatherStart.icon}`
)
"
:title="
t(`workouts.WEATHER.DARK_SKY.${workout.weather_start.icon}`)
t(
`workouts.WEATHER.DARK_SKY.${workoutObject.weatherStart.icon}`
)
"
/>
</div>
@ -24,12 +31,16 @@
{{ t('workouts.END') }}
<img
class="weather-img"
:src="`/img/weather/${workout.weather_end.icon}.svg`"
:src="`/img/weather/${workoutObject.weatherEnd.icon}.svg`"
:alt="
t(`workouts.WEATHER.DARK_SKY.${workout.weather_end.icon}`)
t(
`workouts.WEATHER.DARK_SKY.${workoutObject.weatherEnd.icon}`
)
"
:title="
t(`workouts.WEATHER.DARK_SKY.${workout.weather_end.icon}`)
t(
`workouts.WEATHER.DARK_SKY.${workoutObject.weatherEnd.icon}`
)
"
/>
</div>
@ -46,8 +57,12 @@
:title="t(`workouts.WEATHER.TEMPERATURE`)"
/>
</td>
<td>{{ Number(workout.weather_start.temperature).toFixed(1) }}°C</td>
<td>{{ Number(workout.weather_end.temperature).toFixed(1) }}°C</td>
<td>
{{ Number(workoutObject.weatherStart.temperature).toFixed(1) }}°C
</td>
<td>
{{ Number(workoutObject.weatherEnd.temperature).toFixed(1) }}°C
</td>
</tr>
<tr>
<td>
@ -59,9 +74,11 @@
/>
</td>
<td>
{{ Number(workout.weather_start.humidity * 100).toFixed(1) }}%
{{ Number(workoutObject.weatherStart.humidity * 100).toFixed(1) }}%
</td>
<td>
{{ Number(workoutObject.weatherEnd.humidity * 100).toFixed(1) }}%
</td>
<td>{{ Number(workout.weather_end.humidity * 100).toFixed(1) }}%</td>
</tr>
<tr>
<td>
@ -72,8 +89,8 @@
:title="t(`workouts.WEATHER.WIND`)"
/>
</td>
<td>{{ Number(workout.weather_start.wind).toFixed(1) }}m/s</td>
<td>{{ Number(workout.weather_end.wind).toFixed(1) }}m/s</td>
<td>{{ Number(workoutObject.weatherStart.wind).toFixed(1) }}m/s</td>
<td>{{ Number(workoutObject.weatherEnd.wind).toFixed(1) }}m/s</td>
</tr>
</tbody>
</table>
@ -84,12 +101,12 @@
import { defineComponent, PropType } from 'vue'
import { useI18n } from 'vue-i18n'
import { IWorkout } from '@/types/workouts'
import { IWorkoutObject } from '@/types/workouts'
export default defineComponent({
name: 'WorkoutWeather',
props: {
workout: {
type: Object as PropType<IWorkout>,
workoutObject: {
type: Object as PropType<IWorkoutObject>,
required: true,
},
},

View File

@ -4,18 +4,15 @@
<template #title>
<div
class="workout-previous workout-arrow"
:class="{ inactive: !workoutData.workout.previous_workout }"
:class="{ inactive: !workoutObject.previousUrl }"
:title="
workoutData.workout.previous_workout
? t('workouts.PREVIOUS_WORKOUT')
: t('workouts.NO_PREVIOUS_WORKOUT')
workoutObject.previousUrl
? t(`workouts.PREVIOUS_${workoutObject.type}`)
: t(`workouts.NO_PREVIOUS_${workoutObject.type}`)
"
@click="
workoutData.workout.previous_workout
? $router.push({
name: 'Workout',
params: { workoutId: workoutData.workout.previous_workout },
})
workoutObject.previousUrl
? $router.push(workoutObject.previousUrl)
: null
"
>
@ -26,27 +23,41 @@
<img alt="workout sport logo" :src="sport.img" />
</div>
<div class="workout-title-date">
<div class="workout-title">{{ workoutData.workout.title }}</div>
<div class="workout-title" v-if="workoutObject.type === 'WORKOUT'">
{{ workoutObject.title }}
</div>
<div class="workout-title" v-else>
<router-link
:to="{
name: 'Workout',
params: { workoutId: workoutObject.workoutId },
}"
>
{{ workoutObject.title }}
</router-link>
<span class="workout-segment">
<i class="fa fa-map-marker" aria-hidden="true" />
{{ t('workouts.SEGMENT') }}
{{ workoutObject.segmentId + 1 }}
</span>
</div>
<div class="workout-date">
{{ workoutDate.workout_date }} - {{ workoutDate.workout_time }}
{{ workoutObject.workoutDate }} -
{{ workoutObject.workoutTime }}
</div>
</div>
</div>
<div
class="workout-next workout-arrow"
:class="{ inactive: !workoutData.workout.next_workout }"
:class="{ inactive: !workoutObject.nextUrl }"
:title="
workoutData.workout.next_workout
? t('workouts.NEXT_WORKOUT')
: t('workouts.NO_NEXT_WORKOUT')
workoutObject.nextUrl
? t(`workouts.NEXT_${workoutObject.type}`)
: t(`workouts.NO_NEXT_${workoutObject.type}`)
"
@click="
workoutData.workout.next_workout
? $router.push({
name: 'Workout',
params: { workoutId: workoutData.workout.next_workout },
})
: null
workoutObject.nextUrl ? $router.push(workoutObject.nextUrl) : null
"
>
<i class="fa fa-chevron-right" aria-hidden="true" />
@ -57,25 +68,37 @@
:workoutData="workoutData"
:markerCoordinates="markerCoordinates"
/>
<WorkoutData :workout="workoutData.workout" />
<WorkoutData :workoutObject="workoutObject" />
</template>
</Card>
</div>
</template>
<script lang="ts">
import { PropType, defineComponent, computed, watch } from 'vue'
import {
ComputedRef,
PropType,
Ref,
defineComponent,
computed,
ref,
watch,
} from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute } from 'vue-router'
import Card from '@/components/Common/Card.vue'
import WorkoutData from '@/components/Workout/WorkoutDetail/WorkoutData.vue'
import WorkoutMap from '@/components/Workout/WorkoutDetail/WorkoutMap.vue'
import { WORKOUTS_STORE } from '@/store/constants'
import { ISport } from '@/types/sports'
import { IAuthUserProfile } from '@/types/user'
import { IWorkoutData, TCoordinates } from '@/types/workouts'
import { useStore } from '@/use/useStore'
import {
IWorkout,
IWorkoutData,
IWorkoutObject,
IWorkoutSegment,
TCoordinates,
} from '@/types/workouts'
import { formatWorkoutDate, getDateWithTZ } from '@/utils/dates'
export default defineComponent({
@ -101,17 +124,98 @@
type: Object as PropType<IWorkoutData>,
required: true,
},
displaySegment: {
type: Boolean,
required: true,
},
},
setup(props) {
const route = useRoute()
const store = useStore()
const { t } = useI18n()
function getWorkoutObjectUrl(
workout: IWorkout,
displaySegment: boolean,
segmentId: number | null
): Record<string, string | null> {
const previousUrl =
displaySegment && segmentId && segmentId !== 1
? `/workouts/${workout.id}/segment/${segmentId - 1}`
: !displaySegment && workout.previous_workout
? `/workouts/${workout.previous_workout}`
: null
const nextUrl =
displaySegment && segmentId && segmentId < workout.segments.length
? `/workouts/${workout.id}/segment/${segmentId + 1}`
: !displaySegment && workout.next_workout
? `/workouts/${workout.next_workout}`
: null
return {
previousUrl,
nextUrl,
}
}
function getWorkoutObject(
workout: IWorkout,
segment: IWorkoutSegment | null
): IWorkoutObject {
const urls = getWorkoutObjectUrl(
workout,
props.displaySegment,
segmentId.value ? +segmentId.value : null
)
const workoutDate = formatWorkoutDate(
getDateWithTZ(
props.workoutData.workout.workout_date,
props.authUser.timezone
)
)
return {
ascent: segment ? segment.ascent : workout.ascent,
aveSpeed: segment ? segment.ave_speed : workout.ave_speed,
distance: segment ? segment.distance : workout.distance,
descent: segment ? segment.descent : workout.descent,
duration: segment ? segment.duration : workout.duration,
maxAlt: segment ? segment.max_alt : workout.max_alt,
maxSpeed: segment ? segment.max_speed : workout.max_speed,
minAlt: segment ? segment.min_alt : workout.min_alt,
moving: segment ? segment.moving : workout.moving,
nextUrl: urls.nextUrl,
pauses: segment ? segment.pauses : workout.pauses,
previousUrl: urls.previousUrl,
records: segment ? [] : workout.records,
segmentId: segment ? segment.segment_id : null,
title: workout.title,
type: props.displaySegment ? 'SEGMENT' : 'WORKOUT',
workoutDate: workoutDate.workout_date,
weatherEnd: segment ? null : workout.weather_end,
workoutId: workout.id,
weatherStart: segment ? null : workout.weather_start,
workoutTime: workoutDate.workout_time,
}
}
const workout: ComputedRef<IWorkout> = computed(
() => props.workoutData.workout
)
let segmentId: Ref<number | null> = ref(
route.params.workoutId ? +route.params.segmentId : null
)
const segment: ComputedRef<IWorkoutSegment | null> = computed(() =>
workout.value.segments.length > 0 && segmentId.value
? workout.value.segments[+segmentId.value - 1]
: null
)
watch(
() => route.params.workoutId,
async (newWorkoutId) => {
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_WORKOUT_DATA, newWorkoutId)
() => route.params.segmentId,
async (newSegmentId) => {
if (newSegmentId) {
segmentId.value = +newSegmentId
}
}
)
return {
sport: computed(() =>
props.sports
@ -120,13 +224,8 @@
)
: {}
),
workoutDate: computed(() =>
formatWorkoutDate(
getDateWithTZ(
props.workoutData.workout.workout_date,
props.authUser.timezone
)
)
workoutObject: computed(() =>
getWorkoutObject(workout.value, segment.value)
),
t,
}
@ -166,6 +265,10 @@
font-size: 0.8em;
font-weight: normal;
}
.workout-segment {
font-style: italic;
font-weight: normal;
}
}
}
.card-content {

View File

@ -0,0 +1,72 @@
<template>
<div id="workout-segments">
<Card :without-title="false">
<template #title>{{ t('workouts.SEGMENT', 2) }}</template>
<template #content>
<ul>
<li v-for="(segment, index) in segments" :key="segment.segment_id">
<router-link
:to="{
name: 'WorkoutSegment',
params: {
workoutId: segment.workout_id,
segmentId: index + 1,
},
}"
>{{ t('workouts.SEGMENT', 1) }} {{ index + 1 }}</router-link
>
({{ t('workouts.DISTANCE') }}: {{ segment.distance }} km,
{{ t('workouts.DURATION') }}: {{ segment.duration }})
</li>
</ul>
</template>
</Card>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue'
import { useI18n } from 'vue-i18n'
import Card from '@/components/Common/Card.vue'
import { IWorkoutSegment } from '@/types/workouts'
export default defineComponent({
name: 'WorkoutSegments',
components: {
Card,
},
props: {
segments: {
type: Object as PropType<IWorkoutSegment[]>,
required: true,
},
},
setup() {
const { t } = useI18n()
return { t }
},
})
</script>
<style lang="scss" scoped>
@import '~@/scss/base';
#workout-segments {
::v-deep(.card) {
.card-title {
text-transform: capitalize;
}
.card-content {
padding-bottom: 0;
padding-top: 0;
a {
font-weight: bold;
}
ul {
padding: 0 $default-padding;
list-style: square;
}
}
}
}
</style>

View File

@ -13,22 +13,27 @@
"MAX_ALTITUDE": "max. altitude",
"MAX_SPEED": "max. speed",
"MIN_ALTITUDE": "min. altitude",
"NEXT_SEGMENT": "No next segment",
"NEXT_WORKOUT": "Next workout",
"NO_DATA_CLEANING": "data from gpx, without any cleaning",
"NO_MAP": "No map",
"NO_NEXT_SEGMENT": "No next segment",
"NO_NEXT_WORKOUT": "No next workout",
"NO_NOTES": "No notes",
"NO_PREVIOUS_SEGMENT": "No previous segment",
"NO_PREVIOUS_WORKOUT": "No previous workout",
"NO_RECORDS": "No records.",
"NO_WORKOUTS": "No workouts.",
"NOTES": "Notes",
"PAUSES": "pauses",
"PREVIOUS_SEGMENT": "Previous segment",
"PREVIOUS_WORKOUT": "Previous workout",
"RECORD": "record | records",
"RECORD_AS": "Ave. speed",
"RECORD_FD": "Farest distance",
"RECORD_LD": "Longest duration",
"RECORD_MS": "Max. speed",
"SEGMENT": "segment | segments",
"SPEED": "speed",
"SPORT": "sport | sports",
"START": "start",

View File

@ -13,22 +13,27 @@
"MAX_ALTITUDE": "altitude max",
"MAX_SPEED": "vitesse max",
"MIN_ALTITUDE": "altitude min",
"NEXT_SEGMENT": "Segment suivant",
"NEXT_WORKOUT": "Séance suivante",
"NO_DATA_CLEANING": "données issues du fichier gpx, sans correction",
"NO_MAP": "Pas de carte",
"NO_NEXT_SEGMENT": "Pas de segment suivant",
"NO_NEXT_WORKOUT": "Pas de séance suivante",
"NO_NOTES": "Pas de notes",
"NO_PREVIOUS_WORKOUT": "Pas de séances précédente",
"NO_PREVIOUS_SEGMENT": "Pas de segment précédent",
"NO_PREVIOUS_WORKOUT": "Pas de séance précédente",
"NO_RECORDS": "Pas de records.",
"NO_WORKOUTS": "Pas de séances.",
"NOTES": "Notes",
"PAUSES": "pauses",
"PREVIOUS_SEGMENT": "Segment précédent",
"PREVIOUS_WORKOUT": "Séance précédente",
"RECORD": "record | records",
"RECORD_AS": "Vitesse moy.",
"RECORD_FD": "Distance la + longue",
"RECORD_LD": "Durée la + longue",
"RECORD_MS": "Vitesse max.",
"SEGMENT": "segment | segments",
"SPEED": "vitesse",
"SPORT": "sport | sports",
"START": "début",

View File

@ -29,6 +29,13 @@ const routes: Array<RouteRecordRaw> = [
path: '/workouts/:workoutId',
name: 'Workout',
component: Workout,
props: { displaySegment: false },
},
{
path: '/workouts/:workoutId/segment/:segmentId',
name: 'WorkoutSegment',
component: Workout,
props: { displaySegment: true },
},
{ path: '/:pathMatch(.*)*', name: 'not-found', component: NotFoundView },
]

View File

@ -7,7 +7,7 @@ import {
IWorkoutsActions,
IWorkoutsState,
} from '@/store/modules/workouts/types'
import { IWorkoutsPayload } from '@/types/workouts'
import { IWorkout, IWorkoutPayload, IWorkoutsPayload } from '@/types/workouts'
import { handleError } from '@/utils'
const getWorkouts = (
@ -51,41 +51,58 @@ export const actions: ActionTree<IWorkoutsState, IRootState> &
},
[WORKOUTS_STORE.ACTIONS.GET_WORKOUT_DATA](
context: ActionContext<IWorkoutsState, IRootState>,
workoutId: string
payload: IWorkoutPayload
): void {
context.commit(ROOT_STORE.MUTATIONS.EMPTY_ERROR_MESSAGES)
context.commit(WORKOUTS_STORE.MUTATIONS.SET_WORKOUT_LOADING, true)
const segmentUrl = payload.segmentId ? `/segment/${payload.segmentId}` : ''
authApi
.get(`workouts/${workoutId}`)
.get(`workouts/${payload.workoutId}`)
.then((res) => {
const workout: IWorkout = res.data.data.workouts[0]
if (res.data.status === 'success') {
if (
payload.segmentId &&
(workout.segments.length === 0 ||
!workout.segments[+payload.segmentId - 1])
) {
throw new Error('WORKOUT_NOT_FOUND')
}
context.commit(
WORKOUTS_STORE.MUTATIONS.SET_WORKOUT,
res.data.data.workouts[0]
)
if (res.data.data.workouts[0].with_gpx) {
authApi.get(`workouts/${workoutId}/chart_data`).then((res) => {
if (res.data.status === 'success') {
context.commit(
WORKOUTS_STORE.MUTATIONS.SET_WORKOUT_CHART_DATA,
res.data.data.chart_data
)
}
})
authApi.get(`workouts/${workoutId}/gpx`).then((res) => {
if (res.data.status === 'success') {
context.commit(
WORKOUTS_STORE.MUTATIONS.SET_WORKOUT_GPX,
res.data.data.gpx
)
}
})
authApi
.get(`workouts/${payload.workoutId}/chart_data${segmentUrl}`)
.then((res) => {
if (res.data.status === 'success') {
context.commit(
WORKOUTS_STORE.MUTATIONS.SET_WORKOUT_CHART_DATA,
res.data.data.chart_data
)
}
})
authApi
.get(`workouts/${payload.workoutId}/gpx${segmentUrl}`)
.then((res) => {
if (res.data.status === 'success') {
context.commit(
WORKOUTS_STORE.MUTATIONS.SET_WORKOUT_GPX,
res.data.data.gpx
)
}
})
}
} else {
context.commit(WORKOUTS_STORE.MUTATIONS.EMPTY_WORKOUT)
handleError(context, null)
}
})
.catch((error) => handleError(context, error))
.catch((error) => {
context.commit(WORKOUTS_STORE.MUTATIONS.EMPTY_WORKOUT)
handleError(context, error)
})
.finally(() =>
context.commit(WORKOUTS_STORE.MUTATIONS.SET_WORKOUT_LOADING, false)
)

View File

@ -12,6 +12,7 @@ import {
IWorkoutApiChartData,
IWorkoutsPayload,
IWorkoutData,
IWorkoutPayload,
} from '@/types/workouts'
export interface IWorkoutsState {
@ -31,7 +32,7 @@ export interface IWorkoutsActions {
): void
[WORKOUTS_STORE.ACTIONS.GET_WORKOUT_DATA](
context: ActionContext<IWorkoutsState, IRootState>,
workoutId: string | string[]
payload: IWorkoutPayload
): void
}

View File

@ -73,6 +73,35 @@ export interface IWorkout {
workout_date: string
}
export interface IWorkoutObject {
ascent: number | null
aveSpeed: number
descent: number | null
distance: number
duration: string
maxAlt: number | null
maxSpeed: number
minAlt: number | null
moving: string
nextUrl: string | null
pauses: string | null
previousUrl: string | null
records: IRecord[]
segmentId: number | null
title: string
type: string
workoutDate: string
weatherEnd: IWeather | null
workoutId: string
weatherStart: IWeather | null
workoutTime: string
}
export interface IWorkoutPayload {
workoutId: string | string[]
segmentId?: string | string[]
}
export interface IWorkoutsPayload {
from?: string
to?: string

View File

@ -14,6 +14,7 @@
:sports="sports"
:authUser="authUser"
:markerCoordinates="markerCoordinates"
:displaySegment="displaySegment"
/>
<WorkoutChart
v-if="
@ -21,9 +22,17 @@
"
:workoutData="workoutData"
:authUser="authUser"
:displaySegment="displaySegment"
@getCoordinates="updateCoordinates"
/>
<WorkoutNotes :notes="workoutData.workout.notes" />
<WorkoutSegments
v-if="!displaySegment && workoutData.workout.segments.length > 1"
:segments="workoutData.workout.segments"
></WorkoutSegments>
<WorkoutNotes
v-if="!displaySegment"
:notes="workoutData.workout.notes"
/>
</div>
<div v-else>
<NotFound target="WORKOUT" />
@ -40,6 +49,7 @@
computed,
defineComponent,
ref,
watch,
onBeforeMount,
onUnmounted,
} from 'vue'
@ -50,9 +60,10 @@
import WorkoutChart from '@/components/Workout/WorkoutChart/index.vue'
import WorkoutDetail from '@/components/Workout/WorkoutDetail/index.vue'
import WorkoutNotes from '@/components/Workout/WorkoutNotes.vue'
import WorkoutSegments from '@/components/Workout/WorkoutSegments.vue'
import { SPORTS_STORE, USER_STORE, WORKOUTS_STORE } from '@/store/constants'
import { IAuthUserProfile } from '@/types/user'
import { IWorkoutData, TCoordinates } from '@/types/workouts'
import { IWorkoutData, IWorkoutPayload, TCoordinates } from '@/types/workouts'
import { useStore } from '@/use/useStore'
export default defineComponent({
@ -63,16 +74,25 @@
WorkoutChart,
WorkoutDetail,
WorkoutNotes,
WorkoutSegments,
},
setup() {
props: {
displaySegment: {
type: Boolean,
required: true,
},
},
setup(props) {
const route = useRoute()
const store = useStore()
onBeforeMount(() =>
store.dispatch(
WORKOUTS_STORE.ACTIONS.GET_WORKOUT_DATA,
route.params.workoutId
)
)
onBeforeMount(() => {
const payload: IWorkoutPayload = { workoutId: route.params.workoutId }
if (props.displaySegment) {
payload.segmentId = route.params.segmentId
}
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_WORKOUT_DATA, payload)
})
const workoutData: ComputedRef<IWorkoutData> = computed(
() => store.getters[WORKOUTS_STORE.GETTERS.WORKOUT_DATA]
@ -93,9 +113,31 @@
}
}
watch(
() => route.params.workoutId,
async (newWorkoutId) => {
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_WORKOUT_DATA, {
workoutId: newWorkoutId,
})
}
)
watch(
() => route.params.segmentId,
async (newSegmentId) => {
const payload: IWorkoutPayload = {
workoutId: route.params.workoutId,
}
if (newSegmentId) {
payload.segmentId = newSegmentId
}
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_WORKOUT_DATA, payload)
}
)
onUnmounted(() => {
store.commit(WORKOUTS_STORE.MUTATIONS.EMPTY_WORKOUT)
})
return {
authUser,
markerCoordinates,