mirror of
https://github.com/joaovitoriasilva/endurain.git
synced 2026-01-09 07:47:58 -05:00
feat: show HR based on zone that calculated from user birthdate (if any)
This commit is contained in:
10
backend/app/activities/activity_streams/constants.py
Normal file
10
backend/app/activities/activity_streams/constants.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# Stream type constants for activity streams
|
||||
STREAM_TYPE_HR = 1
|
||||
STREAM_TYPE_POWER = 2
|
||||
STREAM_TYPE_CADENCE = 3
|
||||
STREAM_TYPE_ELEVATION = 4
|
||||
STREAM_TYPE_SPEED = 5
|
||||
STREAM_TYPE_PACE = 6
|
||||
STREAM_TYPE_MAP = 7
|
||||
|
||||
STREAM_TYPE_HR_ZONES = 11
|
||||
@@ -1,5 +1,7 @@
|
||||
from fastapi import HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
import numpy as np
|
||||
import datetime
|
||||
|
||||
import activities.activity_streams.schema as activity_streams_schema
|
||||
import activities.activity_streams.models as activity_streams_models
|
||||
@@ -10,8 +12,12 @@ import activities.activity.models as activities_models
|
||||
|
||||
import server_settings.crud as server_settings_crud
|
||||
|
||||
import users.user.crud as users_crud
|
||||
|
||||
import core.logger as core_logger
|
||||
|
||||
import activities.activity_streams.constants as stream_constants
|
||||
|
||||
|
||||
def get_activity_streams(activity_id: int, token_user_id: int, db: Session):
|
||||
try:
|
||||
@@ -44,18 +50,18 @@ def get_activity_streams(activity_id: int, token_user_id: int, db: Session):
|
||||
activity_streams = [
|
||||
stream for stream in activity_streams
|
||||
if not (
|
||||
(activity.hide_hr and stream.stream_type == 1) or
|
||||
(activity.hide_power and stream.stream_type == 2) or
|
||||
(activity.hide_cadence and stream.stream_type == 3) or
|
||||
(activity.hide_elevation and stream.stream_type == 4) or
|
||||
(activity.hide_speed and stream.stream_type == 5) or
|
||||
(activity.hide_pace and stream.stream_type == 6) or
|
||||
(activity.hide_map and stream.stream_type == 7)
|
||||
(activity.hide_hr and stream.stream_type == stream_constants.STREAM_TYPE_HR) or
|
||||
(activity.hide_power and stream.stream_type == stream_constants.STREAM_TYPE_POWER) or
|
||||
(activity.hide_cadence and stream.stream_type == stream_constants.STREAM_TYPE_CADENCE) or
|
||||
(activity.hide_elevation and stream.stream_type == stream_constants.STREAM_TYPE_ELEVATION) or
|
||||
(activity.hide_speed and stream.stream_type == stream_constants.STREAM_TYPE_SPEED) or
|
||||
(activity.hide_pace and stream.stream_type == stream_constants.STREAM_TYPE_PACE) or
|
||||
(activity.hide_map and stream.stream_type == stream_constants.STREAM_TYPE_MAP)
|
||||
)
|
||||
]
|
||||
|
||||
# Return the activity streams
|
||||
return activity_streams
|
||||
return [transform_activity_streams(stream, activity, db) for stream in activity_streams]
|
||||
except Exception as err:
|
||||
# Log the exception
|
||||
core_logger.print_to_log(
|
||||
@@ -108,18 +114,18 @@ def get_public_activity_streams(activity_id: int, db: Session):
|
||||
activity_streams = [
|
||||
stream for stream in activity_streams
|
||||
if not (
|
||||
(activity.hide_hr and stream.stream_type == 1) or
|
||||
(activity.hide_power and stream.stream_type == 2) or
|
||||
(activity.hide_cadence and stream.stream_type == 3) or
|
||||
(activity.hide_elevation and stream.stream_type == 4) or
|
||||
(activity.hide_speed and stream.stream_type == 5) or
|
||||
(activity.hide_pace and stream.stream_type == 6) or
|
||||
(activity.hide_map and stream.stream_type == 7)
|
||||
(activity.hide_hr and stream.stream_type == stream_constants.STREAM_TYPE_HR) or
|
||||
(activity.hide_power and stream.stream_type == stream_constants.STREAM_TYPE_POWER) or
|
||||
(activity.hide_cadence and stream.stream_type == stream_constants.STREAM_TYPE_CADENCE) or
|
||||
(activity.hide_elevation and stream.stream_type == stream_constants.STREAM_TYPE_ELEVATION) or
|
||||
(activity.hide_speed and stream.stream_type == stream_constants.STREAM_TYPE_SPEED) or
|
||||
(activity.hide_pace and stream.stream_type == stream_constants.STREAM_TYPE_PACE) or
|
||||
(activity.hide_map and stream.stream_type == stream_constants.STREAM_TYPE_MAP)
|
||||
)
|
||||
]
|
||||
|
||||
# Return the activity streams
|
||||
return activity_streams
|
||||
return [transform_activity_streams(stream, activity, db) for stream in activity_streams]
|
||||
except Exception as err:
|
||||
# Log the exception
|
||||
core_logger.print_to_log(
|
||||
@@ -161,23 +167,23 @@ def get_activity_stream_by_type(activity_id: int, stream_type: int, token_user_i
|
||||
user_is_owner = False
|
||||
|
||||
if not user_is_owner:
|
||||
if activity.hide_hr and activity_stream.stream_type == 1:
|
||||
if activity.hide_hr and activity_stream.stream_type == stream_constants.STREAM_TYPE_HR:
|
||||
return None
|
||||
if activity.hide_power and activity_stream.stream_type == 2:
|
||||
if activity.hide_power and activity_stream.stream_type == stream_constants.STREAM_TYPE_POWER:
|
||||
return None
|
||||
if activity.hide_cadence and activity_stream.stream_type == 3:
|
||||
if activity.hide_cadence and activity_stream.stream_type == stream_constants.STREAM_TYPE_CADENCE:
|
||||
return None
|
||||
if activity.hide_elevation and activity_stream.stream_type == 4:
|
||||
if activity.hide_elevation and activity_stream.stream_type == stream_constants.STREAM_TYPE_ELEVATION:
|
||||
return None
|
||||
if activity.hide_speed and activity_stream.stream_type == 5:
|
||||
if activity.hide_speed and activity_stream.stream_type == stream_constants.STREAM_TYPE_SPEED:
|
||||
return None
|
||||
if activity.hide_pace and activity_stream.stream_type == 6:
|
||||
if activity.hide_pace and activity_stream.stream_type == stream_constants.STREAM_TYPE_PACE:
|
||||
return None
|
||||
if activity.hide_map and activity_stream.stream_type == 7:
|
||||
if activity.hide_map and activity_stream.stream_type == stream_constants.STREAM_TYPE_MAP:
|
||||
return None
|
||||
|
||||
# Return the activity stream
|
||||
return activity_stream
|
||||
return transform_activity_streams(activity_stream, activity, db)
|
||||
except Exception as err:
|
||||
# Log the exception
|
||||
core_logger.print_to_log(
|
||||
@@ -189,6 +195,77 @@ def get_activity_stream_by_type(activity_id: int, stream_type: int, token_user_i
|
||||
detail="Internal Server Error",
|
||||
) from err
|
||||
|
||||
def transform_activity_streams(activity_stream, activity, db):
|
||||
print("Transforming activity stream")
|
||||
"""
|
||||
Transform the activity stream based on the stream type.
|
||||
"""
|
||||
if activity_stream.stream_type == stream_constants.STREAM_TYPE_HR:
|
||||
return transform_activity_streams_hr(activity_stream, activity, db)
|
||||
else:
|
||||
return activity_stream
|
||||
|
||||
def transform_activity_streams_hr(activity_stream, activity, db):
|
||||
print("Transforming HR activity stream")
|
||||
"""
|
||||
Transform the activity stream for heart rate.
|
||||
Calculate the percentage of time spent in each HR zone using numpy for performance.
|
||||
"""
|
||||
detail_user = users_crud.get_user_by_id(activity.user_id, db)
|
||||
print(f"Detail user: {detail_user}")
|
||||
if not detail_user or not detail_user.birthdate:
|
||||
return activity_stream
|
||||
year = int(detail_user.birthdate.split("-")[0])
|
||||
current_year = datetime.datetime.now().year
|
||||
max_heart_rate = 220 - (current_year - year)
|
||||
print(f"Max heart rate: {max_heart_rate}")
|
||||
|
||||
zone_1 = max_heart_rate * 0.5
|
||||
zone_2 = max_heart_rate * 0.6
|
||||
zone_3 = max_heart_rate * 0.7
|
||||
zone_4 = max_heart_rate * 0.8
|
||||
print(f"Heart rate zones: {zone_1}, {zone_2}, {zone_3}, {zone_4}")
|
||||
|
||||
waypoints = activity_stream.stream_waypoints
|
||||
if not waypoints or not isinstance(waypoints, list):
|
||||
return activity_stream
|
||||
|
||||
hr_values = np.array([wp.get("hr") for wp in waypoints if wp.get("hr") is not None])
|
||||
|
||||
total = len(hr_values)
|
||||
print(f"Total HR values: {total}")
|
||||
|
||||
if total == 0:
|
||||
return activity_stream
|
||||
|
||||
zone_counts = [
|
||||
np.sum(hr_values < zone_1),
|
||||
np.sum((hr_values >= zone_1) & (hr_values < zone_2)),
|
||||
np.sum((hr_values >= zone_2) & (hr_values < zone_3)),
|
||||
np.sum((hr_values >= zone_3) & (hr_values < zone_4)),
|
||||
np.sum(hr_values >= zone_4),
|
||||
]
|
||||
zone_percentages = [round((count / total) * 100, 2) for count in zone_counts]
|
||||
|
||||
# Calculate zone HR boundaries for display
|
||||
zone_hr = {
|
||||
"zone_1": f"< {int(zone_1)}",
|
||||
"zone_2": f"{int(zone_1)} - {int(zone_2) - 1}",
|
||||
"zone_3": f"{int(zone_2)} - {int(zone_3) - 1}",
|
||||
"zone_4": f"{int(zone_3)} - {int(zone_4) - 1}",
|
||||
"zone_5": f">= {int(zone_4)}",
|
||||
}
|
||||
activity_stream.hr_zone_percentages = {
|
||||
"zone_1": {"percent": zone_percentages[0], "hr": zone_hr["zone_1"]},
|
||||
"zone_2": {"percent": zone_percentages[1], "hr": zone_hr["zone_2"]},
|
||||
"zone_3": {"percent": zone_percentages[2], "hr": zone_hr["zone_3"]},
|
||||
"zone_4": {"percent": zone_percentages[3], "hr": zone_hr["zone_4"]},
|
||||
"zone_5": {"percent": zone_percentages[4], "hr": zone_hr["zone_5"]},
|
||||
}
|
||||
|
||||
print(f"HR zone percentages: {activity_stream.hr_zone_percentages}")
|
||||
|
||||
return activity_stream
|
||||
|
||||
def get_public_activity_stream_by_type(activity_id: int, stream_type: int, db: Session):
|
||||
try:
|
||||
@@ -228,19 +305,19 @@ def get_public_activity_stream_by_type(activity_id: int, stream_type: int, db: S
|
||||
if not activity_stream:
|
||||
return None
|
||||
|
||||
if activity.hide_hr and activity_stream.stream_type == 1:
|
||||
if activity.hide_hr and activity_stream.stream_type == stream_constants.STREAM_TYPE_HR:
|
||||
return None
|
||||
if activity.hide_power and activity_stream.stream_type == 2:
|
||||
if activity.hide_power and activity_stream.stream_type == stream_constants.STREAM_TYPE_POWER:
|
||||
return None
|
||||
if activity.hide_cadence and activity_stream.stream_type == 3:
|
||||
if activity.hide_cadence and activity_stream.stream_type == stream_constants.STREAM_TYPE_CADENCE:
|
||||
return None
|
||||
if activity.hide_elevation and activity_stream.stream_type == 4:
|
||||
if activity.hide_elevation and activity_stream.stream_type == stream_constants.STREAM_TYPE_ELEVATION:
|
||||
return None
|
||||
if activity.hide_speed and activity_stream.stream_type == 5:
|
||||
if activity.hide_speed and activity_stream.stream_type == stream_constants.STREAM_TYPE_SPEED:
|
||||
return None
|
||||
if activity.hide_pace and activity_stream.stream_type == 6:
|
||||
if activity.hide_pace and activity_stream.stream_type == stream_constants.STREAM_TYPE_PACE:
|
||||
return None
|
||||
if activity.hide_map and activity_stream.stream_type == 7:
|
||||
if activity.hide_map and activity_stream.stream_type == stream_constants.STREAM_TYPE_MAP:
|
||||
return None
|
||||
|
||||
# Return the activity stream
|
||||
|
||||
@@ -8,6 +8,7 @@ class ActivityStreams(BaseModel):
|
||||
stream_type: int
|
||||
stream_waypoints: List[dict]
|
||||
strava_activity_stream_id: int | None = None
|
||||
hr_zone_percentages: dict | None = None
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "endurain"
|
||||
version = "0.12.2"
|
||||
version = "0.13.0"
|
||||
description = "Endurain API for the Endurain app"
|
||||
authors = ["João Vitória Silva <8648976+joaovitoriasilva@users.noreply.github.com>"]
|
||||
readme = "README.md"
|
||||
@@ -39,6 +39,7 @@ user-agents = "^2.2.0"
|
||||
pydantic = {extras = ["email"], version = "^2.11.3"}
|
||||
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
@@ -124,16 +124,16 @@ onMounted(async () => {
|
||||
try {
|
||||
if (props.activityActivityStreams && props.activityActivityStreams.length > 0) {
|
||||
// Check if the activity has the streams
|
||||
for (let i = 0; i < props.activityActivityStreams.length; i++) {
|
||||
if (props.activityActivityStreams[i].stream_type === 1) {
|
||||
for (const element of props.activityActivityStreams) {
|
||||
if (element.stream_type === 1) {
|
||||
hrPresent.value = true;
|
||||
graphItems.value.push({ type: "hr", label: `${t("activityMandAbovePillsComponent.labelGraphHR")}` });
|
||||
}
|
||||
if (props.activityActivityStreams[i].stream_type === 2) {
|
||||
if (element.stream_type === 2) {
|
||||
powerPresent.value = true;
|
||||
graphItems.value.push({ type: "power", label: `${t("activityMandAbovePillsComponent.labelGraphPower")}` });
|
||||
}
|
||||
if (props.activityActivityStreams[i].stream_type === 3) {
|
||||
if (element.stream_type === 3) {
|
||||
cadPresent.value = true;
|
||||
// Label as "Stroke Rate" over "Cadence" for swimming activities
|
||||
if (activityTypeIsSwimming(props.activity)) {
|
||||
@@ -142,14 +142,14 @@ onMounted(async () => {
|
||||
graphItems.value.push({ type: "cad", label: `${t("activityMandAbovePillsComponent.labelGraphCadence")}` });
|
||||
}
|
||||
}
|
||||
if (props.activityActivityStreams[i].stream_type === 4) {
|
||||
if (element.stream_type === 4) {
|
||||
// Do not show elevation for swimming activities
|
||||
if (!activityTypeIsSwimming(props.activity)) {
|
||||
elePresent.value = true;
|
||||
graphItems.value.push({ type: "ele", label: `${t("activityMandAbovePillsComponent.labelGraphElevation")}` });
|
||||
}
|
||||
}
|
||||
if (props.activityActivityStreams[i].stream_type === 5) {
|
||||
if (element.stream_type === 5) {
|
||||
velPresent.value = true;
|
||||
if (
|
||||
props.activity.activity_type === 4 ||
|
||||
@@ -161,7 +161,7 @@ onMounted(async () => {
|
||||
graphItems.value.push({ type: "vel", label: `${t("activityMandAbovePillsComponent.labelGraphVelocity")}` });
|
||||
}
|
||||
}
|
||||
if (props.activityActivityStreams[i].stream_type === 6) {
|
||||
if (element.stream_type === 6) {
|
||||
pacePresent.value = true;
|
||||
if (
|
||||
props.activity.activity_type !== 4 &&
|
||||
|
||||
@@ -41,7 +41,9 @@
|
||||
</span>
|
||||
|
||||
<!-- Display the date and time -->
|
||||
<span v-if="activity.start_time">{{ formatDateMed(activity.start_time) }} @ {{ formatTime(activity.start_time) }}</span>
|
||||
<span v-if="activity.start_time">
|
||||
{{ formatDateMed(activity.start_time) }} @ {{ formatTime(activity.start_time) }}
|
||||
</span>
|
||||
<!-- Conditionally display city and country -->
|
||||
<span v-if="activity.town || activity.city || activity.country">
|
||||
-
|
||||
@@ -95,7 +97,7 @@
|
||||
<!-- Activity summary -->
|
||||
<div class="row mt-3 align-items-center text-start">
|
||||
<!-- distance -->
|
||||
<div class="col" v-if="activity.activity_type != 10 && activity.activity_type != 14 && activity.activity_type != 18 && activity.activity_type != 19 && activity.activity_type != 20 && activity.activity_type != 21 && activity.activity_type != 22 && activity.activity_type != 23 && activity.activity_type != 24 && activity.activity_type != 25 && activity.activity_type != 26">
|
||||
<div class="col border-start border-opacity-50" v-if="activity.activity_type != 10 && activity.activity_type != 14 && activity.activity_type != 18 && activity.activity_type != 19 && activity.activity_type != 20 && activity.activity_type != 21 && activity.activity_type != 22 && activity.activity_type != 23 && activity.activity_type != 24 && activity.activity_type != 25 && activity.activity_type != 26">
|
||||
<span class="fw-lighter">
|
||||
{{ $t("activitySummaryComponent.activityDistance") }}
|
||||
</span>
|
||||
@@ -116,7 +118,10 @@
|
||||
{{ $t("activitySummaryComponent.activityTime") }}
|
||||
</span>
|
||||
<br>
|
||||
<span>{{ formatSecondsToMinutes(activity.total_elapsed_time) }}</span>
|
||||
<span>
|
||||
{{$t('activitySummaryComponent.activityMovingTime')}}: {{ formatSecondsToMinutes(activity.total_timer_time) }} <br>
|
||||
{{$t('activitySummaryComponent.activityTotalTime')}}: {{ formatSecondsToMinutes(activity.total_elapsed_time) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="col border-start border-opacity-50">
|
||||
<!-- elevation -->
|
||||
@@ -135,19 +140,11 @@
|
||||
<br>
|
||||
{{ formatPace(activity, authStore.user.units) }}
|
||||
</div>
|
||||
<!-- avg_hr -->
|
||||
<div v-else>
|
||||
<span class="fw-lighter">
|
||||
{{ $t("activitySummaryComponent.activityAvgHR") }}
|
||||
</span>
|
||||
<br>
|
||||
<span>{{ formatHr(activity.average_hr) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row d-flex mt-3" v-if="source === 'activity' && activity.activity_type != 10 && activity.activity_type != 14 && activity.activity_type != 18 && activity.activity_type != 19 && activity.activity_type != 20 && activity.activity_type != 21 && activity.activity_type != 22 && activity.activity_type != 23 && activity.activity_type != 24 && activity.activity_type != 25 && activity.activity_type != 26">
|
||||
<!-- avg_power running and cycling activities-->
|
||||
<div class="col" v-if="activity.activity_type == 1 || activity.activity_type == 2 || activity.activity_type == 3 || activity.activity_type == 4 || activity.activity_type == 5 || activity.activity_type == 6 || activity.activity_type == 7 || activity.activity_type == 27">
|
||||
<div class="col border-start border-opacity-50" v-if="activity.activity_type == 1 || activity.activity_type == 2 || activity.activity_type == 3 || activity.activity_type == 4 || activity.activity_type == 5 || activity.activity_type == 6 || activity.activity_type == 7 || activity.activity_type == 27">
|
||||
<span class="fw-lighter">
|
||||
{{ $t("activitySummaryComponent.activityAvgPower") }}
|
||||
</span>
|
||||
@@ -193,6 +190,23 @@
|
||||
<span>{{ formatCalories(activity.calories) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row d-flex mt-3" v-if="source === 'activity' && activity.activity_type != 10 && activity.activity_type != 14 && activity.activity_type != 18 && activity.activity_type != 19 && activity.activity_type != 20 && activity.activity_type != 21 && activity.activity_type != 22 && activity.activity_type != 23 && activity.activity_type != 24 && activity.activity_type != 25 && activity.activity_type != 26">
|
||||
<div class="col border-start border-opacity-50">
|
||||
<!-- hr -->
|
||||
<div>
|
||||
<span class="fw-lighter">
|
||||
{{ $t("activitySummaryComponent.activityHR") }}
|
||||
</span>
|
||||
<br>
|
||||
<span>{{ $t("activitySummaryComponent.activityAvgHR") }}: {{ formatHr(activity.average_hr) }}</span> <br>
|
||||
<span>{{ $t("activitySummaryComponent.activityMaxHR") }}: {{ formatHr(activity.max_hr) }}</span> <br><br>
|
||||
<span v-for="(value, zone, index) in hrZones" :key="zone"
|
||||
:style="{ color: getZoneColor(index) }">
|
||||
{{ $t("activitySummaryComponent.activityHRZone") }} {{ index + 1 }} ({{ value.hr }}) : {{ value.percent }}%<br>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -237,6 +251,10 @@ const props = defineProps({
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
activityActivityStreams: {
|
||||
type: [Object, null],
|
||||
required: true,
|
||||
},
|
||||
source: {
|
||||
type: String,
|
||||
required: true,
|
||||
@@ -259,10 +277,18 @@ const { t } = useI18n();
|
||||
// Reactive data
|
||||
const isLoading = ref(true);
|
||||
const userActivity = ref(null);
|
||||
const hrZones = ref({
|
||||
zone_1: 0,
|
||||
zone_2: 0,
|
||||
zone_3: 0,
|
||||
zone_4: 0,
|
||||
});
|
||||
|
||||
// Lifecycle
|
||||
onMounted(async () => {
|
||||
try {
|
||||
hrZones.value = props.activityActivityStreams.find(stream => stream.hr_zone_percentages).hr_zone_percentages || {};
|
||||
|
||||
if (authStore.isAuthenticated) {
|
||||
userActivity.value = await users.getUserById(props.activity.user_id);
|
||||
} else {
|
||||
@@ -297,4 +323,16 @@ function updateActivityFieldsOnEdit(data) {
|
||||
// Emit the activityEditedFields event to the parent component
|
||||
emit("activityEditedFields", data);
|
||||
}
|
||||
|
||||
function getZoneColor(index) {
|
||||
// Example colors for 5 HR zones
|
||||
const colors = [
|
||||
'#1e90ff', // Zone 1: blue
|
||||
'#28a745', // Zone 2: green
|
||||
'#ffc107', // Zone 3: yellow
|
||||
'#fd7e14', // Zone 4: orange
|
||||
'#dc3545', // Zone 5: red
|
||||
];
|
||||
return colors[index] || '#000';
|
||||
}
|
||||
</script>
|
||||
@@ -10,12 +10,16 @@
|
||||
"labelVirtual": "(Virtual) ",
|
||||
"activityDistance": "Distance",
|
||||
"activityTime": "Time",
|
||||
"activityTotalTime": "Total Time",
|
||||
"activityMovingTime": "Moving Time",
|
||||
"activityElevationGain": "Elevation Gain",
|
||||
"activityPace": "Pace",
|
||||
"activityAvgPower": "Avg Power",
|
||||
"activityAvgSpeed": "Avg Speed",
|
||||
"activityHR": "Heart Rate",
|
||||
"activityAvgHR": "Avg HR",
|
||||
"activityMaxHR": "Max HR",
|
||||
"activityHRZone": "Zone",
|
||||
"activityEleGain": "Elevation gain",
|
||||
"activityEleLoss": "Elevation loss",
|
||||
"activityCalories": "Calories",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<LoadingComponent v-if="isLoading"/>
|
||||
|
||||
<div v-else>
|
||||
<ActivitySummaryComponent v-if="activity" :activity="activity" :source="'activity'" @activityEditedFields="updateActivityFieldsOnEdit" :units="units" />
|
||||
<ActivitySummaryComponent v-if="activity" :activity="activity" :activityActivityStreams="activityActivityStreams" :source="'activity'" @activityEditedFields="updateActivityFieldsOnEdit" :units="units" />
|
||||
<AlertComponent v-if="activity && activity.user_id === authStore.user.id && (activity.hide_start_time || activity.hide_location || activity.hide_map || activity.hide_hr || activity.hide_power || activity.hide_cadence || activity.hide_elevation || activity.hide_speed || activity.hide_pace || activity.hide_laps || activity.hide_workout_sets_steps || activity.hide_gear)" :message="alertPrivacyMessage" :dismissible="true" class="mt-2"/>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user