Kaynağa Gözat

chart funzionanti

FabioFratini 8 ay önce
ebeveyn
işleme
fb920af7a9

+ 164 - 37
app/Http/Livewire/Reports.php

@@ -138,8 +138,13 @@ class Reports extends Component
 
     public function getMonthlyTotals()
     {
+        Log::info('=== getMonthlyTotals called ===');
+        Log::info('Current seasonFilter: ' . $this->seasonFilter);
+
         $dateRange = $this->getSeasonDateRange($this->seasonFilter);
 
+        Log::info('Date range start: ' . $dateRange['start']);
+        Log::info('Date range end: ' . $dateRange['end']);
         // September to August order
         $monthOrder = [9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8];
         $monthNames = ['Set', 'Ott', 'Nov', 'Dic', 'Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago'];
@@ -181,6 +186,9 @@ class Reports extends Component
             }
         }
 
+        Log::info('Income data: ' . json_encode($incomeData));
+        Log::info('Expense data: ' . json_encode($expenseData));
+
         return [
             'labels' => $monthNames,
             'datasets' => [
@@ -295,14 +303,39 @@ class Reports extends Component
 
         $courses = Course::with(['level', 'type', 'frequency'])
             ->where('active', true)
-            ->where(function($query) use ($seasonYears) {
-                // Match courses that contain either year of the season
-                $query->where('year', 'like', '%' . $seasonYears['start_year'] . '%')
-                      ->orWhere('year', 'like', '%' . $seasonYears['end_year'] . '%')
-                      ->orWhere('year', 'like', '%' . $this->seasonFilter . '%');
+            ->where(function ($query) use ($seasonYears) {
+                // Match courses that belong to the exact season
+                $query->where('year', $this->seasonFilter)
+                    ->orWhere('year', 'like', '%' . $seasonYears['start_year'] . '-' . $seasonYears['end_year'] . '%')
+                    ->orWhere('year', 'like', '%' . $seasonYears['start_year'] . '%')
+                    ->orWhere('year', 'like', '%' . $seasonYears['end_year'] . '%');
             })
             ->orderBy('name')
             ->get()
+            ->filter(function ($course) use ($seasonYears) {
+                // Additional filtering to ensure course belongs to the season
+                $courseYear = $course->year;
+
+                // Check if course year matches the season format (e.g., "2024-2025")
+                if ($courseYear === $this->seasonFilter) {
+                    return true;
+                }
+
+                // Check if course year contains the season years
+                if (
+                    str_contains($courseYear, $seasonYears['start_year']) &&
+                    str_contains($courseYear, $seasonYears['end_year'])
+                ) {
+                    return true;
+                }
+
+                // Check if course year is exactly one of the season years
+                if ($courseYear == $seasonYears['start_year'] || $courseYear == $seasonYears['end_year']) {
+                    return true;
+                }
+
+                return false;
+            })
             ->map(function ($course) {
                 $type = null;
                 if (!empty($course->course_type_id)) {
@@ -323,21 +356,60 @@ class Reports extends Component
                     'frequency_name' => $frequencyName,
                     'year' => $year
                 ];
-            })->toArray();
+            })->values()->toArray();
 
         Log::info('Found ' . count($courses) . ' courses for season ' . $this->seasonFilter);
 
         return $courses;
     }
 
-public function updatedSelectedCourse()
-{
-    Log::info('updatedSelectedCourse called with: ' . $this->selectedCourse);
-    if ($this->selectedCourse) {
-        $this->emit('courseSelected', $this->selectedCourse);
-        Log::info('Event emitted with course ID: ' . $this->selectedCourse);
+    public function getMonthlyTotalsForSeason($season)
+    {
+        $originalSeason = $this->seasonFilter;
+        $this->seasonFilter = $season;
+
+        $result = $this->getMonthlyTotals();
+
+        $this->seasonFilter = $originalSeason;
+        return $result;
+    }
+
+    /**
+     * Get top causals for a specific season
+     */
+    public function getTopCausalsByAmountForSeason($season, $limit = 10)
+    {
+        $originalSeason = $this->seasonFilter;
+        $this->seasonFilter = $season;
+
+        $result = $this->getTopCausalsByAmount($limit);
+
+        $this->seasonFilter = $originalSeason;
+        return $result;
+    }
+
+    /**
+     * Get tesserati data for a specific season
+     */
+    public function getTesseratiDataForSeason($season)
+    {
+        $originalSeason = $this->seasonFilter;
+        $this->seasonFilter = $season;
+
+        $result = $this->getTesseratiData();
+
+        $this->seasonFilter = $originalSeason;
+        return $result;
+    }
+
+    public function updatedSelectedCourse()
+    {
+        Log::info('updatedSelectedCourse called with: ' . $this->selectedCourse);
+        if ($this->selectedCourse) {
+            $this->emit('courseSelected', $this->selectedCourse);
+            Log::info('Event emitted with course ID: ' . $this->selectedCourse);
+        }
     }
-}
     public function getCourseData($courseId)
     {
         $this->selectedCourse = $courseId;
@@ -351,14 +423,27 @@ public function updatedSelectedCourse()
         if (!$courseId) {
             return [
                 'labels' => [],
-                'datasets' => []
+                'datasets' => [],
+                'tableData' => [],
+                'isEmpty' => true,
+                'message' => 'Seleziona un corso per visualizzare i dati'
             ];
         }
+
         $monthOrder = [9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8];
         $monthNames = [
-            9 => 'Set', 10 => 'Ott', 11 => 'Nov', 12 => 'Dic',
-            1 => 'Gen', 2 => 'Feb', 3 => 'Mar', 4 => 'Apr',
-            5 => 'Mag', 6 => 'Giu', 7 => 'Lug', 8 => 'Ago'
+            9 => 'Set',
+            10 => 'Ott',
+            11 => 'Nov',
+            12 => 'Dic',
+            1 => 'Gen',
+            2 => 'Feb',
+            3 => 'Mar',
+            4 => 'Apr',
+            5 => 'Mag',
+            6 => 'Giu',
+            7 => 'Lug',
+            8 => 'Ago'
         ];
 
         $monthlyData = [];
@@ -374,6 +459,19 @@ public function updatedSelectedCourse()
             ->with('member')
             ->get();
 
+        // Check if there are any member courses
+        if ($memberCourses->isEmpty()) {
+            return [
+                'labels' => [],
+                'datasets' => [],
+                'tableData' => [],
+                'isEmpty' => true,
+                'message' => 'Nessun dato disponibile per questo corso nella stagione ' . $this->seasonFilter
+            ];
+        }
+
+        $hasData = false;
+
         foreach ($memberCourses as $memberCourse) {
             $price = (float)($memberCourse->price ?? 0);
 
@@ -387,30 +485,54 @@ public function updatedSelectedCourse()
 
                         if ($month !== null && isset($monthlyData[$month])) {
                             $monthlyData[$month]['total'] += $price;
+                            $monthlyData[$month]['participants']++;
+                            $hasData = true;
 
                             if ($status === 1) {
                                 $monthlyData[$month]['earned'] += $price;
                             }
-
-                            $monthlyData[$month]['participants']++;
                         }
                     }
                 }
             }
         }
 
+        // Check if we actually have any data
+        if (!$hasData) {
+            return [
+                'labels' => [],
+                'datasets' => [],
+                'tableData' => [],
+                'isEmpty' => true,
+                'message' => 'Nessun pagamento registrato per questo corso nella stagione ' . $this->seasonFilter
+            ];
+        }
+
         $labels = [];
         $earnedData = [];
         $totalData = [];
         $participantData = [];
-        $missingData = [];
+        $tableData = [];
 
         foreach ($monthOrder as $month) {
+            $earned = round($monthlyData[$month]['earned'], 2);
+            $total = round($monthlyData[$month]['total'], 2);
+            $delta = $total - $earned;
+            $participants = $monthlyData[$month]['participants'];
+
             $labels[] = $monthNames[$month];
-            $earnedData[] = round($monthlyData[$month]['earned'], 2);
-            $totalData[] = round($monthlyData[$month]['total'], 2);
-            $participantData[] = $monthlyData[$month]['participants'];
-            $missingData[] = round($monthlyData[$month]['total'] - $monthlyData[$month]['earned'], 2);
+            $earnedData[] = $earned;
+            $totalData[] = $total;
+            $participantData[] = $participants;
+
+            $tableData[] = [
+                'month' => $monthNames[$month],
+                'participants' => $participants,
+                'earned' => $earned,
+                'total' => $total,
+                'delta' => $delta,
+                'percentage' => $total > 0 ? round(($earned / $total) * 100, 1) : 0
+            ];
         }
 
         return [
@@ -418,26 +540,34 @@ public function updatedSelectedCourse()
             'datasets' => [
                 [
                     'label' => 'Pagamenti Effettuati',
-                    'backgroundColor' => 'rgba(0, 184, 148, 1)',
+                    'backgroundColor' => 'rgba(16, 185, 129, 0.8)',
+                    'borderColor' => 'rgba(16, 185, 129, 1)',
+                    'borderWidth' => 0,
+                    'borderRadius' => 8,
+                    'borderSkipped' => false,
                     'data' => $earnedData,
                     'type' => 'bar',
-                    'order' => 3
+                    'order' => 2
                 ],
                 [
                     'label' => 'Pagamenti Attesi',
                     'backgroundColor' => 'transparent',
-                    'borderColor' => 'rgba(48, 51, 107, 1)',
+                    'borderColor' => 'rgba(59, 130, 246, 1)',
                     'borderWidth' => 3,
-                    'pointBackgroundColor' => 'rgba(48, 51, 107, 1)',
-                    'pointRadius' => 5,
+                    'pointBackgroundColor' => 'rgba(59, 130, 246, 1)',
+                    'pointBorderColor' => '#ffffff',
+                    'pointBorderWidth' => 3,
+                    'pointRadius' => 7,
+                    'pointHoverRadius' => 9,
                     'data' => $totalData,
                     'type' => 'line',
-                    'tension' => 0.2,
-                    'order' => 2,
-                    'participants' => $participantData,
-                    'missing' => $missingData
+                    'tension' => 0.3,
+                    'order' => 1,
+                    'participantData' => $participantData
                 ]
-            ]
+            ],
+            'tableData' => $tableData,
+            'isEmpty' => false
         ];
     }
 
@@ -467,12 +597,9 @@ public function updatedSelectedCourse()
             $expireYear = date('Y', strtotime($card->expire_date));
             $expireMonth = date('n', strtotime($card->expire_date));
 
-            // Determine which season this belongs to
             if ($expireMonth >= 9) {
-                // September-December: belongs to season starting that year
                 $seasonPeriod = $expireYear . '-' . ($expireYear + 1);
             } else {
-                // January-August: belongs to season starting previous year
                 $seasonPeriod = ($expireYear - 1) . '-' . $expireYear;
             }
 

+ 207 - 0
public/css/chart-reports.css

@@ -498,3 +498,210 @@
         gap: 1rem;
     }
 }
+
+.modern-course-card {
+    background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
+    border: 1px solid #e2e8f0;
+    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+}
+
+.modern-select {
+    background: white;
+    border: 2px solid #e2e8f0;
+    border-radius: 12px;
+    padding: 12px 16px;
+    font-weight: 500;
+    transition: all 0.3s ease;
+}
+
+.modern-select:focus {
+    border-color: #3b82f6;
+    box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
+    outline: none;
+}
+
+.modern-chart-layout {
+    display: grid;
+    grid-template-columns: 280px 1fr;
+    gap: 24px;
+    align-items: start;
+    margin-top: 20px;
+}
+
+.course-delta-table {
+    background: rgb(248, 249, 250);
+    border-radius: 16px;
+    border: 1px solid #e5e7eb;
+    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
+}
+
+.course-table-header {
+    background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
+    padding: 16px 20px;
+    color: white;
+}
+
+.course-table-header h4 {
+    margin: 0;
+    font-size: 1rem;
+    font-weight: 600;
+}
+
+.course-table {
+    max-height: 500px;
+    overflow-y: auto;
+}
+
+.course-table .table-header {
+    display: grid;
+    grid-template-columns: 1fr 40px 80px 50px;
+    background: #f8fafc;
+    padding: 12px 16px;
+    font-weight: 600;
+    font-size: 0.875rem;
+    color: #374151;
+    border-bottom: 1px solid #e5e7eb;
+}
+
+.course-table .table-row {
+    display: grid;
+    grid-template-columns: 1fr 40px 80px 50px;
+    padding: 12px 16px;
+    border-bottom: 1px solid #f3f4f6;
+    transition: background-color 0.2s;
+}
+
+.course-table .table-row:hover {
+    background: #f9fafb;
+}
+
+.course-table .table-row:last-child {
+    border-bottom: none;
+}
+
+.course-table .table-cell {
+    font-size: 0.875rem;
+    display: flex;
+    align-items: center;
+}
+
+.course-table .table-cell.month {
+    font-weight: 600;
+    color: #111827;
+}
+
+.course-table .table-cell.participants {
+    justify-content: center;
+    color: #6b7280;
+    font-weight: 500;
+}
+
+.course-table .table-cell.delta {
+    justify-content: flex-end;
+    font-weight: 600;
+}
+
+.course-table .table-cell.delta.positive {
+    color: #059669;
+}
+
+.course-table .table-cell.delta.negative {
+    color: #dc2626;
+}
+
+.course-table .table-cell.delta.neutral {
+    color: #6b7280;
+}
+
+.course-table .table-cell.percentage {
+    justify-content: center;
+    font-weight: 600;
+    font-size: 0.8rem;
+}
+
+.course-table .table-cell.percentage.good {
+    color: #059669;
+}
+
+.course-table .table-cell.percentage.warning {
+    color: #d97706;
+}
+
+.course-table .table-cell.percentage.bad {
+    color: #dc2626;
+}
+
+.modern-chart-container {
+    background: white;
+    border-radius: 16px;
+    border: 1px solid #e5e7eb;
+    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
+    padding: 20px;
+}
+
+.chart-placeholder {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    min-height: 400px;
+    background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
+    border-radius: 16px;
+    border: 2px dashed #cbd5e1;
+    margin-top: 20px;
+}
+
+.placeholder-content {
+    text-align: center;
+    color: #64748b;
+}
+
+.placeholder-icon {
+    width: 48px;
+    height: 48px;
+    margin: 0 auto 16px;
+    opacity: 0.5;
+}
+
+.placeholder-content p {
+    font-size: 1.1rem;
+    font-weight: 500;
+    margin: 0;
+}
+
+@media (max-width: 1024px) {
+    .modern-chart-layout {
+        grid-template-columns: 1fr;
+        gap: 16px;
+    }
+
+    .course-delta-table {
+        order: 2;
+    }
+
+    .modern-chart-container {
+        order: 1;
+    }
+}
+
+
+.modern-chart-container {
+    background: white;
+    border-radius: 16px;
+    border: 1px solid #e5e7eb;
+    box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
+    padding: 20px;
+    height: 500px;
+}
+
+.modern-chart-container canvas {
+    height: 460px !important;
+}
+
+.modern-chart-layout {
+    display: grid;
+    grid-template-columns: 280px 1fr;
+    gap: 24px;
+    align-items: start;
+    margin-top: 20px;
+    min-height: 500px;
+}

+ 304 - 86
resources/views/livewire/reports.blade.php

@@ -86,7 +86,7 @@
         </div>
 
         <div class="chart-row">
-            <div class="chart-card">
+            <div class="chart-card modern-course-card">
                 <div class="chart-header">
                     <h3 class="chart-title">Analisi Corsi</h3>
                 </div>
@@ -94,36 +94,40 @@
                     <div class="course-controls">
                         <div class="control-group">
                             <label>Seleziona Corso ({{ $seasonFilter }}):</label>
-                            <select class="form-select" wire:model.live="selectedCourse">
+                            <select class="form-select modern-select" wire:model.live="selectedCourse">
                                 <option value="">Seleziona un Corso</option>
                                 @foreach($this->getCoursesForSelect() as $course)
                                     <option value="{{ $course['id'] }}">{{ $course['full_name'] }}</option>
                                 @endforeach
                             </select>
                         </div>
-                        <div class="legend-container">
-                            <div class="legend-item">
-                                <div class="legend-color" style="background: rgba(0, 184, 148, 1);"></div>
-                                <span>Pagamenti Effettuati</span>
-                            </div>
-                            <div class="legend-item">
-                                <div class="legend-color" style="background: rgba(48, 51, 107, 1);"></div>
-                                <span>Pagamenti Attesi</span>
-                            </div>
-                        </div>
                     </div>
 
                     @if($selectedCourse)
                         <div wire:ignore wire:key="course-chart-{{ $seasonFilter }}-{{ $selectedCourse }}">
-                            <div class="chart-container">
-                                <canvas
-                                    id="courses-chart-{{ str_replace('-', '', $seasonFilter) }}-{{ $selectedCourse }}"></canvas>
+                            <div class="modern-chart-layout">
+                                <!-- Delta Table on the left -->
+                                <div class="course-delta-table"
+                                    id="course-delta-table-{{ str_replace('-', '', $seasonFilter) }}-{{ $selectedCourse }}">
+                                    <!-- Table will be populated by JavaScript -->
+                                </div>
+
+                                <!-- Chart on the right -->
+                                <div class="modern-chart-container">
+                                    <canvas
+                                        id="courses-chart-{{ str_replace('-', '', $seasonFilter) }}-{{ $selectedCourse }}"></canvas>
+                                </div>
                             </div>
                         </div>
                     @else
-                        <div class="chart-container"
-                            style="display: flex; align-items: center; justify-content: center; min-height: 400px; color: var(--secondary-color);">
-                            <p style="font-size: 1.1rem;">Seleziona un corso per visualizzare il grafico</p>
+                        <div class="chart-placeholder">
+                            <div style="text-align: center;">
+                                <div style="font-size: 3rem; margin-bottom: 1rem; opacity: 0.3;">📊</div>
+                                <p style="font-size: 1.25rem; font-weight: 600; margin: 0;">Seleziona un corso per
+                                    visualizzare il grafico</p>
+                                <p style="font-size: 1rem; opacity: 0.7; margin-top: 0.5rem;">Usa il menu a tendina sopra
+                                    per scegliere un corso</p>
+                            </div>
                         </div>
                     @endif
                 </div>
@@ -133,7 +137,6 @@
 
     <!-- Single JavaScript section -->
     <script>
-        // Global chart manager
         window.ReportsChartManager = window.ReportsChartManager || {
             charts: {},
             currentSeason: null,
@@ -151,40 +154,66 @@
                 });
             },
 
+            // NEW: Method to destroy season-specific charts
+            destroySeasonCharts: function (oldSeasonKey) {
+                const chartsToDestroy = Object.keys(this.charts).filter(chartId =>
+                    chartId.includes(oldSeasonKey)
+                );
+                chartsToDestroy.forEach(chartId => this.destroyChart(chartId));
+            },
+
+            // Replace your updateMainCharts method with this version that uses fixed canvas IDs:
             updateMainCharts: function () {
-                const seasonFilter = '{{ $seasonFilter }}';
-                const seasonKey = '{{ str_replace('-', '', $seasonFilter) }}';
+                console.log('=== updateMainCharts called ===');
 
-                // Only update if season changed
-                if (this.currentSeason === seasonFilter) {
-                    return;
-                }
+                const seasonFilter = @this.get('seasonFilter');
 
-                this.currentSeason = seasonFilter;
+                // Update titles
+                const monthlyTitle = document.getElementById('monthly-season-title');
+                const causalsTitle = document.getElementById('causals-season-title');
+                if (monthlyTitle) {
+                    monthlyTitle.textContent = seasonFilter;
+                }
+                if (causalsTitle) {
+                    causalsTitle.textContent = seasonFilter;
+                }
 
-                // Get fresh data
-                const monthlyData = @json($this->getMonthlyTotals());
-                const causalsData = @json($this->getTopCausalsByAmount());
-                const membersData = @json($this->getTesseratiData());
+                // Use the original canvas IDs from the blade template
+                const originalSeasonKey = '{{ str_replace('-', '', $seasonFilter) }}';
+                console.log('Using original season key for canvas IDs:', originalSeasonKey);
 
-                // Update titles
-                document.getElementById('monthly-season-title').textContent = seasonFilter;
-                document.getElementById('causals-season-title').textContent = seasonFilter;
+                // Get fresh data and update charts
+                @this.call('getMonthlyTotals').then(monthlyData => {
+                    console.log('Got monthly data:', monthlyData);
+                    this.createMonthlyChart(originalSeasonKey, monthlyData);
+                    this.updateMonthlyTable(monthlyData);
+                });
 
-                // Create/update charts
-                this.createMonthlyChart(seasonKey, monthlyData);
-                this.createCausalsChart(seasonKey, causalsData);
-                this.createMembersChart(seasonKey, membersData);
+                @this.call('getTopCausalsByAmount').then(causalsData => {
+                    console.log('Got causals data:', causalsData);
+                    this.createCausalsChart(originalSeasonKey, causalsData);
+                });
 
-                // Update tables
-                this.updateMonthlyTable(monthlyData);
-                this.updateMembersTable(membersData);
+                @this.call('getTesseratiData').then(membersData => {
+                    console.log('Got members data:', membersData);
+                    this.createMembersChart(originalSeasonKey, membersData);
+                    this.updateMembersTable(membersData);
+                });
+            },
+            // Add this new method to force chart updates
+            forceUpdateCharts: function () {
+                console.log('Force updating charts...');
+                this.currentSeason = null; // Reset to force update
+                this.updateMainCharts();
             },
 
             createMonthlyChart: function (seasonKey, monthlyData) {
                 const chartId = `monthly-chart-${seasonKey}`;
                 const canvas = document.getElementById(chartId);
-                if (!canvas) return;
+                if (!canvas) {
+                    console.error('Canvas not found for ID:', chartId);
+                    return;
+                }
 
                 this.destroyChart(chartId);
 
@@ -422,7 +451,7 @@
                 let tableHtml = `
                     <div class="monthly-table">
                         <div class="table-header">
-                            <div class="table-cell">Mese</div>
+                            <div class="table-cell month">Mese</div>
                             <div class="table-cell">Entrate</div>
                             <div class="table-cell">Uscite</div>
                             <div class="table-cell">Delta</div>
@@ -457,9 +486,6 @@
                 const memberCounts = membersData.datasets[0].data;
 
                 let tableHtml = `
-                    <h4 style="margin-bottom: 1rem; font-size: 1rem; font-weight: 600; color: var(--dark-color);">
-                        Riepilogo Tesserati
-                    </h4>
                     <div class="members-table">
                         <div class="table-header">
                             <div class="table-cell">Stagione</div>
@@ -593,50 +619,226 @@
                     }
                 });
             },
-           createCourseChartWithValue: function (selectedCourseValue) {
-    console.log('Creating course chart with value:', selectedCourseValue);
-    const seasonFilter = '{{ $seasonFilter }}';
-    const seasonKey = '{{ str_replace('-', '', $seasonFilter) }}';
-
-    const chartId = `courses-chart-${seasonKey}-${selectedCourseValue}`;
-    const canvas = document.getElementById(chartId);
-    if (!canvas) {
-        console.log('Canvas not found for chart ID:', chartId);
-        return;
-    }
-
-    this.destroyChart(chartId);
-
-    // Call Livewire method to get fresh data
-    @this.call('getCourseData', selectedCourseValue).then(courseData => {
-        console.log('Received course data:', courseData);
-
-        if (!courseData || !courseData.labels || courseData.labels.length === 0) {
-            console.log('No data available for chart');
-            return;
-        }
-
-        const ctx = canvas.getContext('2d');
-        this.charts[chartId] = new Chart(ctx, {
-            type: 'bar',
-            data: {
-                labels: courseData.labels,
-                datasets: courseData.datasets
-            },
-            options: {
-                responsive: true,
-                maintainAspectRatio: false,
-                scales: {
-                    y: {
-                        beginAtZero: true
+            createCourseChartWithValue: function (selectedCourseValue) {
+                console.log('Creating modern course chart with value:', selectedCourseValue);
+                const seasonFilter = '{{ $seasonFilter }}';
+                const seasonKey = '{{ str_replace('-', '', $seasonFilter) }}';
+
+                const chartId = `courses-chart-${seasonKey}-${selectedCourseValue}`;
+                const tableId = `course-delta-table-${seasonKey}-${selectedCourseValue}`;
+                const canvas = document.getElementById(chartId);
+                const tableContainer = document.getElementById(tableId);
+
+                if (!canvas) {
+                    console.log('Canvas not found for chart ID:', chartId);
+                    return;
+                }
+
+                this.destroyChart(chartId);
+
+                // Call Livewire method to get fresh data
+                @this.call('getCourseData', selectedCourseValue).then(courseData => {
+                    console.log('Received course data:', courseData);
+
+                    if (!courseData || !courseData.labels || courseData.labels.length === 0) {
+                        console.log('No data available for chart');
+                        return;
                     }
+
+                    // Update the delta table
+                    this.updateCourseTable(tableContainer, courseData.tableData);
+
+                    // Store participant data for tooltip
+                    const participantData = courseData.datasets.find(d => d.participantData)?.participantData || [];
+
+                    const ctx = canvas.getContext('2d');
+
+                    // Create gradients
+                    const earnedGradient = ctx.createLinearGradient(0, 0, 0, 400);
+                    earnedGradient.addColorStop(0, 'rgba(16, 185, 129, 0.9)');
+                    earnedGradient.addColorStop(1, 'rgba(16, 185, 129, 0.3)');
+
+                    this.charts[chartId] = new Chart(ctx, {
+                        type: 'bar',
+                        data: {
+                            labels: courseData.labels,
+                            datasets: courseData.datasets.map(dataset => {
+                                if (dataset.type === 'line') {
+                                    return {
+                                        ...dataset,
+                                        type: 'line',
+                                        fill: false,
+                                        backgroundColor: 'transparent'
+                                    };
+                                } else {
+                                    return {
+                                        ...dataset,
+                                        backgroundColor: earnedGradient
+                                    };
+                                }
+                            })
+                        },
+                        options: {
+                            responsive: true,
+                            maintainAspectRatio: false, // This allows the chart to use full container height
+                            interaction: {
+                                mode: 'index',
+                                intersect: false,
+                            },
+                            layout: {
+                                padding: {
+                                    top: 20,
+                                    right: 20,
+                                    bottom: 20,
+                                    left: 10
+                                }
+                            },
+                            scales: {
+                                x: {
+                                    grid: {
+                                        display: false
+                                    },
+                                    ticks: {
+                                        font: {
+                                            weight: '600',
+                                            size: 13 // Slightly larger font for better visibility
+                                        },
+                                        color: '#6b7280'
+                                    },
+                                    border: {
+                                        display: false
+                                    }
+                                },
+                                y: {
+                                    beginAtZero: true,
+                                    grid: {
+                                        color: 'rgba(156, 163, 175, 0.15)',
+                                        borderDash: [3, 3]
+                                    },
+                                    border: {
+                                        display: false
+                                    },
+                                    ticks: {
+                                        font: {
+                                            size: 12, // Larger font for better visibility
+                                            weight: '500'
+                                        },
+                                        color: '#6b7280',
+                                        callback: function (value) {
+                                            return '€' + new Intl.NumberFormat('it-IT', {
+                                                minimumFractionDigits: 0,
+                                                maximumFractionDigits: 0
+                                            }).format(value);
+                                        }
+                                    }
+                                }
+                            },
+                            plugins: {
+                                legend: {
+                                    display: false
+                                },
+                                tooltip: {
+                                    backgroundColor: 'rgba(255, 255, 255, 0.98)',
+                                    titleColor: '#111827',
+                                    bodyColor: '#374151',
+                                    borderColor: 'rgba(229, 231, 235, 0.8)',
+                                    borderWidth: 1,
+                                    cornerRadius: 12,
+                                    titleFont: {
+                                        weight: 'bold',
+                                        size: 15 // Larger tooltip font
+                                    },
+                                    bodyFont: {
+                                        size: 14,
+                                        weight: '500'
+                                    },
+                                    padding: 16,
+                                    boxPadding: 8,
+                                    usePointStyle: true,
+                                    displayColors: true,
+                                    callbacks: {
+                                        title: function (context) {
+                                            return context[0].label;
+                                        },
+                                        label: function (context) {
+                                            let label = context.dataset.label + ': €' +
+                                                new Intl.NumberFormat('it-IT').format(context.parsed.y);
+
+                                            if (context.dataset.label === 'Pagamenti Attesi' && participantData[context.dataIndex]) {
+                                                label += '\n👥 Partecipanti: ' + participantData[context.dataIndex];
+                                            }
+
+                                            return label;
+                                        }
+                                    }
+                                }
+                            },
+                            animation: {
+                                duration: 1500,
+                                easing: 'easeOutCubic'
+                            },
+                            elements: {
+                                bar: {
+                                    borderRadius: {
+                                        topLeft: 8,
+                                        topRight: 8,
+                                        bottomLeft: 0,
+                                        bottomRight: 0
+                                    }
+                                },
+                                line: {
+                                    borderCapStyle: 'round',
+                                    borderJoinStyle: 'round'
+                                },
+                                point: {
+                                    hoverBorderWidth: 4,
+                                    borderWidth: 3
+                                }
+                            }
+                        }
+                    });
+                }).catch(error => {
+                    console.error('Error calling getCourseData:', error);
+                });
+            },
+
+            updateCourseTable: function (container, tableData) {
+                if (!container || !tableData) return;
+
+                let tableHtml = `
+        <div class="course-table">
+            <div class="table-header">
+                <div class="table-cell month">Mese</div>
+                <div class="table-cell participants">👥</div>
+                <div class="table-cell delta">Mancanti</div>
+                <div class="table-cell percentage">%</div>
+            </div>
+    `;
+
+                tableData.forEach(row => {
+                    const deltaClass = row.delta > 0 ? 'negative' : (row.delta === 0 ? 'neutral' : 'positive');
+                    const percentageClass = row.percentage >= 80 ? 'good' : (row.percentage >= 50 ? 'warning' : 'bad');
+
+                    tableHtml += `
+            <div class="table-row">
+                <div class="table-cell month">${row.month}</div>
+                <div class="table-cell participants">${row.participants}</div>
+                <div class="table-cell delta ${deltaClass}">€${new Intl.NumberFormat('it-IT').format(Math.abs(row.delta))}</div>
+                <div class="table-cell percentage ${percentageClass}">${row.percentage}%</div>
+            </div>
+        `;
+                });
+
+                tableHtml += '</div>';
+                container.innerHTML = tableHtml;
+            },
+            updateCourseChart: function () {
+                if (this.selectedCourse) {
+                    const seasonFilter = @json($seasonFilter);
+                    const seasonKey = seasonFilter.replace('-', '');
+                    this.createCourseChartWithValue(this.selectedCourse);
                 }
             }
-        });
-    }).catch(error => {
-        console.error('Error calling getCourseData:', error);
-    });
-},
         };
 
         document.addEventListener('DOMContentLoaded', function () {
@@ -650,6 +852,14 @@
                 window.ReportsChartManager.updateMainCharts();
             }, 100);
         });
+
+        document.addEventListener('livewire:updated', function (event) {
+            console.log('Livewire updated, waiting for component to fully update...');
+            setTimeout(() => {
+                console.log('Now updating charts after delay');
+                window.ReportsChartManager.forceUpdateCharts();
+            }, 800); // Increased delay to 800ms
+        });
         document.addEventListener('livewire:load', function () {
             Livewire.on('courseSelected', (courseId) => {
                 console.log('Course selected event received:', courseId);
@@ -657,6 +867,14 @@
                     window.ReportsChartManager.createCourseChartWithValue(courseId);
                 }, 200);
             });
+
+            // Listen for the chartsUpdated event from your updateCharts method
+            Livewire.on('chartsUpdated', () => {
+                console.log('Charts updated event received from Livewire');
+                setTimeout(() => {
+                    window.ReportsChartManager.forceUpdateCharts();
+                }, 200);
+            });
         });
     </script>
 </div>