PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.4.0
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.4.0
2.4.0 2.4.1 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.2 All 57 releases
← All changes | templates/dashboard-page.php +129 -222 2.1.12.4.0 View file →
@@ -3,23 +3,62 @@
3 3 if (!defined('ABSPATH')) {
4 4 exit;
5 5 }
6 6
7 +use EasyInvoice\Constants\PagesSlugs;
7 8
9 +$monthly_revenue = isset($monthly_revenue) && is_array($monthly_revenue) ? $monthly_revenue : array();
10 +$easy_invoice_has_chart_data = false;
11 +foreach ($monthly_revenue as $currencies) {
12 + if (! is_array($currencies)) {
13 + continue;
14 + }
15 + foreach ($currencies as $row) {
16 + if (isset($row['amount']) && is_numeric($row['amount']) && (float) $row['amount'] > 0) {
17 + $easy_invoice_has_chart_data = true;
18 + break 2;
19 + }
20 + }
21 +}
22 +
23 +if ($easy_invoice_has_chart_data) {
24 + wp_enqueue_script(
25 + 'easy-invoice-chart-vendor',
26 + EASY_INVOICE_PLUGIN_URL . 'assets/js/vendors/chart.min.js',
27 + array(),
28 + EASY_INVOICE_VERSION,
29 + true
30 + );
31 + wp_enqueue_script(
32 + 'easy-invoice-dashboard-chart',
33 + EASY_INVOICE_PLUGIN_URL . 'assets/js/dashboard-chart.js',
34 + array('easy-invoice-chart-vendor'),
35 + EASY_INVOICE_VERSION,
36 + true
37 + );
38 + wp_localize_script(
39 + 'easy-invoice-dashboard-chart',
40 + 'easyInvoiceDashboard',
41 + array(
42 + 'monthlyRevenue' => $monthly_revenue,
43 + 'hasData' => true,
44 + )
45 + );
46 +}
47 +
48 +$invoices_list_url = admin_url('admin.php?page=' . PagesSlugs::ALL_INVOICES);
8 49 ?>
9 50
10 51 <div class="p-8">
11 - <!-- Page Header -->
12 - <div class="bg-white border-b border-gray-200 px-6 py-5" style="margin-left: -2rem; margin-top: -2rem; padding-left:2rem; padding-right:2rem; margin-right: -2rem;">
52 + <div class="ei-app-page-header bg-white border-b border-gray-200 px-6 easy-invoice-admin-page-header">
13 53 <div class="flex items-center justify-between">
14 54 <div>
15 - <h1 class="text-2xl font-bold text-gray-900">Dashboard</h1>
16 - <p class="mt-1 text-sm text-gray-500">Overview of your invoice management system</p>
55 + <h1 class="text-2xl font-bold text-gray-900"><?php esc_html_e( 'Dashboard', 'easy-invoice' ); ?></h1>
56 + <p class="mt-1 text-sm text-gray-500"><?php esc_html_e( 'Overview of your invoice management system', 'easy-invoice' ); ?></p>
17 57 </div>
18 58 </div>
19 59 </div>
20 60
21 - <!-- Stats Cards -->
22 61 <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8 mt-8">
23 62 <div class="bg-white rounded-lg shadow p-6 transition-transform duration-300 hover:shadow-md hover:-translate-y-1">
24 63 <div class="flex items-center">
25 64 <div class="rounded-full bg-indigo-100 p-3 mr-4">
@@ -27,9 +66,9 @@
27 66 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
28 67 </svg>
29 68 </div>
30 69 <div>
31 - <h3 class="text-sm font-medium text-gray-500">Total Invoices</h3>
70 + <h3 class="text-sm font-medium text-gray-500"><?php esc_html_e( 'Total Invoices', 'easy-invoice' ); ?></h3>
32 71 <p class="mt-1 text-2xl font-bold text-gray-900"><?php echo esc_html($total_invoices); ?></p>
33 72 </div>
34 73 </div>
35 74 </div>
@@ -40,9 +79,9 @@
40 79 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
41 80 </svg>
42 81 </div>
43 82 <div>
44 - <h3 class="text-sm font-medium text-gray-500">Total Revenue</h3>
83 + <h3 class="text-sm font-medium text-gray-500"><?php esc_html_e( 'Total Revenue', 'easy-invoice' ); ?></h3>
45 84 <?php if (is_array($total_revenue) && !empty($total_revenue)): ?>
46 85 <div class="mt-1">
47 86 <?php
48 87 $currency_count = count($total_revenue);
@@ -51,15 +90,30 @@
51 90 $amount = isset($data['amount']) && is_numeric($data['amount']) ? $data['amount'] : 0;
52 91 $symbol = isset($data['symbol']) ? $data['symbol'] : '';
53 92 ?>
54 93 <div class="<?php echo $currency_count > 0 ? 'text-sm' : 'text-lg'; ?> font-bold text-gray-900 <?php echo !$is_last ? 'mb-1' : ''; ?>">
55 - <?php echo $symbol . number_format($amount, 2); ?>
94 + <?php echo esc_html($symbol . number_format($amount, 2)); ?>
56 95 <span class="text-xs font-normal text-gray-500"><?php echo esc_html(strtoupper((string)($currency ?? 'USD'))); ?></span>
57 96 </div>
58 97 <?php endforeach; ?>
59 98 </div>
60 99 <?php else: ?>
61 - <p class="mt-1 text-lg font-bold text-gray-900">$0.00</p>
100 + <?php
101 + // Show a formatted zero, not a sentence. Every sibling tile on
102 + // this row displays a number ("0"), so putting the prose
103 + // "No revenue recorded" here broke the row's visual rhythm and
104 + // wrapped onto two lines, making this card read as taller and
105 + // more important than the others. The zero carries the same
106 + // meaning and stays scannable alongside them.
107 + $ei_zero_symbol = function_exists('easy_invoice_get_currency_symbol') ? easy_invoice_get_currency_symbol() : '';
108 + $ei_zero_code = function_exists('easy_invoice_get_currency_code') ? easy_invoice_get_currency_code() : '';
109 + ?>
110 + <div class="text-lg font-bold text-gray-900">
111 + <?php echo esc_html($ei_zero_symbol . number_format(0, 2)); ?>
112 + <?php if ($ei_zero_code) : ?>
113 + <span class="text-xs font-normal text-gray-500"><?php echo esc_html(strtoupper((string) $ei_zero_code)); ?></span>
114 + <?php endif; ?>
115 + </div>
62 116 <?php endif; ?>
63 117 </div>
64 118 </div>
65 119 </div>
@@ -70,10 +124,13 @@
70 124 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
71 125 </svg>
72 126 </div>
73 127 <div>
74 - <h3 class="text-sm font-medium text-gray-500">Unpaid Invoices</h3>
128 + <h3 class="text-sm font-medium text-gray-500"><?php esc_html_e( 'Unpaid Invoices', 'easy-invoice' ); ?></h3>
75 129 <p class="mt-1 text-2xl font-bold text-yellow-600"><?php echo esc_html($unpaid_invoices); ?></p>
130 + <?php foreach ((array) ($unpaid_amount ?? []) as $ei_cur => $ei_amt) : ?>
131 + <p class="text-xs text-gray-500" style="font-variant-numeric: tabular-nums;"><?php echo esc_html(easy_invoice_format_money((float) $ei_amt, null, (string) $ei_cur)); ?> <?php esc_html_e('outstanding', 'easy-invoice'); ?></p>
132 + <?php endforeach; ?>
76 133 </div>
77 134 </div>
78 135 </div>
79 136 <div class="bg-white rounded-lg shadow p-6 transition-transform duration-300 hover:shadow-md hover:-translate-y-1">
@@ -83,17 +140,23 @@
83 140 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path>
84 141 </svg>
85 142 </div>
86 143 <div>
87 - <h3 class="text-sm font-medium text-gray-500">Overdue Invoices</h3>
144 + <h3 class="text-sm font-medium text-gray-500"><?php esc_html_e( 'Overdue Invoices', 'easy-invoice' ); ?></h3>
88 145 <p class="mt-1 text-2xl font-bold text-red-600"><?php echo esc_html($overdue_invoices); ?></p>
146 + <?php foreach ((array) ($overdue_amount ?? []) as $ei_cur => $ei_amt) : ?>
147 + <p class="text-xs text-gray-500" style="font-variant-numeric: tabular-nums;"><?php echo esc_html(easy_invoice_format_money((float) $ei_amt, null, (string) $ei_cur)); ?> <?php esc_html_e('past due', 'easy-invoice'); ?></p>
148 + <?php endforeach; ?>
89 149 </div>
90 150 </div>
91 151 </div>
92 152 </div>
93 153
94 - <!-- Client Stats Cards -->
95 - <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
154 + <?php // Same 4-column track as the stat row above (grid-cols-4 at lg), so the two
155 + // client cards line up under the first four instead of stretching to half the
156 + // page each. They are the same kind of tile and were rendering at roughly
157 + // double the width of their siblings, which read as unintentional. ?>
158 + <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
96 159 <div class="bg-white rounded-lg shadow p-6 transition-transform duration-300 hover:shadow-md hover:-translate-y-1">
97 160 <div class="flex items-center">
98 161 <div class="rounded-full bg-blue-100 p-3 mr-4">
99 162 <svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
@@ -103,9 +166,9 @@
103 166 <path d="M16.32 11.6722C18.36 11.6722 20 10.0322 20 7.99219C20 5.95219 18.36 4.31219 16.32 4.31219" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
104 167 </svg>
105 168 </div>
106 169 <div>
107 - <h3 class="text-sm font-medium text-gray-500">Total Clients</h3>
170 + <h3 class="text-sm font-medium text-gray-500"><?php esc_html_e( 'Total Clients', 'easy-invoice' ); ?></h3>
108 171 <p class="mt-1 text-2xl font-bold text-gray-900"><?php echo esc_html($total_clients); ?></p>
109 172 </div>
110 173 </div>
111 174 </div>
@@ -116,9 +179,9 @@
116 179 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
117 180 </svg>
118 181 </div>
119 182 <div>
120 - <h3 class="text-sm font-medium text-gray-500">Active Clients</h3>
183 + <h3 class="text-sm font-medium text-gray-500"><?php esc_html_e( 'Active Clients', 'easy-invoice' ); ?></h3>
121 184 <p class="mt-1 text-2xl font-bold text-indigo-600"><?php echo esc_html($active_clients); ?></p>
122 185 </div>
123 186 </div>
124 187 </div>
@@ -123,49 +186,61 @@
123 186 </div>
124 187 </div>
125 188 </div>
126 189
127 - <!-- Monthly Revenue Chart -->
128 - <div class="bg-white rounded-lg shadow p-6 mb-8">
129 - <h2 class="text-lg font-medium text-gray-900 mb-4">Monthly Revenue</h2>
130 - <div style="height: 300px; position: relative;">
131 - <canvas id="revenue-chart" style="width: 100% !important; height: 100% !important;"></canvas>
132 - </div>
190 + <div class="bg-white rounded-lg shadow p-6 mb-8 border border-gray-100">
191 + <h2 class="text-lg font-medium text-gray-900 mb-1"><?php esc_html_e( 'Monthly Revenue', 'easy-invoice' ); ?></h2>
192 + <?php if ($easy_invoice_has_chart_data) : ?>
193 + <p class="text-sm text-gray-500 mb-4"><?php esc_html_e( 'Paid amounts recorded over the last twelve months, by currency.', 'easy-invoice' ); ?></p>
194 + <div class="easy-invoice-chart-wrap">
195 + <canvas id="revenue-chart" class="easy-invoice-chart-canvas" role="img" aria-label="<?php echo esc_attr__( 'Monthly revenue by month and currency', 'easy-invoice' ); ?>"></canvas>
196 + </div>
197 + <?php else : ?>
198 + <p class="text-sm text-gray-500 mb-6"><?php esc_html_e( 'Trends appear here once completed payments exist in the selected period.', 'easy-invoice' ); ?></p>
199 + <div class="rounded-xl border border-dashed border-gray-200 bg-gradient-to-b from-gray-50 to-white px-8 py-12 text-center">
200 + <div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-indigo-50 text-indigo-600">
201 + <svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
202 + <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
203 + </svg>
204 + </div>
205 + <h3 class="mt-4 text-base font-semibold text-gray-900"><?php esc_html_e( 'No revenue trend to show yet', 'easy-invoice' ); ?></h3>
206 + <p class="mt-2 max-w-md mx-auto text-sm text-gray-500 leading-relaxed">
207 + <?php esc_html_e( 'Record a payment on an invoice to see your monthly performance in this chart.', 'easy-invoice' ); ?>
208 + </p>
209 + <a href="<?php echo esc_url($invoices_list_url); ?>" class="mt-6 inline-flex items-center rounded-md bg-indigo-600 px-4 py-2.5 text-sm font-medium text-white shadow-sm transition hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">
210 + <?php esc_html_e( 'View all invoices', 'easy-invoice' ); ?>
211 + </a>
212 + </div>
213 + <?php endif; ?>
133 214 </div>
134 215
135 - <!-- Recent Invoices -->
136 216 <div class="bg-white rounded-lg shadow">
137 217 <div class="px-6 py-4 border-b border-gray-200">
138 - <h2 class="text-lg font-medium text-gray-900">Recent Invoices</h2>
218 + <h2 class="text-lg font-medium text-gray-900"><?php esc_html_e( 'Recent Invoices', 'easy-invoice' ); ?></h2>
139 219 </div>
140 220 <div class="overflow-x-auto">
141 221 <table class="min-w-full divide-y divide-gray-200">
142 222 <thead class="bg-gray-50">
143 223 <tr>
144 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Invoice #</th>
145 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Client</th>
146 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
147 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
148 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Due Date</th>
149 - <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
224 + <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e( 'Invoice #', 'easy-invoice' ); ?></th>
225 + <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e( 'Client', 'easy-invoice' ); ?></th>
226 + <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e( 'Amount', 'easy-invoice' ); ?></th>
227 + <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e( 'Status', 'easy-invoice' ); ?></th>
228 + <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e( 'Due Date', 'easy-invoice' ); ?></th>
229 + <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"><?php esc_html_e( 'Actions', 'easy-invoice' ); ?></th>
150 230 </tr>
151 231 </thead>
152 232 <tbody class="bg-white divide-y divide-gray-200">
153 233 <?php if (!empty($recent_invoices)) : ?>
154 234 <?php foreach ($recent_invoices as $invoice):
155 - $statusClass = [
156 - 'paid' => 'bg-green-100 text-green-800',
157 - 'unpaid' => 'bg-yellow-100 text-yellow-800',
158 - 'overdue' => 'bg-red-100 text-red-800',
159 - 'draft' => 'bg-gray-100 text-gray-800'
160 - ][$invoice->getStatus()] ?? 'bg-gray-100 text-gray-800';
161 -
162 235 $invoiceId = $invoice->getId();
163 236 $invoiceNumber = $invoice->getNumber() ?: ('INV-' . $invoiceId);
164 237 $invoiceTotal = $invoice->getTotal();
165 - $clientName = $invoice->getCustomerName() ?: 'Client';
166 - $dueDate = $invoice->getDueDate() ?: date('Y-m-d');
167 - $status = ucfirst($invoice->getStatus());
238 + $clientName = $invoice->getCustomerName() ?: __( 'Client', 'easy-invoice' );
239 + $dueDate = $invoice->getDueDate() ?: current_time('Y-m-d');
240 + $status_key = \EasyInvoice\Helpers\InvoiceStatus::displayKeyFor( $invoice );
241 + $statusClass = \EasyInvoice\Helpers\InvoiceStatus::badgeClass( $status_key );
242 + $status = \EasyInvoice\Helpers\InvoiceStatus::label( $status_key );
168 243 ?>
169 244 <tr>
170 245 <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900"><?php echo esc_html($invoiceNumber); ?></td>
171 246 <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"><?php echo esc_html($clientName); ?></td>
@@ -175,21 +250,31 @@
175 250 echo esc_html($formatter->format($invoiceTotal));
176 251 ?></td>
177 252 <td class="px-6 py-4 whitespace-nowrap">
178 253 <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full <?php echo esc_attr($statusClass); ?>">
179 - <?php echo esc_html($status); ?>
254 + <?php echo esc_html( $status ); ?>
180 255 </span>
181 256 </td>
182 257 <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"><?php echo esc_html($dueDate); ?></td>
183 258 <td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
184 - <a href="<?php echo admin_url('admin.php?page=easy-invoice-invoices&view=edit&invoice_id=' . $invoiceId); ?>" class="text-indigo-600 hover:text-indigo-900 mr-3">Edit</a>
185 - <a href="<?php echo admin_url('admin.php?page=easy-invoice-invoices&view=view&invoice_id=' . $invoiceId); ?>" class="text-indigo-600 hover:text-indigo-900">View</a>
259 + <?php
260 + // Both links pointed at `page=easy-invoice-invoices`, which is
261 + // not a registered admin page — the invoice list is
262 + // `easy-invoice-all` and the editor is `easy-invoice-builder`.
263 + // Every Edit and View link on the dashboard returned a 403
264 + // "you do not have permission" screen.
265 + //
266 + // Now matching what the invoice listing itself uses: Edit opens
267 + // the builder, View opens the public invoice permalink.
268 + ?>
269 + <a href="<?php echo esc_url(admin_url('admin.php?page=easy-invoice-builder&invoice_id=' . $invoiceId)); ?>" class="text-indigo-600 hover:text-indigo-900 mr-3"><?php esc_html_e( 'Edit', 'easy-invoice' ); ?></a>
270 + <a href="<?php echo esc_url(get_permalink($invoiceId)); ?>" target="_blank" rel="noopener" class="text-indigo-600 hover:text-indigo-900"><?php esc_html_e( 'View', 'easy-invoice' ); ?></a>
186 271 </td>
187 272 </tr>
188 273 <?php endforeach; ?>
189 274 <?php else: ?>
190 275 <tr>
191 - <td colspan="6" class="px-6 py-4 text-center text-sm text-gray-500">No invoices found</td>
276 + <td colspan="6" class="px-6 py-4 text-center text-sm text-gray-500"><?php esc_html_e( 'No invoices found', 'easy-invoice' ); ?></td>
192 277 </tr>
193 278 <?php endif; ?>
194 279 </tbody>
195 280 </table>
@@ -194,183 +279,5 @@
194 279 </tbody>
195 280 </table>
196 281 </div>
197 282 </div>
198 -</div>
199 -
200 -<!-- Chart.js for Revenue Chart -->
201 -<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
202 -<script>
203 - // Add fallback to CDN if local file fails
204 - if (typeof Chart === "undefined") {
205 - var script = document.createElement("script");
206 - script.src = "https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js";
207 - script.onload = function() {
208 - // Chart.js loaded from CDN
209 - };
210 - script.onerror = function() {
211 - // Failed to load Chart.js from CDN
212 - };
213 - document.head.appendChild(script);
214 - }
215 -
216 - // Initialize dashboard revenue chart
217 - document.addEventListener("DOMContentLoaded", function() {
218 - const chartElement = document.getElementById("revenue-chart");
219 -
220 - if (!chartElement) {
221 - return;
222 - }
223 -
224 - // Check if Chart.js is available
225 - if (typeof Chart === "undefined") {
226 - setTimeout(function() {
227 - initializeDashboardRevenueChart();
228 - }, 500);
229 - return;
230 - }
231 -
232 - initializeDashboardRevenueChart();
233 - });
234 -
235 - function initializeDashboardRevenueChart() {
236 - const chartElement = document.getElementById("revenue-chart");
237 -
238 - if (!chartElement) {
239 - return;
240 - }
241 -
242 - // Destroy existing chart if it exists
243 - if (window.dashboardRevenueChart) {
244 - window.dashboardRevenueChart.destroy();
245 - }
246 -
247 - const ctx = chartElement.getContext("2d");
248 - if (!ctx) {
249 - return;
250 - }
251 -
252 - // Get data from PHP
253 - const monthlyRevenueData = <?php echo json_encode($monthly_revenue); ?>;
254 - const monthLabels = Object.keys(monthlyRevenueData);
255 -
256 - // Check if we have real data
257 - let hasRealData = false;
258 - if (monthlyRevenueData && typeof monthlyRevenueData === "object") {
259 - for (let month in monthlyRevenueData) {
260 - if (monthlyRevenueData[month] && typeof monthlyRevenueData[month] === "object") {
261 - for (let currency in monthlyRevenueData[month]) {
262 - if (monthlyRevenueData[month][currency] &&
263 - monthlyRevenueData[month][currency].amount &&
264 - monthlyRevenueData[month][currency].amount > 0) {
265 - hasRealData = true;
266 - break;
267 - }
268 - }
269 - }
270 - }
271 - }
272 -
273 - if (hasRealData) {
274 - // Create datasets for each currency
275 - const datasets = [];
276 - const colors = [
277 - "rgba(79, 70, 229, 0.8)",
278 - "rgba(34, 197, 94, 0.8)",
279 - "rgba(239, 68, 68, 0.8)",
280 - "rgba(245, 158, 11, 0.8)",
281 - "rgba(139, 92, 246, 0.8)"
282 - ];
283 -
284 - let colorIndex = 0;
285 - for (let currency in monthlyRevenueData) {
286 - if (monthlyRevenueData[currency] && monthlyRevenueData[currency].amount > 0) {
287 - datasets.push({
288 - label: currency,
289 - data: [monthlyRevenueData[currency].amount],
290 - backgroundColor: colors[colorIndex % colors.length],
291 - borderColor: colors[colorIndex % colors.length].replace("0.8", "1"),
292 - borderWidth: 2
293 - });
294 - colorIndex++;
295 - }
296 - }
297 -
298 - // Create chart with real data
299 - window.dashboardRevenueChart = new Chart(ctx, {
300 - type: "bar",
301 - data: {
302 - labels: monthLabels,
303 - datasets: datasets
304 - },
305 - options: {
306 - responsive: true,
307 - maintainAspectRatio: false,
308 - scales: {
309 - y: {
310 - beginAtZero: true,
311 - ticks: {
312 - callback: function(value) {
313 - return value;
314 - }
315 - }
316 - }
317 - },
318 - plugins: {
319 - legend: {
320 - display: true,
321 - position: "top"
322 - }
323 - }
324 - }
325 - });
326 - } else {
327 - // Create sample chart
328 - const sampleData = {
329 - "Jan 2025": { USD: { amount: 1200, symbol: "$" } },
330 - "Feb 2025": { USD: { amount: 1800, symbol: "$" } },
331 - "Mar 2025": { USD: { amount: 1500, symbol: "$" } },
332 - "Apr 2025": { USD: { amount: 2200, symbol: "$" } },
333 - "May 2025": { USD: { amount: 1900, symbol: "$" } },
334 - "Jun 2025": { USD: { amount: 2500, symbol: "$" } }
335 - };
336 -
337 - const sampleLabels = Object.keys(sampleData);
338 - const sampleValues = sampleLabels.map(month => sampleData[month].USD.amount);
339 -
340 - window.dashboardRevenueChart = new Chart(ctx, {
341 - type: "bar",
342 - data: {
343 - labels: sampleLabels,
344 - datasets: [{
345 - label: "Sample Revenue",
346 - data: sampleValues,
347 - backgroundColor: "rgba(79, 70, 229, 0.8)",
348 - borderColor: "rgba(79, 70, 229, 1)",
349 - borderWidth: 2
350 - }]
351 - },
352 - options: {
353 - responsive: true,
354 - maintainAspectRatio: false,
355 - scales: {
356 - y: {
357 - beginAtZero: true,
358 - ticks: {
359 - callback: function(value) {
360 - return value;
361 - }
362 - }
363 - }
364 - },
365 - plugins: {
366 - legend: {
367 - display: true,
368 - position: "top"
369 - }
370 - }
371 - }
372 - });
373 - }
374 - }
375 - </script>
376 -</script>
283 +</div>