Files
wp-cycling-stats/includes/admin/pages/page-activity-view.php
T
2026-02-12 22:34:54 +01:00

263 lines
12 KiB
PHP

<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
function statpress_view_activity_page() {
global $wpdb;
$activity_id = isset( $_GET['id'] ) ? intval( $_GET['id'] ) : 0;
if ( $activity_id === 0 ) {
echo '<div class="wrap"><h1>Błąd</h1><p>Nie podano ID aktywności.</p></div>';
return;
}
$table_activities = $wpdb->prefix . 'statpress_activities';
$table_categories = $wpdb->prefix . 'statpress_categories';
$table_event_types = $wpdb->prefix . 'statpress_event_types';
$table_equipment = $wpdb->prefix . 'statpress_equipment';
$sql = $wpdb->prepare(
"
SELECT a.*, c.name as category_name, c.icon, c.color, et.name as event_type_name, eq.name as equipment_name
FROM $table_activities a
LEFT JOIN $table_categories c ON a.category_id = c.id
LEFT JOIN $table_event_types et ON a.event_type_id = et.id
LEFT JOIN $table_equipment eq ON a.equipment_id = eq.id
WHERE a.id = %d
",
$activity_id
);
$activity = $wpdb->get_row( $sql );
if ( ! $activity ) {
echo '<div class="wrap"><h1>Błąd</h1><p>Nie znaleziono aktywności o podanym ID.</p></div>';
return;
}
// Funkcja pomocnicza do wyświetlania wiersza, jeśli wartość istnieje
$render_row = function( $label, $value, $unit = '' ) {
if ( ! is_null( $value ) && '' !== $value ) {
echo '<tr>';
echo '<th scope="row">' . esc_html( $label ) . '</th>';
echo '<td>' . esc_html( $value ) . ( $unit ? ' ' . esc_html( $unit ) : '' ) . '</td>';
echo '</tr>';
}
};
// Prepare map and chart data if GPX exists
$gpx_data = array();
$has_gpx_data = false;
if ( ! empty( $activity->gpx_url ) ) {
$gpx_data = statpress_parse_gpx_data( $activity->gpx_url );
$has_gpx_data = ! empty( $gpx_data['points'] );
}
if ( $has_gpx_data ) {
wp_enqueue_style( 'leaflet-css', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css' );
wp_enqueue_script( 'leaflet-js', 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js', array(), '1.9.4', true );
wp_enqueue_script( 'chart-js', 'https://cdn.jsdelivr.net/npm/chart.js', array(), null, true );
wp_register_script( 'statpress-details-loader', false );
wp_enqueue_script( 'statpress-details-loader' );
// Check which profiles have data
$available_profiles = array();
if ( ! empty( array_filter( $gpx_data['profiles']['elevation'] ) ) ) {
$available_profiles['elevation'] = 'Wysokość';}
if ( ! empty( array_filter( $gpx_data['profiles']['speed'] ) ) ) {
$available_profiles['speed'] = 'Prędkość';}
if ( ! empty( array_filter( $gpx_data['profiles']['hr'] ) ) ) {
$available_profiles['hr'] = 'Tętno';}
if ( ! empty( array_filter( $gpx_data['profiles']['cadence'] ) ) ) {
$available_profiles['cadence'] = 'Kadencja';}
$has_time_data = ! empty( array_filter( $gpx_data['profiles']['time'], fn( $t ) => ! is_null( $t ) ) );
$chart_js = '
const track_points = ' . json_encode( $gpx_data['points'] ) . ';
const profiles = ' . json_encode( $gpx_data['profiles'] ) . ';
let activeChart = null;
if (typeof L !== "undefined" && track_points.length > 0) {
const map = L.map("statpress-activity-map");
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: \'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>\' }).addTo(map);
const polyline = L.polyline(track_points, {color: "' . esc_js( $activity->color ) . '"}).addTo(map);
map.fitBounds(polyline.getBounds().pad(0.1));
L.marker(track_points[0]).addTo(map).bindPopup("Start");
L.marker(track_points[track_points.length - 1]).addTo(map).bindPopup("Koniec");
}
const chartConfigs = {
elevation: { label: "Wysokość", unit: "m n.p.m.", color: "#8e44ad" },
speed: { label: "Prędkość", unit: "km/h", color: "#2980b9" },
hr: { label: "Tętno", unit: "bpm", color: "#c0392b" },
cadence: { label: "Kadencja", unit: "rpm", color: "#27ae60" }
};
const xAxisConfigs = {
distance: { label: "Dystans (km)", data: profiles.distance },
time: {
label: "Czas", data: profiles.time,
formatter: (s) => s === null ? "" : new Date(s * 1000).toISOString().substr(11, 8)
}
};
function renderChart() {
if (activeChart) activeChart.destroy();
const chartType = document.querySelector(".statpress-chart-tabs .nav-tab-active").getAttribute("href").substring(1);
const xAxisType = document.querySelector(\'input[name="statpress_xaxis"]:checked\').value;
const yData = profiles[chartType], xData = xAxisConfigs[xAxisType].data;
const filteredY = [], filteredX = [];
if(yData) {
for(let i=0; i<yData.length; i++) {
if (yData[i] !== null) {
filteredY.push(yData[i]);
filteredX.push(xData[i]);
}
}
}
const ctx = document.getElementById("statpress-details-chart").getContext("2d");
activeChart = new Chart(ctx, {
type: "line",
data: {
labels: filteredX,
datasets: [{
label: chartConfigs[chartType].label, data: filteredY,
borderColor: chartConfigs[chartType].color, backgroundColor: chartConfigs[chartType].color + "20",
fill: true, pointRadius: 0, tension: 0.1
}]
},
options: {
responsive: true, maintainAspectRatio: false,
scales: {
x: { title: { display: true, text: xAxisConfigs[xAxisType].label }, ticks: { callback: xAxisType === "time" ? xAxisConfigs.time.formatter : (v) => v, maxRotation: 0, autoSkip: true, maxTicksLimit: 10 } },
y: { title: { display: true, text: chartConfigs[chartType].unit } }
},
plugins: { legend: { display: false } },
interaction: { intersect: false, mode: "index" },
}
});
}
document.querySelectorAll(".statpress-chart-tabs .nav-tab").forEach(t => t.addEventListener("click", e => {
e.preventDefault();
document.querySelector(".statpress-chart-tabs .nav-tab-active").classList.remove("nav-tab-active");
e.target.classList.add("nav-tab-active");
renderChart();
}));
document.querySelectorAll(\'input[name="statpress_xaxis"]\').forEach(r => r.addEventListener("change", renderChart));
if (document.querySelector(".statpress-chart-tabs .nav-tab")) renderChart();
';
wp_add_inline_script( 'statpress-details-loader', 'document.addEventListener("DOMContentLoaded", function() {' . $chart_js . '});' );
}
?>
<div class="wrap">
<h1>
Szczegóły treningu: <?php echo esc_html( $activity->title ); ?>
<a href="<?php echo esc_url( add_query_arg( array( 'page' => 'statpress-edit-activity', 'id' => $activity->id ), admin_url( 'admin.php' ) ) ); ?>" class="page-title-action">
Edytuj
</a>
</h1>
<p><a href="<?php echo esc_url( admin_url( 'admin.php?page=statpress-dashboard' ) ); ?>">&larr; Powrót do listy aktywności</a></p>
<div class="postbox" style="margin-top: 20px;">
<div class="postbox-header"><h2 class="hndle">Podsumowanie</h2></div>
<div class="inside">
<div id="statpress-details-container">
<div class="statpress-details-col">
<h3>Główne dane</h3>
<table class="form-table">
<?php $render_row( 'Kategoria', $activity->category_name ); ?>
<?php $render_row( 'Data', $activity->date ); ?>
<?php $render_row( 'Dystans', number_format( $activity->distance, 2, ',', ' ' ), 'km' ); ?>
<?php $render_row( 'Czas trwania', $activity->duration ); ?>
<?php $render_row( 'Spalone kalorie', $activity->calories, 'kcal' ); ?>
<?php $render_row( 'Typ wydarzenia', $activity->event_type_name ); ?>
<?php $render_row( 'Sprzęt', $activity->equipment_name ); ?>
</table>
</div>
<div class="statpress-details-col">
<h3>Dane szczegółowe</h3>
<table class="form-table">
<?php $render_row( 'Średnia prędkość', number_format( $activity->avg_speed, 1, ',', ' ' ), 'km/h' ); ?>
<?php $render_row( 'Maksymalna prędkość', number_format( $activity->max_speed, 1, ',', ' ' ), 'km/h' ); ?>
<?php $render_row( 'Średnie tętno', $activity->avg_heart_rate, 'bpm' ); ?>
<?php $render_row( 'Maksymalne tętno', $activity->max_heart_rate, 'bpm' ); ?>
<?php $render_row( 'Średni rytm', $activity->avg_cadence, 'rpm' ); ?>
<?php $render_row( 'Maksymalny rytm', $activity->max_cadence, 'rpm' ); ?>
<?php $render_row( 'Suma wzniosów', $activity->total_elevation_gain, 'm' ); ?>
<?php $render_row( 'Suma spadków', $activity->total_elevation_loss, 'm' ); ?>
<?php $render_row( 'Minimalna wysokość', $activity->min_altitude, 'm n.p.m.' ); ?>
<?php $render_row( 'Maksymalna wysokość', $activity->max_altitude, 'm n.p.m.' ); ?>
</table>
</div>
</div>
<hr>
<h3>Notatki i linki</h3>
<table class="form-table">
<?php $render_row( 'Komentarz', nl2br( $activity->comment ) ); ?>
<?php if ( ! empty( $activity->strava_url ) ) : ?>
<tr><th scope="row">Strava</th><td><a href="<?php echo esc_url( $activity->strava_url ); ?>" target="_blank" rel="noopener noreferrer">Zobacz aktywność na Strava</a></td></tr>
<?php endif; ?>
<?php if ( ! empty( $activity->gpx_url ) ) : ?>
<tr><th scope="row">Plik GPX</th><td><a href="<?php echo esc_url( $activity->gpx_url ); ?>" target="_blank">Pobierz plik GPX</a></td></tr>
<?php endif; ?>
</table>
<?php if ( $has_gpx_data ) : ?>
<hr>
<h3>Mapa Trasy</h3>
<div id="statpress-activity-map" style="height: 450px; width: 100%; border: 1px solid #ddd; margin-bottom: 20px;"></div>
<?php if ( ! empty( $available_profiles ) ) : ?>
<h3>Wykresy</h3>
<div class="statpress-charts-container">
<div class="statpress-chart-controls">
<nav class="nav-tab-wrapper statpress-chart-tabs">
<?php
$is_first = true;
foreach ( $available_profiles as $key => $label ) :
?>
<a href="#<?php echo esc_attr( $key ); ?>" class="nav-tab <?php
if ( $is_first ) {
echo 'nav-tab-active';
$is_first = false; }
?>
"><?php echo esc_html( $label ); ?></a>
<?php endforeach; ?>
</nav>
<?php if ( $has_time_data ) : ?>
<div class="statpress-xaxis-switcher">
<strong>Oś X:</strong>&nbsp;
<label><input type="radio" name="statpress_xaxis" value="distance" checked> Dystans</label>
&nbsp;
<label><input type="radio" name="statpress_xaxis" value="time"> Czas</label>
</div>
<?php else : ?>
<input type="hidden" name="statpress_xaxis" value="distance" checked>
<?php endif; ?>
</div>
<div style="position: relative; height:250px; width:100%;">
<canvas id="statpress-details-chart"></canvas>
</div>
</div>
<?php endif; ?>
<?php elseif ( ! empty( $activity->gpx_url ) ) : ?>
<hr>
<div class="notice notice-warning inline">
<p>Nie udało się wczytać danych z pliku GPX lub plik jest uszkodzony/pusty. Brak danych do wyświetlenia mapy i wykresów.</p>
</div>
<?php endif; ?>
</div>
</div>
</div>
<?php
}