PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.3.2
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.3.2
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
easy-invoice / templates / main-template.php

main-template.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.3.2, at templates/main-template.php

620 lines 38.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 $current_page = isset($_GET['page']) ? sanitize_text_field($_GET['page']) : 'easy-invoice';
3
4 // Function to check if current page is a subpage of a main menu
5 function is_subpage_of($current_page, $main_page) {
6 // Check if current page starts with the main page slug
7 $current_page = $current_page ?? '';
8 $main_page = $main_page ?? '';
9 return strpos($current_page, $main_page) === 0;
10 }
11
12 // Function to get the active menu class
13 function get_menu_class($current_page, $menu_page, $is_active = false) {
14 if ($is_active) {
15 return 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600';
16 }
17 return 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700';
18 }
19
20 // Function to get the active icon class
21 function get_icon_class($current_page, $menu_page, $is_active = false) {
22 if ($is_active) {
23 return 'text-indigo-600';
24 }
25 return 'text-gray-400 group-hover:text-indigo-500';
26 }
27
28 // Determine which menu should be active
29 $is_dashboard_active = $current_page === 'easy-invoice';
30 $is_invoices_active = in_array($current_page, [
31 'easy-invoice-all', // All invoices
32 'easy-invoice-builder', // Invoice builder
33 'easy-invoice-preview' // Invoice preview
34 ]);
35 $is_quotes_active = in_array($current_page, [
36 'easy-quote-all', // All quotes
37 'easy-invoice-quote-builder', // Quote builder
38 'easy-quote-preview' // Quote preview
39 ]);
40 $is_payments_active = in_array($current_page, [
41 'easy-invoice-payments', // All payments
42 'easy-invoice-payment-new' // Add new payment
43 ]);
44 $is_clients_active = in_array($current_page, [
45 'easy-invoice-clients', // All clients
46 'easy-invoice-client-edit', // Edit client
47 'easy-invoice-client-view' // View client
48 ]);
49 $is_item_library_active = in_array($current_page, [
50 'easy-invoice-pro-item-library', // Item Library (Pro)
51 'easy-invoice-item-library' // Item Library (alternative)
52 ]);
53 $is_templates_active = in_array($current_page, [
54 'easy-invoice-templates', // Template Builder (Pro)
55 'easy-invoice-template-builder' // Template Builder page
56 ]);
57 $is_reports_active = $current_page === 'easy-invoice-reports';
58 $is_settings_active = in_array($current_page, [
59 'easy-invoice-settings', // Main settings
60 'easy-invoice-email-settings', // Email settings
61 'easy-invoice-email-settings-general',
62 'easy-invoice-email-settings-invoice',
63 'easy-invoice-email-settings-quote',
64 'easy-invoice-email-settings-payment',
65 'easy-invoice-email-settings-payment-reminder',
66 'easy-invoice-pro-settings', // Pro settings
67 'easy-invoice-pro-translations' // Pro translations
68 ]);
69 // The "Addons" sidebar entry is only active on the Addons grid itself.
70 // Per-addon settings pages (Time Tracking / Smart Reminders / White-Label /
71 // Team & Audit / Webhooks) are now top-level sidebar entries — each highlights
72 // itself; the parent Addons row should NOT also light up.
73 $is_addons_active = ($current_page === 'easy-invoice-addons');
74 ?>
75
76 <div class="fixed inset-y-0 left-0 w-64 bg-white shadow-lg border-r border-gray-200 ei-app-sidebar flex flex-col">
77
78 <div class="ei-app-sidebar-top flex flex-col items-center justify-center px-4 py-2 border-b border-gray-200 box-border flex-shrink-0">
79 <?php
80 /**
81 * Default logo HTML. Addons (White-Label) can short-circuit this to
82 * inject a custom image/label without touching this template.
83 *
84 * Filter: easy_invoice_admin_logo_html
85 * Args: ($default_html)
86 */
87 $default_logo_html = '<div class="flex items-center space-x-2 mb-1">'
88 . '<div class="flex items-center justify-center w-8 h-8 bg-indigo-600 rounded ei-app-logo-mark">'
89 . '<svg class="h-5 w-5 text-white" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">'
90 . '<path d="M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
91 . '<path d="M14 2V8H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
92 . '<path d="M16 13H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
93 . '<path d="M16 17H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
94 . '<path d="M10 9H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
95 . '</svg></div>'
96 . '<span class="text-lg font-semibold text-gray-900 ei-app-logo-label">' . esc_html__('Easy Invoice', 'easy-invoice') . '</span>'
97 . '</div>';
98 echo apply_filters('easy_invoice_admin_logo_html', $default_logo_html);
99 ?>
100 <?php if (apply_filters('easy_invoice_admin_show_back_to_wp', true)): ?>
101 <a href="<?php echo admin_url(); ?>" target="_blank" class="inline-flex items-center text-xs text-gray-500 hover:text-gray-700 transition-colors duration-200">
102 <svg class="w-3 h-3 mr-1" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
103 <path d="M19 12H5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
104 <path d="M12 19L5 12L12 5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
105 </svg>
106 <?php esc_html_e( 'Back to WordPress', 'easy-invoice' ); ?>
107 </a>
108 <?php endif; ?>
109
110
111 <?php if (apply_filters('easy_invoice_admin_show_version_badges', true)): ?>
112 <div class="mt-1 flex flex-wrap items-center justify-center gap-1.5">
113
114 <span class="inline-flex items-center px-1.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-700 border border-gray-200">
115 <svg class="w-2.5 h-2.5 mr-1 text-gray-500" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
116 <path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
117 <path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
118 <path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
119 </svg>
120 v<?php echo esc_html(EASY_INVOICE_VERSION); ?>
121 </span>
122
123 <?php if (defined('EASY_INVOICE_PRO_VERSION') && function_exists('is_plugin_active') && is_plugin_active('easy-invoice-pro/easy-invoice-pro.php')): ?>
124
125 <span class="inline-flex items-center px-1.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-700 border border-green-200">
126 <svg class="w-2.5 h-2.5 mr-1 text-green-500" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
127 <path d="M9 12L11 14L15 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
128 <path d="M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
129 </svg>
130 <?php echo esc_html( sprintf( __( 'Pro v%s', 'easy-invoice' ), EASY_INVOICE_PRO_VERSION ) ); ?>
131 </span>
132 <?php endif; ?>
133 </div>
134 <?php endif; // easy_invoice_admin_show_version_badges ?>
135 </div>
136
137
138 <nav class="ei-app-sidebar-nav flex-1 min-h-0 overflow-y-auto mt-6 px-3 pb-4 space-y-2">
139
140 <a href="<?php echo admin_url('admin.php?page=easy-invoice'); ?>"
141 class="<?php echo $is_dashboard_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
142 <svg class="<?php echo $is_dashboard_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
143 <path d="M3 13H9V19H3V13Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
144 <path d="M9 13H15V19H9V13Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
145 <path d="M15 13H21V19H15V13Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
146 <path d="M3 5H9V11H3V5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
147 <path d="M9 5H15V11H9V5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
148 <path d="M15 5H21V11H15V5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
149 </svg>
150 <?php esc_html_e( 'Dashboard', 'easy-invoice' ); ?>
151 </a>
152
153
154 <a href="<?php echo admin_url('admin.php?page=easy-invoice-all'); ?>"
155 class="<?php echo $is_invoices_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
156 <svg class="<?php echo $is_invoices_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
157 <path d="M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
158 <path d="M14 2V8H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
159 <path d="M12 11V19" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
160 <path d="M14.5 13H10.75a1.75 1.75 0 0 0 0 3.5h2.5a1.75 1.75 0 0 1 0 3.5H9.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
161 </svg>
162 <?php esc_html_e( 'Invoices', 'easy-invoice' ); ?>
163 </a>
164
165
166 <a href="<?php echo admin_url('admin.php?page=easy-quote-all'); ?>"
167 class="<?php echo $is_quotes_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
168 <svg class="<?php echo $is_quotes_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
169 <path d="M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
170 <path d="M14 2V8H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
171 <path d="M8.5 15.5L11 18L16 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
172 </svg>
173 <?php esc_html_e( 'Quotes', 'easy-invoice' ); ?>
174 </a>
175
176
177 <a href="<?php echo admin_url('admin.php?page=easy-invoice-payments'); ?>"
178 class="<?php echo $is_payments_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
179 <svg class="<?php echo $is_payments_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
180 <rect x="1" y="4" width="22" height="16" rx="2" ry="2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
181 <line x1="1" y1="10" x2="23" y2="10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
182 </svg>
183 <?php esc_html_e( 'Payments', 'easy-invoice' ); ?>
184 </a>
185
186
187 <a href="<?php echo admin_url('admin.php?page=easy-invoice-clients'); ?>"
188 class="<?php echo $is_clients_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
189 <svg class="<?php echo $is_clients_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
190 <path d="M17 21V19C17 17.9391 16.5786 16.9217 15.8284 16.1716C15.0783 15.4214 14.0609 15 13 15H5C3.93913 15 2.92172 15.4214 2.17157 16.1716C1.42143 16.9217 1 17.9391 1 19V21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
191 <circle cx="9" cy="7" r="4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
192 <path d="M23 21V19C23 18.1137 22.6485 17.2628 22.0237 16.6425C21.3989 16.0221 20.5471 15.6722 19.66 15.6722C18.7729 15.6722 17.9211 16.0221 17.2963 16.6425C16.6715 17.2628 16.32 18.1137 16.32 19V21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
193 <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"/>
194 </svg>
195 <?php esc_html_e( 'Clients', 'easy-invoice' ); ?>
196 </a>
197
198 <?php
199 // Item Library + Template Builder sidebar entries were here.
200 // They've been moved BELOW the Addons menu — see the per-addon
201 // sidebar loop further down in this file (lines ~365). The loop
202 // automatically renders a sidebar entry for every enabled addon
203 // whose registry entry has a non-empty settings_url, so the two
204 // explicit blocks are no longer needed (and were creating
205 // visual duplication with the loop).
206 ?>
207
208 <?php
209 // Reports — addon-gated (PERSONAL tier).
210 //
211 // When the addon is loaded, the per-addon sidebar loop further
212 // down in this file (after the Addons menu entry) renders the
213 // Reports link automatically — so this block only handles the
214 // Free-user upsell state. Showing it twice (here AND via the
215 // loop) was the cause of the "2 Reports pages" duplicate.
216 ?>
217 <?php if (!easy_invoice_has_pro()): ?>
218
219 <a href="#" id="reports-menu-link"
220 class="text-gray-600 hover:bg-indigo-50 hover:text-indigo-700 group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
221 <svg class="text-gray-400 group-hover:text-indigo-500 mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
222 <path d="M18 20V10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
223 <path d="M12 20V4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
224 <path d="M6 20V14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
225 </svg>
226 <?php esc_html_e( 'Reports', 'easy-invoice' ); ?>
227 <span class="ml-auto inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-purple-600 text-white shadow-sm">
228 <svg class="w-4 h-4 mr-1 text-white" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
229 <path d="M12 8L15 13.2L18 10.5L17.3 14H6.7L6 10.5L9 13.2L12 8M12 4L8.5 10L3 5L5 16H19L21 5L15.5 10L12 4Z"/>
230 </svg>
231 <?php esc_html_e( 'Pro', 'easy-invoice' ); ?>
232 </span>
233 </a>
234 <?php endif; ?>
235
236
237 <a href="<?php echo admin_url('admin.php?page=easy-invoice-settings'); ?>"
238 class="<?php echo $is_settings_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
239 <svg class="<?php echo $is_settings_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
240 <circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
241 <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
242 </svg>
243 <?php esc_html_e( 'Settings', 'easy-invoice' ); ?>
244 </a>
245
246
247 <?php
248 // Check if Pro plugin is active and get license status
249 $show_license_badge = false;
250 $license_status = 'inactive';
251 $license_text = __( 'Deactivated', 'easy-invoice' );
252
253 if (easy_invoice_has_pro()) {
254 $license_key = \EasyInvoicePro\Updater\License::get_license_key();
255 $is_valid = \EasyInvoicePro\Updater\License::has_valid_license();
256 $is_expired = \EasyInvoicePro\Updater\License::has_license_expired();
257
258 // Always show badge for Pro version
259 $show_license_badge = true;
260
261 if (!empty($license_key)) {
262 if ($is_valid && !$is_expired) {
263 $license_status = 'activated';
264 $license_text = __( 'Activated', 'easy-invoice' );
265 } elseif ($is_expired) {
266 $license_status = 'expired';
267 $license_text = __( 'Expired', 'easy-invoice' );
268 } else {
269 $license_status = 'inactive';
270 $license_text = __( 'Deactivated', 'easy-invoice' );
271 }
272 } else {
273 // No license key entered
274 $license_status = 'inactive';
275 $license_text = __( 'Inactive', 'easy-invoice' );
276 }
277 } else {
278 // Free version - show Free badge
279 $show_license_badge = true;
280 $license_status = 'free';
281 $license_text = __( 'Free', 'easy-invoice' );
282 }
283 ?>
284 <a href="<?php echo admin_url('admin.php?page=easy-invoice-license'); ?>"
285 class="<?php echo ($current_page === 'easy-invoice-license') ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
286
287 <svg class="<?php echo ($current_page === 'easy-invoice-license') ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
288 <circle cx="7.5" cy="15.5" r="5.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
289 <path d="M21 2L11.5 11.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
290 <path d="M15.5 7.5L18.5 10.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
291 </svg>
292 <span class="flex-1"><?php esc_html_e( 'License', 'easy-invoice' ); ?></span>
293 <?php if ($show_license_badge): ?>
294 <span class="license-status-badge <?php echo $license_status; ?>">
295 <span class="status-dot"></span>
296 <?php echo esc_html( $license_text ); ?>
297 </span>
298 <?php endif; ?>
299 </a>
300
301
302 <?php
303 $show_free_vs_pro = !easy_invoice_has_pro();
304
305 if ($show_free_vs_pro):
306 ?>
307 <a href="<?php echo admin_url('admin.php?page=easy-invoice-free-vs-pro'); ?>"
308 class="<?php echo ($current_page === 'easy-invoice-free-vs-pro') ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
309 <svg class="<?php echo ($current_page === 'easy-invoice-free-vs-pro') ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
310 <path d="M3 6L21 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
311 <path d="M3 12L21 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
312 <path d="M3 18L21 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
313 <path d="M9 3L9 21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
314 <path d="M15 3L15 21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
315 </svg>
316 <span class="flex-1"><?php esc_html_e('Free vs Pro', 'easy-invoice'); ?></span>
317 <span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-purple-100 text-purple-800">
318 <?php esc_html_e('Compare', 'easy-invoice'); ?>
319 </span>
320 </a>
321 <?php endif; ?>
322
323 <?php
324 // Per-addon sidebar entries. Show every enabled addon that has
325 // its own dedicated page (Smart Reminders, Time Tracking,
326 // White Label, etc. — anything whose settings_url is NOT a
327 // deep-link into the main Settings page). Addons whose settings
328 // live inside Settings → <section> (Secure Links → Advanced,
329 // Partial Payments → Invoice, etc.) are intentionally excluded:
330 // the main Settings page's section nav is already the
331 // navigation aid for those, and a sidebar entry would be a
332 // duplicate path to the same place. Users still reach those
333 // via the "Settings →" link on the addon card.
334 if (class_exists('\\EasyInvoice\\Addons\\AddonRegistry') && class_exists('\\EasyInvoice\\Addons\\AddonManager')):
335 foreach (\EasyInvoice\Addons\AddonRegistry::all() as $ei_addon):
336 if (empty($ei_addon['settings_url'])) continue;
337 if (!\EasyInvoice\Addons\AddonManager::isEnabled($ei_addon['id'])) continue;
338 if (!\EasyInvoice\Addons\AddonManager::userCanAccess($ei_addon['id'])) continue;
339
340 // Skip addons whose settings_url deep-links into the
341 // main Settings page (easy-invoice-settings). Those
342 // are accessed via the card's "Settings →" link only.
343 $ei_addon_parsed = wp_parse_url($ei_addon['settings_url']);
344 $ei_addon_query = [];
345 if (!empty($ei_addon_parsed['query'])) {
346 parse_str($ei_addon_parsed['query'], $ei_addon_query);
347 }
348 $ei_addon_slug = $ei_addon_query['page'] ?? '';
349 if ($ei_addon_slug === 'easy-invoice-settings') continue;
350
351 $ei_addon_active = ($current_page === $ei_addon_slug);
352 $ei_addon_icon = !empty($ei_addon['icon']) ? $ei_addon['icon'] : 'dashicons-admin-plugins';
353 $ei_addon_label = !empty($ei_addon['short_name']) ? $ei_addon['short_name'] : $ei_addon['name'];
354 ?>
355 <a href="<?php echo esc_url($ei_addon['settings_url']); ?>"
356 class="<?php echo $ei_addon_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200"
357 title="<?php echo esc_attr($ei_addon['name']); ?>">
358 <span class="dashicons <?php echo esc_attr($ei_addon_icon); ?> mr-3 flex-shrink-0 h-5 w-5 <?php echo $ei_addon_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?>" style="font-size:20px;width:20px;height:20px;line-height:20px;"></span>
359 <span class="flex-1 truncate"><?php echo esc_html($ei_addon_label); ?></span>
360 </a>
361 <?php
362 endforeach;
363 endif;
364 ?>
365
366
367 <a href="<?php echo admin_url('admin.php?page=easy-invoice-addons'); ?>"
368 class="<?php echo $is_addons_active ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
369 <svg class="<?php echo $is_addons_active ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
370 <rect x="3" y="3" width="7" height="7" rx="1" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
371 <rect x="14" y="3" width="7" height="7" rx="1" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
372 <rect x="3" y="14" width="7" height="7" rx="1" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
373 <path d="M17.5 14V21M14 17.5H21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
374 </svg>
375 <span class="flex-1"><?php esc_html_e('Addons', 'easy-invoice'); ?></span>
376 <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-indigo-100 text-indigo-700">
377 <?php esc_html_e('New', 'easy-invoice'); ?>
378 </span>
379 </a>
380
381
382 <a href="<?php echo esc_url('https://www.facebook.com/groups/mantrabraincommunity'); ?>"
383 target="_blank"
384 rel="noopener noreferrer"
385 class="<?php echo ($current_page === 'easy-invoice-join-community') ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-indigo-50 hover:text-indigo-700'; ?> group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
386 <svg class="<?php echo ($current_page === 'easy-invoice-join-community') ? 'text-indigo-600' : 'text-gray-400 group-hover:text-indigo-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
387 <path d="M18 2H15C13.6739 2 12.4021 2.52678 11.4645 3.46447C10.5268 4.40215 10 5.67392 10 7V10H7V14H10V22H14V14H17L18 10H14V7C14 6.73478 14.1054 6.48043 14.2929 6.29289C14.4804 6.10536 14.7348 6 15 6H18V2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
388 </svg>
389 <span class="flex-1"><?php esc_html_e('Join Community', 'easy-invoice'); ?></span>
390 <svg class="flex-shrink-0 h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
391 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/>
392 </svg>
393 </a>
394
395
396 <a href="<?php echo esc_url('https://easy-invoice.matrixaddons.com/docs/'); ?>"
397 target="_blank"
398 rel="noopener noreferrer"
399 class="text-gray-600 hover:bg-indigo-50 hover:text-indigo-700 group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200">
400 <svg class="text-gray-400 group-hover:text-indigo-500 mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
401 <path d="M4 19.5V4.5C4 3.4 4.9 2.5 6 2.5H19C19.5 2.5 20 3 20 3.5V20.5C20 21 19.5 21.5 19 21.5H6C4.9 21.5 4 20.6 4 19.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
402 <path d="M8 7H16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
403 <path d="M8 11H16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
404 <path d="M8 15H13" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
405 </svg>
406 <span class="flex-1"><?php esc_html_e('Documentation', 'easy-invoice'); ?></span>
407 <svg class="flex-shrink-0 h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
408 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/>
409 </svg>
410 </a>
411
412 </nav>
413
414
415 <div class="ei-app-sidebar-foot border-t border-gray-200 p-4 flex-shrink-0 bg-white">
416 <div class="relative">
417 <button type="button" id="user-dropdown-button" class="flex items-center w-full text-left hover:bg-gray-50 rounded-lg p-2 transition-colors duration-200">
418 <div class="flex-shrink-0">
419 <div class="h-8 w-8 rounded-full bg-gray-200 flex items-center justify-center">
420 <span class="text-gray-600 font-medium text-sm"><?php echo substr(wp_get_current_user()->display_name, 0, 1); ?></span>
421 </div>
422 </div>
423 <div class="ml-3 flex-1">
424 <p class="text-sm font-medium text-gray-700"><?php echo esc_html(wp_get_current_user()->display_name); ?></p>
425 <p class="text-xs text-gray-500"><?php echo esc_html(wp_get_current_user()->user_email); ?></p>
426 </div>
427 <div class="flex-shrink-0">
428 <svg class="h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
429 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
430 </svg>
431 </div>
432 </button>
433
434
435 <div id="user-dropdown-menu" class="hidden absolute bottom-full left-0 right-0 mb-2 bg-white border border-gray-200 rounded-lg shadow-lg z-50">
436 <div class="py-1">
437 <a href="<?php echo admin_url(); ?>" target="_blank" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors duration-200">
438 <svg class="mr-3 h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
439 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path>
440 </svg>
441 <?php _e('Back to WordPress', 'easy-invoice'); ?>
442 </a>
443 <a href="<?php echo wp_logout_url(); ?>" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors duration-200">
444 <svg class="mr-3 h-4 w-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
445 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path>
446 </svg>
447 <?php _e('Logout', 'easy-invoice'); ?>
448 </a>
449 </div>
450 </div>
451 </div>
452 </div>
453 </div>
454
455 <div class="fixed top-0 left-0 z-50 p-4 sm:hidden">
456 <button type="button" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500" aria-expanded="false" aria-label="<?php echo esc_attr__( 'Open menu', 'easy-invoice' ); ?>">
457 <svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
458 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
459 </svg>
460 </button>
461 </div>
462
463 <script>
464 document.addEventListener('DOMContentLoaded', function() {
465 const mobileMenuButton = document.querySelector('button[aria-expanded="false"]');
466 const sidebar = document.querySelector('.fixed.inset-y-0.left-0');
467
468 if (mobileMenuButton && sidebar) {
469 mobileMenuButton.addEventListener('click', function() {
470 const expanded = this.getAttribute('aria-expanded') === 'true';
471 this.setAttribute('aria-expanded', !expanded);
472 sidebar.classList.toggle('hidden');
473 });
474 }
475
476 // Handle Reports menu click for premium feature
477 const reportsMenuLink = document.getElementById('reports-menu-link');
478 if (reportsMenuLink) {
479 reportsMenuLink.addEventListener('click', function(e) {
480 e.preventDefault();
481 // Show premium popup using the proper confirmation modal
482 if (typeof EasyInvoiceConfirmation !== 'undefined') {
483 EasyInvoiceConfirmation.showFeatureUpgrade(
484 <?php echo wp_json_encode( __( 'Detailed Reports', 'easy-invoice' ) ); ?>,
485 <?php echo wp_json_encode( __( 'Get comprehensive insights into your business with detailed reports including revenue analysis, payment statistics, invoice status tracking, and monthly revenue charts. Upgrade to Easy Invoice Pro to unlock advanced reporting features.', 'easy-invoice' ) ); ?>
486 );
487 } else {
488 // Fallback to alert if confirmation modal is not available
489 alert('<?php echo esc_js(__('Detailed Reports is a premium feature. Upgrade to Easy Invoice Pro to unlock advanced reporting features including revenue analysis, payment statistics, and monthly revenue charts.', 'easy-invoice')); ?>');
490 }
491 });
492 }
493
494 // Handle user dropdown
495 const userDropdownButton = document.getElementById('user-dropdown-button');
496 const userDropdownMenu = document.getElementById('user-dropdown-menu');
497
498 if (userDropdownButton && userDropdownMenu) {
499 userDropdownButton.addEventListener('click', function(e) {
500 e.preventDefault();
501 e.stopPropagation();
502 userDropdownMenu.classList.toggle('hidden');
503 });
504
505 // Close dropdown when clicking outside
506 document.addEventListener('click', function(e) {
507 if (!userDropdownButton.contains(e.target) && !userDropdownMenu.contains(e.target)) {
508 userDropdownMenu.classList.add('hidden');
509 }
510 });
511
512 // Close dropdown when pressing Escape key
513 document.addEventListener('keydown', function(e) {
514 if (e.key === 'Escape') {
515 userDropdownMenu.classList.add('hidden');
516 }
517 });
518 }
519 });
520 </script>
521
522 <style>
523 html.wp-toolbar {
524 padding-top: 0 !important;
525 }
526 /* Matches hideAdminUi: hidden admin bar must not reserve body padding or main content shifts vs fixed sidebar */
527 body.easy-invoice-admin-body.admin-bar {
528 padding-top: 0 !important;
529 }
530 body.easy-invoice-admin-body.admin-bar #wpbody,
531 body.easy-invoice-admin-body.admin-bar #wpbody-content {
532 padding-top: 0 !important;
533 }
534
535 /* Full-height app shell — works WITH the global
536 `#wpbody-content { display: flex; flex-direction: column; min-height: 100vh }`
537 rule defined in easy-invoice.css. Because the parent is a flex
538 column, the wrapper can't rely on `height: 100%` alone (flex
539 children stay at content height unless given `flex-grow`). We give
540 the wrapper `flex: 1` so it expands to fill whatever vertical space
541 the flex column offers, and a `min-height: 100vh` floor so short
542 pages still paint the bg-gray-50 all the way down to the viewport
543 bottom. Removing the previous html → body → wpwrap → wpcontent
544 chain that wasn't doing anything useful in the flex-column world. */
545 .easy-invoice-admin {
546 flex: 1;
547 min-height: 100vh;
548 }
549
550 /* Custom color for active icons */
551 .group:hover svg {
552 color: rgb(79 70 229) !important;
553 }
554
555 /* Active state icon color */
556 .bg-indigo-50 svg {
557 color: rgb(79 70 229) !important;
558 }
559
560 /* Hover state for non-active items */
561 .group:hover:not(.bg-indigo-50) svg {
562 color: rgb(79 70 229) !important;
563 }
564
565 /* Sidebar scrollbar — slim, only visible on hover/scroll. Firefox uses scrollbar-* */
566 .ei-app-sidebar-nav {
567 scrollbar-width: thin;
568 scrollbar-color: rgba(156, 163, 175, 0) transparent;
569 transition: scrollbar-color 0.2s ease;
570 }
571 .ei-app-sidebar-nav:hover {
572 scrollbar-color: rgba(156, 163, 175, 0.5) transparent;
573 }
574 /* WebKit (Chrome / Safari / Edge) */
575 .ei-app-sidebar-nav::-webkit-scrollbar {
576 width: 8px;
577 }
578 .ei-app-sidebar-nav::-webkit-scrollbar-track {
579 background: transparent;
580 }
581 .ei-app-sidebar-nav::-webkit-scrollbar-thumb {
582 background-color: transparent;
583 border-radius: 4px;
584 border: 2px solid transparent;
585 background-clip: content-box;
586 transition: background-color 0.2s ease;
587 }
588 .ei-app-sidebar-nav:hover::-webkit-scrollbar-thumb {
589 background-color: rgba(156, 163, 175, 0.45);
590 }
591 .ei-app-sidebar-nav::-webkit-scrollbar-thumb:hover {
592 background-color: rgba(107, 114, 128, 0.7);
593 }
594 </style>
595
596 <div class="min-h-screen bg-white easy-invoice-admin">
597 <a href="#easy-invoice-main" class="easy-invoice-skip-link screen-reader-text"><?php esc_html_e( 'Skip to main content', 'easy-invoice' ); ?></a>
598
599 <div id="easy-invoice-main" class="pl-64" tabindex="-1">
600 <?php
601
602 $page = isset($_GET['page']) ? sanitize_text_field($_GET['page']) : 'easy-invoice';
603 // Content will be inserted here
604 do_action('easy_invoice_admin_before_main_content', $page);
605
606 do_action('easy_invoice_admin_main_content', $page);
607
608 do_action('easy_invoice_admin_after_main_content', $page);
609
610 ?>
611 </div>
612
613
614 <script>
615 if (typeof ajaxurl === 'undefined') {
616 var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
617 }
618 </script>
619 </div>
620