@extends('layouts.app') @section('title', 'Report e statistiche · FranCoach') @section('content') @php $periodLabels = ['week' => 'Settimana', 'month' => 'Mese', '90_days' => '90 giorni', '6_months' => '6 mesi', 'custom' => 'Personalizzato']; // Prima voce nera (non gialla): come tratto di linea sottile su sfondo bianco // il giallo fluorescente del brand avrebbe un contrasto reale di ~1,3:1. $chartColors = ['#121212', '#2F80ED', '#27AE60', '#9B51E0', '#EB5757', '#F2C94C', '#56CCF2']; $chart = fn (string $type, array $labels, array $datasets) => compact('type', 'labels', 'datasets'); $adherenceChart = $chart('doughnut', ['Completati', 'Saltati'], [['label' => 'Allenamenti', 'data' => [$summary['completed'], $summary['skipped']]]]); $weightChart = $chart('line', collect($measurements['weight']['points'] ?? [])->pluck('date')->map(fn ($date) => \Illuminate\Support\Carbon::parse($date)->format('d/m'))->all(), [['label' => 'Peso (kg)', 'data' => collect($measurements['weight']['points'] ?? [])->pluck('value')->all()]]); $compositionLabels = $measurements['composition']->flatMap(fn ($series) => $series['points']->pluck('date'))->unique()->sort()->values(); $compositionDatasets = $measurements['composition']->values()->map(fn ($series, $index) => ['label' => $series['name'].' ('.$series['unit'].')', 'data' => $compositionLabels->map(fn ($date) => $series['points']->firstWhere('date', $date)['value'] ?? null)->all(), 'borderColor' => $chartColors[$index % count($chartColors)]])->all(); $circumferenceLabels = $measurements['circumferences']->flatMap(fn ($series) => $series['points']->pluck('date'))->unique()->sort()->values(); $circumferenceDatasets = $measurements['circumferences']->values()->map(fn ($series, $index) => ['label' => $series['name'], 'data' => $circumferenceLabels->map(fn ($date) => $series['points']->firstWhere('date', $date)['value'] ?? null)->all(), 'borderColor' => $chartColors[$index % count($chartColors)]])->all(); $charts = [ ['title' => 'Aderenza', 'description' => 'Allenamenti completati e saltati.', 'config' => $adherenceChart, 'empty' => ($summary['completed'] + $summary['skipped']) === 0], ['title' => 'Andamento peso', 'description' => 'Peso registrato nel periodo.', 'config' => $weightChart, 'empty' => empty($measurements['weight']['points'] ?? [])], ['title' => 'Composizione corporea', 'description' => 'Massa grassa, magra e muscolare.', 'config' => $chart('line', $compositionLabels->map(fn ($date) => \Illuminate\Support\Carbon::parse($date)->format('d/m'))->all(), $compositionDatasets), 'empty' => empty($compositionDatasets)], ['title' => 'Volume per gruppo muscolare', 'description' => 'Volume complessivo in chilogrammi.', 'config' => $chart('bar', $volumeByMuscle->pluck('label')->all(), [['label' => 'Volume (kg)', 'data' => $volumeByMuscle->pluck('value')->map(fn ($value) => round((float) $value, 1))->all()]]), 'empty' => $volumeByMuscle->isEmpty()], ['title' => 'Carichi', 'description' => 'Carico medio e massimo per data.', 'config' => $chart('line', $loadTrend->pluck('date')->map(fn ($date) => \Illuminate\Support\Carbon::parse($date)->format('d/m'))->all(), [['label' => 'Carico medio', 'data' => $loadTrend->pluck('average')->map(fn ($value) => round((float) $value, 1))->all()], ['label' => 'Carico massimo', 'data' => $loadTrend->pluck('maximum')->map(fn ($value) => round((float) $value, 1))->all(), 'borderColor' => '#2F80ED']]), 'empty' => $loadTrend->isEmpty()], ['title' => 'Allenamenti', 'description' => 'Completati e saltati nel tempo.', 'config' => $chart('bar', $trainingTrend->pluck('date')->map(fn ($date) => \Illuminate\Support\Carbon::parse($date)->format('d/m'))->all(), [['label' => 'Completati', 'data' => $trainingTrend->pluck('completed')->all()], ['label' => 'Saltati', 'data' => $trainingTrend->pluck('skipped')->all(), 'backgroundColor' => '#EB5757']]), 'empty' => $trainingTrend->isEmpty()], ['title' => 'Circonferenze', 'description' => 'Variazione delle misure corporee.', 'config' => $chart('line', $circumferenceLabels->map(fn ($date) => \Illuminate\Support\Carbon::parse($date)->format('d/m'))->all(), $circumferenceDatasets), 'empty' => empty($circumferenceDatasets)], ]; @endphp

Report di {{ $athlete->displayName() }}

{{ $from->format('d/m/Y') }} - {{ $to->format('d/m/Y') }}

CSV

Periodo

Azzera
@foreach($charts as $item)

{{ $item['title'] }}

{{ $item['description'] }}

@if($item['empty']) @else @endif
@endforeach

Variazioni corporee

@forelse($measurements['series'] as $series)@empty@endforelse
MisuraInizialeUltimaVariazione
{{ $series['name'] }}{{ $series['first'] }} {{ $series['unit'] }}{{ $series['last'] }} {{ $series['unit'] }}{{ $series['change'] !== null ? ($series['change'] > 0 ? '+' : '').$series['change'].' '.$series['unit'] : '—' }}
Nessuna misurazione.

Record personali

@forelse($personalRecords as $record)@empty@endforelse
EsercizioCarico massimo
{{ $record->label ?: 'Esercizio' }}{{ number_format((float) $record->value, 1, ',', '.') }} kg
Nessun record nel periodo.

Frequenza messaggi

Messaggi totali
{{ $messages['summary']['total'] }}
Dall’atleta
{{ $messages['summary']['from_athlete'] }}
Media settimanale
{{ $messages['summary']['average_per_week'] }}

Note rilevanti

@forelse($notes as $note)
{{ $note['source'] }}
{{ $note['text'] }}
@empty
Nessuna nota nel periodo.
@endforelse

Esporta PDF

@csrf
@endsection