const deviceChart = overviewCharts.device_breakdown || { labels: [], series: [] }; const browserChart = overviewCharts.browser_breakdown || { labels: [], series: [] }; const platformChart = overviewCharts.platform_breakdown || { labels: [], series: [] }; const carrierChart = overviewCharts.carrier_breakdown || { labels: [], series: [] }; const countryDistributionChart = overviewCharts.country_distribution || { labels: [], series: [] }; const gatewayPerformanceChart = overviewCharts.gateway_performance || { labels: [], delivered: [], failed: [] }; const hourlySendingChart = overviewCharts.hourly_sending || { labels: [], series: [] }; const deliveryTimelineChart = overviewCharts.delivery_timeline || { labels: [], delivered: [], failed: [] }; renderOpenTrackingChart("#engagement-overview-chart", openTrackingChart); function deviceBarChartHeight(selector) { const element = document.querySelector(selector); if (!element) { return 200; } const body = element.closest('.campaign-device-bar-card__body'); if (body && body.clientHeight > 0) { return Math.max(140, body.clientHeight); } return 200; } function renderDeviceOpensChart(selector, chartData) { const element = document.querySelector(selector); if (!element) { return; } const body = element.closest('.campaign-device-bar-card__body'); if (body && body.clientHeight === 0) { setTimeout(function () { renderDeviceOpensChart(selector, chartData); }, 250); return; } const noDataMessage = '{{ __('locale.datatables.no_results') }}'; const labels = Array.isArray(chartData.labels) ? chartData.labels.filter(Boolean) : []; const series = Array.isArray(chartData.series) ? chartData.series.map(function (v) { return Number(v) || 0; }) : []; if (!labels.length || !series.length || !series.some(function (v) { return v > 0; })) { showChartPlaceholder(element, noDataMessage); return; } const chartHeight = deviceBarChartHeight(selector); if (element._deviceBarChart && typeof element._deviceBarChart.destroy === 'function') { try { element._deviceBarChart.destroy(); } catch (e) { // ignore } } element.innerHTML = ''; try { element._deviceBarChart = new ApexCharts(element, { chart: { type: 'bar', height: chartHeight, width: '100%', toolbar: { show: false } }, plotOptions: { bar: { columnWidth: '55%', borderRadius: 4, distributed: true } }, series: [{ name: '{{ __('locale.campaigns.estimated_opened') }}', data: series }], xaxis: { categories: labels, labels: { style: { fontSize: '11px' }, rotate: -25, hideOverlappingLabels: true } }, legend: { position: 'bottom', fontSize: '11px', horizontalAlign: 'center' }, colors: [chartColors.primary, chartColors.info, chartColors.success, chartColors.warning, chartColors.secondary], dataLabels: { enabled: false }, grid: { padding: { left: 8, right: 8, bottom: 0 } } }); element._deviceBarChart.render(); } catch (error) { console.warn('Device bar chart render skipped', error); showChartPlaceholder(element, noDataMessage); } } renderDeviceOpensChart("#device-opens-by-device-chart", deviceChart); let deviceBarChartResizeTimer = null; window.addEventListener('resize', function () { clearTimeout(deviceBarChartResizeTimer); deviceBarChartResizeTimer = setTimeout(function () { renderDeviceOpensChart("#device-opens-by-device-chart", deviceChart); }, 200); }); renderChart("#browser-breakdown-chart", { chart: { type: 'donut', height: 350, toolbar: { show: false } }, labels: browserChart.labels || [], series: browserChart.series || [], colors: [chartColors.primary, chartColors.info, chartColors.success, chartColors.warning, chartColors.danger], legend: { position: 'bottom', fontSize: '12px' }, dataLabels: { enabled: false }, stroke: { width: 0 }, plotOptions: { pie: { donut: { size: '70%' } } } }); renderChart("#platform-breakdown-chart", { chart: { type: 'donut', height: 350, toolbar: { show: false } }, labels: platformChart.labels || [], series: platformChart.series || [], colors: [chartColors.info, chartColors.primary, chartColors.success, chartColors.warning, chartColors.danger], legend: { position: 'bottom', fontSize: '12px' }, dataLabels: { enabled: false }, stroke: { width: 0 }, plotOptions: { pie: { donut: { size: '70%' } } } }); renderChart("#carrier-breakdown-chart", { chart: { type: 'donut', height: 350, toolbar: { show: false } }, labels: carrierChart.labels || [], series: carrierChart.series || [], colors: [chartColors.success, chartColors.primary, chartColors.info, chartColors.warning, chartColors.danger], legend: { position: 'bottom', fontSize: '12px' }, dataLabels: { enabled: false }, stroke: { width: 0 }, plotOptions: { pie: { donut: { size: '70%' } } } }); renderChart("#country-distribution-chart", { chart: { stacked: true, type: 'bar', toolbar: { show: false }, height: 290 }, plotOptions: { bar: { columnWidth: '70%' } }, colors: ['#7367F0'], series: [{ name: '{{ __('locale.campaigns.overview.chart_messages') }}', data: chartPath(countryDistributionChart, 'series', []) }], grid: { borderColor: '#e7eef7', padding: { left: 0, right: 0 } }, legend: { show: true, position: 'top', horizontalAlign: 'left', offsetX: 0, fontSize: '14px', markers: { radius: 50, width: 10, height: 10 } }, dataLabels: { enabled: false }, xaxis: { labels: { style: { colors: '#b9c3cd' } }, axisTicks: { show: false }, categories: chartPath(countryDistributionChart, 'labels', []), axisBorder: { show: false } }, yaxis: { tickAmount: 5, labels: { style: { color: '#b9c3cd' }, formatter: function(val) { return val.toFixed(1); } } }, tooltip: { x: { show: false } } }); @if($showGatewayStatistics ?? true) renderChart("#gateway-performance-chart", { chart: { stacked: true, type: 'bar', toolbar: { show: false }, height: 290 }, plotOptions: { bar: { columnWidth: '70%' } }, colors: [chartColors.success, chartColors.danger], series: [ { name: '{{ __('locale.labels.delivered') }}', data: chartPath(gatewayPerformanceChart, 'delivered', []) }, { name: '{{ __('locale.labels.failed') }}', data: chartPath(gatewayPerformanceChart, 'failed', []) } ], grid: { borderColor: '#e7eef7', padding: { left: 0, right: 0 } }, legend: { show: true, position: 'top', horizontalAlign: 'left', offsetX: 0, fontSize: '14px', markers: { radius: 50, width: 10, height: 10 } }, dataLabels: { enabled: false }, xaxis: { labels: { style: { colors: '#b9c3cd' } }, axisTicks: { show: false }, categories: chartPath(gatewayPerformanceChart, 'labels', []), axisBorder: { show: false } }, yaxis: { tickAmount: 5, labels: { style: { color: '#b9c3cd' }, formatter: function(val) { return val.toFixed(1); } } }, tooltip: { x: { show: false } } }); @endif renderChart("#hourly-sending-chart", { chart: { height: 350, type: 'area', toolbar: { show: false }, sparkline: { enabled: false }, zoom: { enabled: false } }, colors: [window.colors ? window.colors.solid.primary : chartColors.primary], dataLabels: { enabled: false }, stroke: { curve: 'smooth', width: 2.5 }, fill: { type: 'gradient', gradient: { shadeIntensity: 0.9, opacityFrom: 0.7, opacityTo: 0.5, stops: [0, 80, 100] } }, series: [{ name: '{{ __('locale.campaigns.overview.chart_sent') }}', data: chartPath(hourlySendingChart, 'series', []) }], xaxis: { categories: chartPath(hourlySendingChart, 'labels', []), labels: { style: { colors: '#b9c3cd', fontSize: '1rem' } }, axisTicks: { show: false }, axisBorder: { show: false } }, yaxis: [{ y: 0, offsetX: 0, offsetY: 0, padding: { left: 0, right: 0 } }], tooltip: { x: { show: false } } }); renderChart("#delivery-timeline-chart", { chart: { height: 350, toolbar: { show: false }, zoom: { enabled: false }, type: 'line', offsetX: -10 }, stroke: { curve: 'smooth', dashArray: [0, 5], width: [5, 7] }, grid: { borderColor: $label_color, padding: { top: -20, bottom: -10, left: 20 } }, legend: { show: true }, colors: [$stroke_color_2, chartColors.danger], fill: { type: 'gradient', gradient: { shade: 'dark', inverseColors: false, gradientToColors: [window.colors ? window.colors.solid.primary : chartColors.primary, chartColors.danger], shadeIntensity: 1, type: 'horizontal', opacityFrom: 1, opacityTo: 1, stops: [0, 100, 100, 100] } }, markers: { size: 0, hover: { size: 5 } }, xaxis: { labels: { style: { colors: $textMutedColor, fontSize: '0.75rem' }, rotate: -45, rotateAlways: false, hideOverlappingLabels: true, trim: true, maxHeight: 60 }, axisTicks: { show: false }, categories: chartPath(deliveryTimelineChart, 'labels', []), axisBorder: { show: false }, tickPlacement: 'on' }, yaxis: { tickAmount: 5, labels: { style: { colors: $textMutedColor, fontSize: '1rem' }, formatter: function(val) { return val > 999 ? (val / 1000).toFixed(0) + 'k' : val; } } }, tooltip: { x: { show: false } }, series: [ { name: '{{ __('locale.labels.delivered') }}', data: chartPath(deliveryTimelineChart, 'delivered', []) }, { name: '{{ __('locale.labels.failed') }}', data: chartPath(deliveryTimelineChart, 'failed', []) } ] });