|
|
@@ -114,7 +114,6 @@
|
|
|
<div class="modern-chart-layout">
|
|
|
<div class="course-delta-table" id="course-delta-table-{{ str_replace('-', '', $seasonFilter) }}-{{ $selectedCourse }}">
|
|
|
</div>
|
|
|
-
|
|
|
<div class="modern-chart-container">
|
|
|
<canvas id="courses-chart-{{ str_replace('-', '', $seasonFilter) }}-{{ $selectedCourse }}"></canvas>
|
|
|
</div>
|
|
|
@@ -691,9 +690,9 @@
|
|
|
|
|
|
createCourseChart: function () {
|
|
|
console.log('Creating course chart...');
|
|
|
- const seasonFilter = '{{ $seasonFilter }}';
|
|
|
- const selectedCourse = '{{ $selectedCourse ?? '' }}';
|
|
|
- const seasonKey = '{{ str_replace('-', '', $seasonFilter) }}';
|
|
|
+ const seasonFilter = @this.seasonFilter;
|
|
|
+ const selectedCourse = @this.selectedCourse ?? '';
|
|
|
+ const seasonKey = seasonFilter.replace('-', '');
|
|
|
console.log('Selected course:', selectedCourse, 'for season:', seasonFilter);
|
|
|
|
|
|
if (!selectedCourse || selectedCourse.trim() === '') {
|
|
|
@@ -784,8 +783,8 @@
|
|
|
},
|
|
|
createCourseChartWithValue: function (selectedCourseValue) {
|
|
|
console.log('Creating modern course chart with value:', selectedCourseValue);
|
|
|
- const seasonFilter = '{{ $seasonFilter }}';
|
|
|
- const seasonKey = '{{ str_replace('-', '', $seasonFilter) }}';
|
|
|
+ const seasonFilter = @this.seasonFilter;
|
|
|
+ const seasonKey = seasonFilter.replace('-', '');
|
|
|
|
|
|
const chartId = `courses-chart-${seasonKey}-${selectedCourseValue}`;
|
|
|
const tableId = `course-delta-table-${seasonKey}-${selectedCourseValue}`;
|
|
|
@@ -797,19 +796,17 @@
|
|
|
|
|
|
const chartContainer = document.querySelector('.modern-chart-container');
|
|
|
if (chartContainer) {
|
|
|
- chartContainer.innerHTML = `
|
|
|
- <div class="chart-empty-state">
|
|
|
- <div style="text-align: center; padding: 4rem 2rem;">
|
|
|
- <div style="font-size: 4rem; margin-bottom: 1.5rem; opacity: 0.3;">📊</div>
|
|
|
- <h3 style="font-size: 1.5rem; font-weight: 600; margin-bottom: 1rem; color: #374151;">
|
|
|
- Grafico non disponibile
|
|
|
- </h3>
|
|
|
- <p style="font-size: 1rem; opacity: 0.7; margin: 0; max-width: 400px; margin-left: auto; margin-right: auto; line-height: 1.5;">
|
|
|
- Il grafico per questo corso non può essere visualizzato nella stagione selezionata.
|
|
|
- </p>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- `;
|
|
|
+ chartContainer.innerHTML = `<div class="chart-empty-state">
|
|
|
+ <div style="text-align: center; padding: 4rem 2rem;">
|
|
|
+ <div style="font-size: 4rem; margin-bottom: 1.5rem; opacity: 0.3;">📊</div>
|
|
|
+ <h3 style="font-size: 1.5rem; font-weight: 600; margin-bottom: 1rem; color: #374151;">
|
|
|
+ Grafico non disponibile
|
|
|
+ </h3>
|
|
|
+ <p style="font-size: 1rem; opacity: 0.7; margin: 0; max-width: 400px; margin-left: auto; margin-right: auto; line-height: 1.5;">
|
|
|
+ Il grafico per questo corso non può essere visualizzato nella stagione selezionata.
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>`;
|
|
|
}
|
|
|
|
|
|
if (tableContainer) {
|
|
|
@@ -832,19 +829,17 @@
|
|
|
}
|
|
|
|
|
|
const chartContainer = canvas.parentElement;
|
|
|
- chartContainer.innerHTML = `
|
|
|
- <div class="chart-empty-state">
|
|
|
- <div style="text-align: center; padding: 4rem 2rem;">
|
|
|
- <div style="font-size: 4rem; margin-bottom: 1.5rem; opacity: 0.3;">📊</div>
|
|
|
- <h3 style="font-size: 1.5rem; font-weight: 600; margin-bottom: 1rem; color: #374151;">
|
|
|
- ${courseData.message}
|
|
|
- </h3>
|
|
|
- <p style="font-size: 1rem; opacity: 0.7; margin: 0; max-width: 400px; margin-left: auto; margin-right: auto; line-height: 1.5;">
|
|
|
- Questo corso non ha pagamenti registrati per la stagione selezionata.
|
|
|
- </p>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- `;
|
|
|
+ chartContainer.innerHTML = `<div class="chart-empty-state">
|
|
|
+ <div style="text-align: center; padding: 4rem 2rem;">
|
|
|
+ <div style="font-size: 4rem; margin-bottom: 1.5rem; opacity: 0.3;">📊</div>
|
|
|
+ <h3 style="font-size: 1.5rem; font-weight: 600; margin-bottom: 1rem; color: #374151;">
|
|
|
+ ${courseData.message}
|
|
|
+ </h3>
|
|
|
+ <p style="font-size: 1rem; opacity: 0.7; margin: 0; max-width: 400px; margin-left: auto; margin-right: auto; line-height: 1.5;">
|
|
|
+ Questo corso non ha pagamenti registrati per la stagione selezionata.
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>`;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -863,6 +858,8 @@
|
|
|
this.updateCourseTable(tableContainer, courseData.tableData);
|
|
|
|
|
|
const participantData = courseData.datasets.find(d => d.participantData)?.participantData || [];
|
|
|
+ const suspendedData = courseData.datasets.find(d => d.suspendedData)?.suspendedData || [];
|
|
|
+ const monthNamesExtended = courseData.datasets.find(d => d.monthNamesExtended)?.monthNamesExtended || [];
|
|
|
|
|
|
const ctx = canvasElement.getContext('2d');
|
|
|
|
|
|
@@ -870,8 +867,8 @@
|
|
|
earnedGradient.addColorStop(0, 'rgba(16, 185, 129, 1)');
|
|
|
earnedGradient.addColorStop(1, 'rgba(16, 185, 129, 1)');
|
|
|
|
|
|
- const totalData = courseData.datasets.find(d => d.label === 'Pagamenti Attesi')?.data || [];
|
|
|
- const earnedData = courseData.datasets.find(d => d.label === 'Pagamenti Effettuati')?.data || [];
|
|
|
+ const totalData = courseData.datasets.find(d => d.label === 'TOT. DA INCASSARE')?.data || [];
|
|
|
+ const earnedData = courseData.datasets.find(d => d.label === 'TOT. INCASSATO')?.data || [];
|
|
|
|
|
|
this.charts[chartId] = new Chart(ctx, {
|
|
|
type: 'bar',
|
|
|
@@ -879,7 +876,7 @@
|
|
|
labels: courseData.labels,
|
|
|
datasets: [
|
|
|
{
|
|
|
- label: 'Pagamenti Effettuati',
|
|
|
+ label: 'TOT. INCASSATO',
|
|
|
backgroundColor: earnedGradient,
|
|
|
borderColor: 'rgba(16, 185, 129, 1)',
|
|
|
borderWidth: 0,
|
|
|
@@ -894,13 +891,16 @@
|
|
|
type: 'bar',
|
|
|
barThickness: "flex",
|
|
|
barPercentage: 0.65,
|
|
|
- categoryPercentage: 0.4,
|
|
|
- order: 2,
|
|
|
+ categoryPercentage: 0.25,
|
|
|
+ order: 1,
|
|
|
+ participantData: participantData,
|
|
|
+ suspendedData: suspendedData,
|
|
|
+ monthNamesExtended: monthNamesExtended,
|
|
|
},
|
|
|
{
|
|
|
- label: 'Pagamenti Attesi',
|
|
|
- backgroundColor: 'rgba(59, 130, 246, 1)',
|
|
|
- borderColor: 'rgba(59, 130, 246, 1)',
|
|
|
+ label: 'TOT. DA INCASSARE',
|
|
|
+ backgroundColor: '#F28322',
|
|
|
+ borderColor: '#F28322',
|
|
|
borderWidth: 0,
|
|
|
borderRadius: {
|
|
|
topLeft: 8,
|
|
|
@@ -913,9 +913,11 @@
|
|
|
type: 'bar',
|
|
|
barThickness: "flex",
|
|
|
barPercentage: 0.65,
|
|
|
- categoryPercentage: 0.4,
|
|
|
- order: 1,
|
|
|
+ categoryPercentage: 0.25,
|
|
|
+ order: 2,
|
|
|
participantData: participantData,
|
|
|
+ suspendedData: suspendedData,
|
|
|
+ monthNamesExtended: monthNamesExtended,
|
|
|
}
|
|
|
]
|
|
|
},
|
|
|
@@ -988,51 +990,60 @@
|
|
|
},
|
|
|
tooltip: {
|
|
|
backgroundColor: 'rgba(255, 255, 255, 1)',
|
|
|
- titleColor: '#111827',
|
|
|
- bodyColor: '#374151',
|
|
|
borderColor: 'rgba(229, 231, 235, 0.8)',
|
|
|
borderWidth: 2,
|
|
|
cornerRadius: 0,
|
|
|
titleFont: {
|
|
|
+ size: 15,
|
|
|
weight: 'bold',
|
|
|
- size: 15
|
|
|
},
|
|
|
+ titleColor: '#111827',
|
|
|
bodyFont: {
|
|
|
size: 14,
|
|
|
- weight: '500'
|
|
|
+ weight: '400',
|
|
|
+ },
|
|
|
+ bodyColor: '#111827',
|
|
|
+ footerFont: {
|
|
|
+ size: 14,
|
|
|
+ weight: '400',
|
|
|
},
|
|
|
+ // footerColor: '#0C6197',
|
|
|
+ footerSpacing: 0,
|
|
|
+ footerMarginTop: 0,
|
|
|
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);
|
|
|
+ title: function (tooltipItems) {
|
|
|
+ let sum = 0;
|
|
|
|
|
|
- if (context.dataset.label === 'Pagamenti Effettuati') {
|
|
|
- const earnedValue = parseFloat(context.parsed.y) || 0;
|
|
|
- const totalValue = parseFloat(totalData[context.dataIndex]) || 0;
|
|
|
- const missingValue = Math.max(0, totalValue - earnedValue);
|
|
|
+ tooltipItems.forEach(function(tooltipItem) {
|
|
|
+ sum += tooltipItem.parsed.y;
|
|
|
+ });
|
|
|
|
|
|
- if (participantData[context.dataIndex]) {
|
|
|
- label += '\n👥 Partecipanti: ' + participantData[context.dataIndex];
|
|
|
- }
|
|
|
+ let item = tooltipItems[0];
|
|
|
+ let index = item.dataIndex;
|
|
|
+ let monthNameExtended = item.dataset["monthNamesExtended"] ? item.dataset["monthNamesExtended"][index] : 0;
|
|
|
|
|
|
- if (missingValue > 0) {
|
|
|
- label += '\n🔴 Mancanti: €' + new Intl.NumberFormat('it-IT').format(missingValue);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (context.dataset.label === 'Pagamenti Attesi' && participantData[context.dataIndex]) {
|
|
|
- label += '\n👥 Partecipanti: ' + participantData[context.dataIndex];
|
|
|
- }
|
|
|
+ // return item.label + '\n' + 'TOTALE ATTESO: €' + new Intl.NumberFormat('it-IT').format(sum);
|
|
|
+ return monthNameExtended + '\n' + 'TOTALE ATTESO: €' + new Intl.NumberFormat('it-IT').format(sum);
|
|
|
+ },
|
|
|
+ // labelTextColor: function(tooltipItems) {
|
|
|
+ // return tooltipItems.dataset.backgroundColor;
|
|
|
+ // },
|
|
|
+ label: function (tooltipItems) {
|
|
|
+ let label = tooltipItems.dataset.label + ': €' + new Intl.NumberFormat('it-IT').format(tooltipItems.parsed.y);
|
|
|
|
|
|
return label;
|
|
|
- }
|
|
|
+ },
|
|
|
+ // footer: function (tooltipItems) {
|
|
|
+ // let item = tooltipItems[0];
|
|
|
+ // let index = item.dataIndex;
|
|
|
+ // let suspendedData = item.dataset["suspendedData"] ? item.dataset["suspendedData"][index] : 0;
|
|
|
+
|
|
|
+ // return "TOTALE SOSPESI: " + suspendedData;
|
|
|
+ // }
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
@@ -1068,15 +1079,13 @@
|
|
|
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>
|
|
|
- `;
|
|
|
+ let tableHtml = `<div class="course-table">
|
|
|
+ <div class="table-header">
|
|
|
+ <div class="table-cell month">MESE</div>
|
|
|
+ <div class="table-cell percentage">%<br/>INCASSATO</div>
|
|
|
+ <div class="table-cell delta">TOT. DA INCASSARE</div>
|
|
|
+ <div class="table-cell suspended">SOSPESI</div>
|
|
|
+ </div>`;
|
|
|
|
|
|
tableData.forEach(row => {
|
|
|
const earned = parseFloat(row.earned) || 0;
|
|
|
@@ -1108,9 +1117,9 @@
|
|
|
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(delta)}</div>
|
|
|
<div class="table-cell percentage ${percentageClass}">${percentageDisplay}</div>
|
|
|
+ <div class="table-cell delta ${deltaClass}">€${new Intl.NumberFormat('it-IT').format(delta)}</div>
|
|
|
+ <div class="table-cell suspended">${row.suspended}</div>
|
|
|
</div>
|
|
|
`;
|
|
|
});
|