PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.1.19
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.1.19
2.4.3 2.4.4 2.4.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 All 60 releases
easy-invoice / templates / settings-page.php

settings-page.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.1.19, at templates/settings-page.php

1,180 lines 105.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Settings page template for Easy Invoice
4 *
5 * @package Easy_Invoice
6 * @since 1.0.0
7 */
8
9 // Exit if accessed directly
10 if (!defined('ABSPATH')) {
11 exit;
12 }
13
14 /**
15 * Helper function to render a single settings field.
16 *
17 * @param string $option_key The option key.
18 * @param array $field_config The field configuration.
19 * @param mixed $current_value The current value of the field.
20 */
21 function easy_invoice_render_field($option_key, $field_config, $current_value) {
22 $label = esc_html($field_config['label'] ?? '');
23 $type = $field_config['type'] ?? 'text';
24 $default = $field_config['default'] ?? '';
25 $value = $current_value ?? $default;
26 $description_text = $field_config['description'] ?? '';
27 $field_id = esc_attr($option_key);
28 $field_name = 'settings[' . esc_attr($option_key) . ']';
29 $col_span_class = esc_attr($field_config['col_span'] ?? 'sm:col-span-6');
30 $placeholder = isset($field_config['placeholder']) ? esc_attr($field_config['placeholder']) : '';
31 $required = !empty($field_config['required']) ? 'required' : '';
32 $aria_describedby = !empty($description_text) ? 'aria-describedby="' . $field_id . '-description"' : '';
33
34 echo '<div class=" ' . $col_span_class . '">'; // Added 'form-group' class for JS show/hide functionality
35
36 // Special layout for checkboxes with descriptions (e.g., Invoice Numbering type)
37 if ($type === 'checkbox' && !empty($description_text) && ($option_key === 'easy_invoice_invoice_numbering')) {
38 echo '<div class="flex items-start space-x-3 p-4 bg-gray-50 rounded-lg border border-gray-200">';
39 echo ' <div class="flex items-center h-5 mt-0.5">';
40 echo ' <input type="checkbox" name="' . $field_name . '" id="' . $field_id . '" value="yes" ' . checked($value, 'yes', false) . ' class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" ' . $required . '>';
41 echo ' </div>';
42 echo ' <div class="flex-1">';
43 echo ' <label for="' . $field_id . '" class="block text-sm font-medium text-gray-700 mb-1">' . $label . '</label>';
44 echo ' <p id="' . $field_id . '-description" class="text-sm text-gray-400 leading-relaxed">' . wp_kses($description_text, array(
45 'a' => array(
46 'href' => array(),
47 'target' => array(),
48 'class' => array()
49 )
50 )) . '</p>';
51 echo ' </div>';
52 echo '</div>';
53 } else {
54 // Standard label for other types, or checkboxes without the special description structure
55 if ($type !== 'checkbox') {
56 echo '<label for="' . $field_id . '" class="block text-sm font-medium text-gray-700 mb-2">' . $label . '</label>';
57 }
58
59 $input_class = 'mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm';
60 $select_class = 'mt-1 block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md';
61
62
63 switch ($type) {
64 case 'text':
65 case 'email':
66 case 'url':
67 case 'tel':
68 echo '<input type="' . esc_attr($type) . '" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '" class="' . $input_class . '" placeholder="' . $placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
69 break;
70 case 'number':
71 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
72 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
73 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
74 echo '<input type="number" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '"' . $min . $max . $step . ' class="' . $input_class . '" placeholder="' . $placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
75 break;
76 case 'textarea':
77 echo '<textarea id="' . $field_id . '" name="' . $field_name . '" rows="3" class="' . $input_class . '" placeholder="' . $placeholder . '" ' . $required . ' ' . $aria_describedby . '>' . wp_kses_post($value) . '</textarea>';
78 break;
79 case 'select':
80 echo '<select id="' . $field_id . '" name="' . $field_name . '" class="' . $select_class . '" ' . $required . ' ' . $aria_describedby . '>';
81 if (!empty($field_config['options']) && is_array($field_config['options'])) {
82 foreach ($field_config['options'] as $opt_val => $opt_label) {
83 echo '<option value="' . esc_attr($opt_val) . '" ' . selected($value, $opt_val, false) . '>' . esc_html($opt_label) . '</option>';
84 }
85 }
86 echo '</select>';
87 break;
88 case 'multiselect':
89 echo '<select id="' . $field_id . '" name="' . $field_name . '[]" class="' . $select_class . '" multiple="multiple" aria-label="' . esc_attr($label) . '">';
90 if (!empty($field_config['options']) && is_array($field_config['options'])) {
91 foreach ($field_config['options'] as $opt_val => $opt_label) {
92 $selected = is_array($value) && in_array($opt_val, $value) ? 'selected="selected"' : '';
93 echo '<option value="' . esc_attr($opt_val) . '" ' . $selected . '>' . esc_html($opt_label) . '</option>';
94 }
95 }
96 echo '</select>';
97 break;
98 case 'readonly':
99 echo '<input type="text" id="' . $field_id . '" value="' . esc_attr($value) . '" class="' . $input_class . ' bg-gray-50" readonly ' . $aria_describedby . '>';
100 echo '<input type="hidden" name="' . $field_name . '" value="' . esc_attr($value) . '">';
101 break;
102 case 'checkbox': // Checkboxes that don't use the special description layout
103 echo '<div class="flex items-center">'; // Original 'tax_enabled' was just this simple structure
104 echo ' <input type="checkbox" name="' . $field_name . '" id="' . $field_id . '" value="yes" ' . checked($value, 'yes', false) . ' class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded" ' . $required . ' ' . $aria_describedby . '>';
105 echo ' <label for="' . $field_id . '" class="ml-2 block text-sm text-gray-900">' . $label . '</label>';
106 echo '</div>';
107 if (!empty($description_text)) { // Show description below the field
108 echo '<p id="' . $field_id . '-description" class="mt-2 text-sm text-gray-400 leading-relaxed">' . wp_kses($description_text, array(
109 'a' => array(
110 'href' => array(),
111 'target' => array(),
112 'class' => array()
113 )
114 )) . '</p>';
115 }
116 break;
117 case 'image':
118 echo '<div class="mt-1 flex items-center">';
119 echo ' <span class="inline-block h-12 w-12 rounded-full overflow-hidden bg-gray-100">';
120 echo ' <img id="' . $field_id . '-preview" src="' . esc_url($value) . '" alt="' . esc_attr($label) . '" class="h-full w-full object-cover' . (empty($value) ? ' hidden' : '') . '">';
121 echo ' </span>';
122 echo ' <button type="button" id="upload_image_button_' . $field_id . '" class="upload-logo-button ml-5 bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" data-uploader_title="' . esc_attr__('Choose Logo', 'easy-invoice') . '" data-uploader_button_text="' . esc_attr__('Select Logo', 'easy-invoice') . '">';
123 echo esc_html__('Change', 'easy-invoice');
124 echo '</button>';
125 echo ' <input type="hidden" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '" ' . $required . ' ' . $aria_describedby . '>';
126 echo '</div>';
127 break;
128 case 'wp_editor':
129 // For wp_editor, the label is usually handled before calling it.
130 // The col_span div wraps this.
131 wp_editor( $value, $field_id, ['textarea_name' => $field_name, 'teeny' => true, 'media_buttons' => false, 'textarea_rows' => 7, 'editor_class' => 'mt-1'] );
132 // Handle description for wp_editor specifically
133 if (!empty($description_text)) {
134 echo '<p id="' . $field_id . '-description" class="mt-1 text-sm text-gray-400">' . wp_kses($description_text, array(
135 'a' => array(
136 'href' => array(),
137 'target' => array(),
138 'class' => array()
139 )
140 )) . '</p>';
141 }
142 break;
143 case 'test_email':
144 echo '<div class="mt-1">';
145 echo ' <div class="flex items-center space-x-3">';
146 echo ' <input type="email" id="' . $field_id . '_email" placeholder="' . esc_attr__('Enter email address to test', 'easy-invoice') . '" class="mt-1 block w-[200px] border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" value="' . esc_attr(get_option('admin_email')) . '">';
147 echo ' <button type="button" id="' . $field_id . '_button" class="test-email-button inline-flex items-center px-3 py-1.5 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 h-[38px]">';
148 echo ' <i class="fas fa-paper-plane mr-2" aria-hidden="true"></i>';
149 echo ' ' . esc_html__('Send Test Email', 'easy-invoice');
150 echo ' </button>';
151 echo ' </div>';
152 echo ' <div id="' . $field_id . '_result" class="mt-2" style="display: none;"></div>';
153 echo '</div>';
154 break;
155 case 'color':
156 echo '<input type="color" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '" class="h-10 w-20 border border-gray-300 rounded">';
157 break;
158 case 'range':
159 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
160 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
161 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
162 echo '<input type="range" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '"' . $min . $max . $step . ' class="w-full">';
163 echo '<span class="text-sm text-gray-400">' . esc_html($value) . '%</span>';
164 break;
165 case 'button':
166 $button_text = $field_config['button_text'] ?? $label;
167 $button_class = $field_config['button_class'] ?? 'button button-secondary';
168 $button_class_name = 'regenerate-invoice-numbers-button';
169 if ($option_key === 'easy_invoice_regenerate_quote_numbers') {
170 $button_class_name = 'regenerate-quote-numbers-button';
171 }
172 echo '<button type="button" id="' . $field_id . '" class="' . esc_attr($button_class) . ' ' . $button_class_name . '">';
173 echo esc_html($button_text);
174 echo '</button>';
175 break;
176 case 'image_upload':
177 echo '<div class="image-upload-wrap">';
178 echo '<div class="flex items-center space-x-3">';
179 echo ' <input type="hidden" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '">';
180 echo ' <button type="button" class="upload-image-button bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" data-target="' . $field_id . '">';
181 echo esc_html__('Upload Image', 'easy-invoice');
182 echo '</button>';
183 echo '</div>';
184 echo '<div class="image-preview mt-2' . (empty($value) ? ' hidden' : '') . '">';
185 if (!empty($value)) {
186 echo '<img src="' . esc_url($value) . '" alt="Preview" style="max-width: 200px; max-height: 100px;">';
187 }
188 echo '</div>';
189 echo '</div>';
190 break;
191 default:
192 // Special handling for regenerate invoice numbers button
193 if ($option_key === 'easy_invoice_regenerate_invoice_numbers') {
194 $button_text = $field_config['button_text'] ?? $label;
195 $button_class = $field_config['button_class'] ?? 'button button-secondary';
196 echo '<button type="button" id="' . $field_id . '" class="' . esc_attr($button_class) . ' regenerate-invoice-numbers-button">';
197 echo esc_html($button_text);
198 echo '</button>';
199 } elseif ($option_key === 'easy_invoice_regenerate_quote_numbers') {
200 $button_text = $field_config['button_text'] ?? $label;
201 $button_class = $field_config['button_class'] ?? 'button button-secondary';
202 echo '<button type="button" id="' . $field_id . '" class="' . esc_attr($button_class) . ' regenerate-quote-numbers-button">';
203 echo esc_html($button_text);
204 echo '</button>';
205 } else {
206 echo '<input type="text" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($value) . '" class="' . $input_class . '" placeholder="' . $placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
207 }
208 break;
209 }
210 // General description for non-checkbox and non-wp_editor fields (if it exists and not handled by special layouts)
211 if ($type !== 'checkbox' && $type !== 'wp_editor' && !empty($description_text)) {
212 echo '<p id="' . $field_id . '-description" class="mt-1 text-sm text-gray-400">' . wp_kses($description_text, array(
213 'a' => array(
214 'href' => array(),
215 'target' => array(),
216 'class' => array()
217 )
218 )) . '</p>';
219 }
220 }
221 echo '</div>'; // End col_span div
222 }
223
224 /**
225 * Filter settings config to allow extensions to modify it
226 * Note: This filter is already applied in the controller, so this is redundant
227 */
228 // $settings_config = apply_filters('easy_invoice_settings_fields_config', $settings_config);
229
230 $active_section = $_GET['section'] ?? key($settings_config);
231 if (!isset($settings_config[$active_section])) {
232 $active_section = key($settings_config);
233 }
234 ?>
235
236 <div class="p-8">
237 <!-- Header with Actions -->
238 <div class="ei-app-page-header bg-white border-b border-gray-200 px-6 easy-invoice-admin-page-header">
239 <div class="flex items-center justify-between">
240 <div>
241 <h1 class="text-2xl font-bold text-gray-900"><?php esc_html_e('Settings', 'easy-invoice'); ?></h1>
242 <p class="mt-1 text-sm text-gray-400"><?php esc_html_e('Configure your invoice management system', 'easy-invoice'); ?></p>
243 </div>
244 <div class="flex items-center space-x-3">
245 <button type="button" id="save-settings" class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" aria-label="<?php esc_attr_e('Save Settings', 'easy-invoice'); ?>">
246 <i class="fas fa-save mr-2" aria-hidden="true"></i>
247 <?php esc_html_e('Save Changes', 'easy-invoice'); ?>
248 </button>
249 </div>
250 </div>
251 </div>
252
253 <!-- Main Content -->
254 <div class="max-w-7xl mx-auto">
255 <div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mt-8">
256 <!-- Left Sidebar - Navigation -->
257 <div class="lg:col-span-1">
258 <div class="bg-white shadow-lg rounded-lg sticky top-24 border border-gray-200">
259 <nav class="space-y-2 p-4" aria-label="<?php esc_attr_e('Settings Navigation', 'easy-invoice'); ?>">
260 <?php foreach ($settings_config as $section_id => $section_data) : ?>
261 <div class="space-y-1">
262 <a href="?page=easy-invoice-settings&section=<?php echo esc_attr($section_id); ?>"
263 class="nav-link group flex items-center px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200 <?php echo ($section_id === $active_section) ? 'bg-indigo-50 text-indigo-700 border-r-2 border-indigo-600' : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'; ?>"
264 aria-selected="<?php echo $section_id === $active_section ? 'true' : 'false'; ?>"
265 role="tab">
266
267 <?php if ($section_id === 'company'): ?>
268 <svg class="<?php echo ($section_id === $active_section) ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
269 <path d="M3 9L12 2L21 9V20C21 20.5304 20.7893 21.0391 20.4142 21.4142C20.0391 21.7893 19.5304 22 19 22H5C4.46957 22 3.96086 21.7893 3.58579 21.4142C3.21071 21.0391 3 20.5304 3 20V9Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
270 <polyline points="9,22 9,12 15,12 15,22" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
271 </svg>
272 <?php elseif ($section_id === 'invoice'): ?>
273 <svg class="<?php echo ($section_id === $active_section) ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
274 <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"/>
275 <path d="M14 2V8H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
276 <path d="M16 13H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
277 <path d="M16 17H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
278 <path d="M10 9H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
279 </svg>
280 <?php elseif ($section_id === 'quote'): ?>
281 <svg class="<?php echo ($section_id === $active_section) ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
282 <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"/>
283 <path d="M14 2V8H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
284 <path d="M9 9H15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
285 <path d="M9 13H15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
286 <path d="M9 17H13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
287 </svg>
288 <?php elseif ($section_id === 'currency'): ?>
289 <svg class="<?php echo ($section_id === $active_section) ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
290 <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
291 <path d="M12 1V23" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
292 <path d="M17 5H9.5C8.57174 5 7.6815 5.36875 7.02513 6.02513C6.36875 6.6815 6 7.57174 6 8.5C6 9.42826 6.36875 10.3185 7.02513 10.9749C7.6815 11.6313 8.57174 12 9.5 12H14.5C15.4283 12 16.3185 12.3687 16.9749 13.0251C17.6313 13.6815 18 14.5717 18 15.5C18 16.4283 17.6313 17.3185 16.9749 17.9749C16.3185 18.6313 15.4283 19 14.5 19H6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
293 </svg>
294 <?php elseif ($section_id === 'tax'): ?>
295 <svg class="<?php echo ($section_id === $active_section) ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
296 <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
297 <path d="M8 14L16 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
298 <path d="M8 8L16 14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
299 <path d="M12 6V18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
300 </svg>
301 <?php elseif ($section_id === 'payment'): ?>
302 <svg class="<?php echo ($section_id === $active_section) ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
303 <rect x="1" y="4" width="22" height="16" rx="2" ry="2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
304 <line x1="1" y1="10" x2="23" y2="10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
305 </svg>
306 <?php elseif ($section_id === 'email'): ?>
307 <svg class="<?php echo ($section_id === $active_section) ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
308 <path d="M4 4H20C21.1 4 22 4.9 22 6V18C22 19.1 21.1 20 20 20H4C2.9 20 2 19.1 2 18V6C2 4.9 2.9 4 4 4Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
309 <polyline points="22,6 12,13 2,6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
310 </svg>
311 <?php elseif ($section_id === 'advanced'): ?>
312 <svg class="<?php echo ($section_id === $active_section) ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
313 <circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
314 <path d="M19.4 15A1.65 1.65 0 0 0 18 14A6 6 0 0 0 6 14A1.65 1.65 0 0 0 4.6 15A2 2 0 0 0 6 19H18A2 2 0 0 0 19.4 15Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
315 </svg>
316 <?php elseif ($section_id === 'text_settings'): ?>
317 <svg class="<?php echo ($section_id === $active_section) ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
318 <path d="M4 7V4C4 3.44772 4.44772 3 5 3H19C19.5523 3 20 3.44772 20 4V7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
319 <path d="M4 7V20C4 20.5523 4.44772 21 5 21H19C19.5523 21 20 20.5523 20 20V7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
320 <path d="M8 11H16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
321 <path d="M8 15H12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
322 <path d="M8 19H14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
323 <path d="M12 11L14 13L12 15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
324 </svg>
325 <?php else: ?>
326 <svg class="<?php echo ($section_id === $active_section) ? 'text-indigo-600' : 'text-gray-400 group-hover:text-gray-500'; ?> mr-3 flex-shrink-0 h-5 w-5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
327 <circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
328 <path d="M19.4 15A1.65 1.65 0 0 0 18 14A6 6 0 0 0 6 14A1.65 1.65 0 0 0 4.6 15A2 2 0 0 0 6 19H18A2 2 0 0 0 19.4 15Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
329 </svg>
330 <?php endif; ?>
331
332 <span class="flex-1"><?php echo esc_html($section_data['title']); ?></span>
333 <?php if ($section_id === 'email' && !empty($section_data['subsections'])): ?>
334 <svg class="flex-shrink-0 h-4 w-4 text-gray-400 group-hover:text-gray-500 transition-transform duration-200" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
335 <polyline points="6,9 12,15 18,9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
336 </svg>
337 <?php endif; ?>
338 </a>
339
340 <?php if ($section_id === 'email' && !empty($section_data['subsections'])): ?>
341 <div class="ml-6 space-y-1 email-settings-submenu" style="display: none;">
342 <?php
343 // Only show active subsection if we're actually on an email settings page
344 $active_email_subsection = null;
345 if ($active_section === 'email') {
346 if (isset($_GET['subsection']) && isset($section_data['subsections'][$_GET['subsection']])) {
347 $active_email_subsection = $_GET['subsection'];
348 } elseif (!empty($_GET['subsection']) && isset($section_data['subsections'][$_GET['subsection']])) {
349 $active_email_subsection = $_GET['subsection'];
350 } else {
351 // Default to 'general' only if we're on email section but no specific subsection
352 $active_email_subsection = 'general';
353 }
354 }
355 ?>
356 <?php foreach ($section_data['subsections'] as $subsection_id => $subsection_data): ?>
357 <?php $is_active_subsection = ($active_email_subsection && $subsection_id === $active_email_subsection); ?>
358 <a href="?page=easy-invoice-settings&section=email&subsection=<?php echo esc_attr($subsection_id); ?>"
359 class="email-submenu-link group flex items-center px-3 py-2 text-sm font-medium rounded-md transition-all duration-200 <?php echo $is_active_subsection ? 'text-indigo-700 bg-indigo-50 border-l-2 border-indigo-500' : 'text-gray-500 hover:text-gray-700 hover:bg-gray-50'; ?>"
360 data-subsection="<?php echo esc_attr($subsection_id); ?>"
361 data-section="<?php echo esc_attr($section_id); ?>">
362 <svg class="mr-2 flex-shrink-0 h-4 w-4 <?php echo $is_active_subsection ? 'text-indigo-500' : 'text-gray-400 group-hover:text-gray-500'; ?>" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
363 <polyline points="9,18 15,12 9,6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
364 </svg>
365 <?php
366 // Display shorter names for better UX
367 $display_name = '';
368 switch ($subsection_id) {
369 case 'general':
370 $display_name = 'General';
371 break;
372 case 'invoice_available':
373 $display_name = 'Invoice Available';
374 break;
375 case 'quote_available':
376 $display_name = 'Quote Available';
377 break;
378 case 'payment_received':
379 $display_name = 'Payment Received';
380 break;
381 default:
382 $display_name = $subsection_data['title'];
383 break;
384 }
385 echo esc_html($display_name);
386 ?>
387 </a>
388 <?php endforeach; ?>
389 </div>
390 <?php endif; ?>
391 </div>
392 <?php endforeach; ?>
393 </nav>
394 </div>
395 </div>
396
397 <!-- Right Content - Settings -->
398 <div class="lg:col-span-2">
399 <form id="settings-form" method="post" action="">
400 <?php wp_nonce_field('easy_invoice_settings', 'easy_invoice_settings_nonce'); ?>
401 <input type="hidden" name="action" value="easy_invoice_save_settings">
402
403 <?php foreach ($settings_config as $section_id => $section_data) : ?>
404 <div id="<?php echo esc_attr($section_id); ?>"
405 class="settings-section bg-white shadow rounded-lg <?php echo ($section_id !== $active_section) ? 'hidden' : ''; ?>"
406 role="tabpanel"
407 aria-labelledby="tab-<?php echo esc_attr($section_id); ?>">
408 <div class="px-6 py-5 border-b border-gray-200">
409 <div class="flex items-center">
410 <div class="flex-shrink-0 bg-indigo-100 rounded-lg p-3">
411 <?php if (isset($section_data['icon']) && !empty($section_data['icon'])): ?>
412 <?php if (strpos($section_data['icon'], '<svg') === 0): ?>
413 <?php echo $section_data['icon']; ?>
414 <?php else: ?>
415 <i class="<?php echo esc_attr($section_data['icon']); ?> text-indigo-600 text-xl"></i>
416 <?php endif; ?>
417 <?php else: ?>
418 <svg class="text-indigo-600 text-xl h-6 w-6" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
419 <circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
420 <path d="M19.4 15A1.65 1.65 0 0 0 18 14A6 6 0 0 0 6 14A1.65 1.65 0 0 0 4.6 15A2 2 0 0 0 6 19H18A2 2 0 0 0 19.4 15Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
421 </svg>
422 <?php endif; ?>
423 </div>
424 <div class="ml-4">
425 <h2 class="text-lg font-medium text-gray-900"><?php echo esc_html($section_data['title']); ?></h2>
426 <p class="mt-1 text-sm text-gray-400"><?php echo esc_html($section_data['description']); ?></p>
427 </div>
428 </div>
429 </div>
430 <div class="px-6 py-5">
431 <div class="email-settings">
432 <?php if ($section_id === 'email' && !empty($section_data['subsections'])): ?>
433 <?php
434 // Determine the active subsection from the hash or default to 'general'
435 $active_email_subsection = 'general';
436 if (isset($_GET['subsection']) && isset($section_data['subsections'][$_GET['subsection']])) {
437 $active_email_subsection = $_GET['subsection'];
438 } elseif (!empty($_GET['subsection']) && isset($section_data['subsections'][$_GET['subsection']])) {
439 $active_email_subsection = $_GET['subsection'];
440 }
441 if (!isset($section_data['subsections'][$active_email_subsection])) {
442 $active_email_subsection = array_key_first($section_data['subsections']);
443 }
444 $subsection_data = $section_data['subsections'][$active_email_subsection];
445 ?>
446 <?php
447 // Render all email subsections so JS can show/hide them
448 foreach ($section_data['subsections'] as $subsection_key => $subsection_data) {
449 $is_active = ($subsection_key === $active_email_subsection) ? '' : 'hidden';
450 ?>
451 <div id="email--<?php echo esc_attr($subsection_key); ?>-content" class="email-subsection-content <?php echo $is_active; ?>">
452 <?php
453 // Display subsection title
454 $subsection_title = '';
455 switch ($subsection_key) {
456 case 'general':
457 $subsection_title = 'General Email Settings';
458 break;
459 case 'invoice_available':
460 $subsection_title = 'Invoice Available Email Settings';
461 break;
462 case 'quote_available':
463 $subsection_title = 'Quote Available Email Settings';
464 break;
465 case 'payment_received':
466 $subsection_title = 'Payment Received Email Settings';
467 break;
468 default:
469 $subsection_title = $subsection_data['title'];
470 break;
471 }
472 ?>
473 <div class="mb-6">
474 <h3 class="text-lg font-medium text-gray-900 mb-2"><?php echo esc_html($subsection_title); ?></h3>
475 <?php if (!empty($subsection_data['description'])): ?>
476 <p class="text-sm text-gray-400"><?php echo esc_html($subsection_data['description']); ?></p>
477 <?php endif; ?>
478 </div>
479 <div class="space-y-6">
480 <?php if (!empty($subsection_data['fields'])) {
481 foreach ($subsection_data['fields'] as $option_key => $field_config) {
482 $current_value = $settings[$option_key] ?? ($field_config['default'] ?? '');
483 $field_id = esc_attr($option_key);
484 $field_type = $field_config['type'] ?? 'text';
485 $field_label = esc_html($field_config['label'] ?? '');
486 $field_placeholder = isset($field_config['placeholder']) ? esc_attr($field_config['placeholder']) : '';
487 $field_description = $field_config['description'] ?? '';
488 $field_name = 'settings[' . esc_attr($option_key) . ']';
489 $input_class = 'mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm';
490 $select_class = 'mt-1 block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md';
491 $col_span_class = esc_attr($field_config['col_span'] ?? 'sm:col-span-6');
492 echo '<div class="field-wrapper form-group">';
493 if ($field_type !== 'checkbox') {
494 echo '<label for="' . $field_id . '" class="block text-sm font-medium text-gray-700">' . $field_label . '</label>';
495 }
496
497 // Define required and aria_describedby variables
498 $required = !empty($field_config['required']) ? 'required' : '';
499 $aria_describedby = !empty($field_description) ? 'aria-describedby="' . $field_id . '-description"' : '';
500
501 switch ($field_type) {
502 case 'text':
503 case 'email':
504 case 'url':
505 case 'tel':
506 echo '<input type="' . esc_attr($field_type) . '" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
507 break;
508 case 'number':
509 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
510 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
511 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
512 echo '<input type="number" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
513 break;
514 case 'textarea':
515 echo '<textarea id="' . $field_id . '" name="' . $field_name . '" rows="3" class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>' . wp_kses_post($current_value) . '</textarea>';
516 break;
517 case 'select':
518 echo '<select id="' . $field_id . '" name="' . $field_name . '" class="' . $select_class . '" ' . $required . ' ' . $aria_describedby . '>';
519 if (!empty($field_config['options']) && is_array($field_config['options'])) {
520 foreach ($field_config['options'] as $opt_val => $opt_label) {
521 echo '<option value="' . esc_attr($opt_val) . '" ' . selected($current_value, $opt_val, false) . '>' . esc_html($opt_label) . '</option>';
522 }
523 }
524 echo '</select>';
525 break;
526 case 'multiselect':
527 echo '<select id="' . $field_id . '" name="' . $field_name . '[]" class="' . $select_class . '" multiple="multiple" aria-label="' . esc_attr($field_label) . '">';
528 if (!empty($field_config['options']) && is_array($field_config['options'])) {
529 foreach ($field_config['options'] as $opt_val => $opt_label) {
530 $selected = is_array($current_value) && in_array($opt_val, $current_value) ? 'selected="selected"' : '';
531 echo '<option value="' . esc_attr($opt_val) . '" ' . $selected . '>' . esc_html($opt_label) . '</option>';
532 }
533 }
534 echo '</select>';
535 break;
536 case 'readonly':
537 echo '<input type="text" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . ' bg-gray-50" readonly>';
538 echo '<input type="hidden" name="' . $field_name . '" value="' . esc_attr($current_value) . '">';
539 break;
540 case 'checkbox':
541 echo '<div class="flex items-center">';
542 echo ' <input type="checkbox" name="' . $field_name . '" id="' . $field_id . '" value="yes" ' . checked($current_value, 'yes', false) . ' class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">';
543 echo ' <label for="' . $field_id . '" class="ml-2 block text-sm text-gray-900">' . $field_label . '</label>';
544 echo '</div>';
545 if (!empty($field_description)) {
546 echo '<p id="' . $field_id . '-description" class="mt-2 text-sm text-gray-400 leading-relaxed">' . esc_html($field_description) . '</p>';
547 }
548 break;
549 case 'image':
550 echo '<div class="mt-1 flex items-center">';
551 echo ' <span class="inline-block h-12 w-12 rounded-full overflow-hidden bg-gray-100">';
552 echo ' <img id="' . $field_id . '-preview" src="' . esc_url($current_value) . '" alt="' . esc_attr($field_label) . '" class="h-full w-full object-cover' . (empty($current_value) ? ' hidden' : '') . '">';
553 echo ' </span>';
554 echo ' <button type="button" id="upload_image_button_' . $field_id . '" class="upload-logo-button ml-5 bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" data-uploader_title="' . esc_attr__('Choose Logo', 'easy-invoice') . '" data-uploader_button_text="' . esc_attr__('Select Logo', 'easy-invoice') . '">';
555 echo esc_html__('Change', 'easy-invoice');
556 echo '</button>';
557 echo ' <input type="hidden" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '">';
558 echo '</div>';
559 break;
560 case 'wp_editor':
561 wp_editor( $current_value, $field_id, ['textarea_name' => $field_name, 'teeny' => true, 'media_buttons' => false, 'textarea_rows' => 7, 'editor_class' => 'mt-1'] );
562 // Handle description for wp_editor specifically
563 if (!empty($field_description)) {
564 echo '<p class="mt-1 text-sm text-gray-400">' . esc_html($field_description) . '</p>';
565 }
566 break;
567 case 'test_email':
568 echo '<div class="mt-1">';
569 echo ' <div class="flex items-center space-x-3">';
570 echo ' <input type="email" id="' . $field_id . '_email" placeholder="' . esc_attr__('Enter email address to test', 'easy-invoice') . '" class="mt-1 block w-[200px] border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" value="' . esc_attr(get_option('admin_email')) . '">';
571 echo ' <button type="button" id="' . $field_id . '_button" class="test-email-button inline-flex items-center px-3 py-1.5 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 h-[38px]">';
572 echo ' <i class="fas fa-paper-plane mr-2" aria-hidden="true"></i>';
573 echo ' ' . esc_html__('Send Test Email', 'easy-invoice');
574 echo ' </button>';
575 echo ' </div>';
576 echo ' <div id="' . $field_id . '_result" class="mt-2" style="display: none;"></div>';
577 echo '</div>';
578 break;
579 case 'test_template_email':
580 $template_type = $field_config['template_type'] ?? '';
581 $is_payment_test = ($field_id === 'easy_invoice_payment_test_template');
582 $width_class = $is_payment_test ? 'w-[200px]' : 'w-64';
583 echo '<div class="mt-1">';
584 echo ' <div class="flex items-center space-x-3">';
585 echo ' <input type="email" id="' . $field_id . '_email" placeholder="' . esc_attr__('Enter email address to test', 'easy-invoice') . '" class="mt-1 block ' . $width_class . ' border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" value="' . esc_attr(get_option('admin_email')) . '">';
586 echo ' <button type="button" id="' . $field_id . '_button" class="test-template-email-button inline-flex items-center px-3 py-1.5 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 h-[38px]" data-template-type="' . esc_attr($template_type) . '">';
587 echo ' <i class="fas fa-envelope mr-2" aria-hidden="true"></i>';
588 echo ' ' . esc_html__('Test Template', 'easy-invoice');
589 echo ' </button>';
590 echo ' </div>';
591 echo ' <div id="' . $field_id . '_result" class="mt-2" style="display: none;"></div>';
592 echo '</div>';
593 break;
594 case 'test_payment_reminder_email':
595 echo '<div class="mt-1">';
596 echo ' <div class="flex items-center space-x-3">';
597 echo ' <input type="email" id="' . $field_id . '_email" placeholder="' . esc_attr__('Enter email address to test', 'easy-invoice') . '" class="mt-1 block w-64 border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" value="' . esc_attr(get_option('admin_email')) . '">';
598 echo ' <button type="button" id="' . $field_id . '_button" class="test-payment-reminder-email-button inline-flex items-center px-3 py-1.5 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-orange-600 hover:bg-orange-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-orange-500 h-[38px]">';
599 echo ' <i class="fas fa-bell mr-2" aria-hidden="true"></i>';
600 echo ' ' . esc_html__('Test Reminder', 'easy-invoice');
601 echo ' </button>';
602 echo ' </div>';
603 echo ' <div id="' . $field_id . '_result" class="mt-2" style="display: none;"></div>';
604 echo '</div>';
605 break;
606 default:
607 echo '<input type="text" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . '" placeholder="' . $field_placeholder . '">';
608 break;
609 }
610 if ($field_type !== 'checkbox' && $field_type !== 'wp_editor' && !empty($field_description)) {
611 echo '<p class="mt-1 text-sm text-gray-400">' . esc_html($field_description) . '</p>';
612 }
613 echo '</div>'; // Close the field wrapper div
614 }
615 }
616 ?>
617
618 <?php
619 // Show placeholders only for specific email subsections (not General)
620 if (in_array($subsection_key, ['invoice_available', 'quote_available', 'payment_received', 'payment_reminder'])): ?>
621 <div class="mt-6">
622 <div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
623 <p class="text-sm font-medium text-blue-900 mb-3"><?php esc_html_e('Available Placeholders:', 'easy-invoice'); ?></p>
624 <div class="grid grid-cols-2 md:grid-cols-3 gap-2">
625 <?php if (in_array($subsection_key, ['invoice_available', 'payment_received', 'payment_reminder'])): ?>
626 <!-- Invoice-specific placeholders -->
627 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{invoice_number}}</div>
628 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{due_date}}</div>
629 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{invoice_url}}</div>
630 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{payment_url}}</div>
631 <?php endif; ?>
632
633 <?php if (in_array($subsection_key, ['quote_available'])): ?>
634 <!-- Quote-specific placeholders -->
635 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{quote_number}}</div>
636 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{expiry_date}}</div>
637 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{quote_url}}</div>
638 <?php endif; ?>
639
640 <!-- Common placeholders for all templates -->
641 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{client_name}}</div>
642 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{client_first_name}}</div>
643 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{client_last_name}}</div>
644 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{client_email}}</div>
645 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{client_address}}</div>
646 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{company_name}}</div>
647 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{total_amount}}</div>
648 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{issue_date}}</div>
649 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{company_email}}</div>
650 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{company_phone}}</div>
651 <div class="bg-white border border-blue-200 rounded px-3 py-2 text-xs text-blue-700 font-mono">{{payment_terms}}</div>
652 <?php do_action('easy_invoice_settings_email_placeholders', $settings); ?>
653 </div>
654 </div>
655 </div>
656 <?php endif; ?>
657 </div>
658 </div>
659 <?php } ?>
660 <?php elseif ($section_id === 'payment' && !empty($all_gateways_sorted)): ?>
661 <div class="space-y-5">
662 <?php if (count($all_gateways_sorted) > 1): ?>
663 <div class="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6">
664 <div class="flex items-center">
665 <i class="fas fa-info-circle text-blue-500 mr-2"></i>
666 <p class="text-sm text-blue-700">
667 <?php _e('Drag and drop payment methods to reorder them. The order will be reflected on payment forms.', 'easy-invoice'); ?>
668 </p>
669 </div>
670 </div>
671 <?php endif; ?>
672
673 <div id="sortable-gateways" class="space-y-5">
674 <?php foreach ($all_gateways_sorted as $gateway_id => $gateway) : ?>
675 <div class="gateway-item bg-gray-50 p-5 rounded-lg border border-gray-200 cursor-move" data-gateway-id="<?php echo esc_attr($gateway_id); ?>">
676 <div class="flex items-center mb-3 space-x-3">
677 <!-- Drag Handle -->
678 <div class="gateway-handle text-gray-400 hover:text-gray-600 cursor-move mr-2">
679 <i class="fas fa-grip-vertical"></i>
680 </div>
681
682 <input type="checkbox"
683 class="gateway-enable-checkbox h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded"
684 name="settings[easy_invoice_payment_methods][]"
685 id="gateway-enable-<?php echo esc_attr($gateway_id); ?>"
686 value="<?php echo esc_attr($gateway_id); ?>"
687 <?php checked(!empty($payment_methods_enabled) && in_array($gateway_id, $payment_methods_enabled)); ?>>
688
689 <div class="flex-1">
690 <label for="gateway-enable-<?php echo esc_attr($gateway_id); ?>" class="font-medium text-gray-900">
691 <?php echo esc_html(method_exists($gateway, 'getTitle') ? $gateway->getTitle() : $gateway_id); ?>
692 </label>
693 <?php if (method_exists($gateway, 'getDescription') && $gateway->getDescription()): ?>
694 <span class="block text-sm text-gray-400"><?php echo esc_html($gateway->getDescription()); ?></span>
695 <?php endif; ?>
696 </div>
697 </div>
698
699 <!-- Custom Display Name Field -->
700 <div class="gateway-settings <?php echo empty($payment_methods_enabled) || !in_array($gateway_id, $payment_methods_enabled) ? 'hidden' : ''; ?>">
701 <div class="mb-4">
702 <label for="gateway-display-name-<?php echo esc_attr($gateway_id); ?>" class="block text-sm font-medium text-gray-700">
703 <?php _e('Display Name', 'easy-invoice'); ?>
704 </label>
705 <input type="text"
706 id="gateway-display-name-<?php echo esc_attr($gateway_id); ?>"
707 name="settings[easy_invoice_gateway_display_name_<?php echo esc_attr($gateway_id); ?>]"
708 value="<?php echo esc_attr($settings['easy_invoice_gateway_display_name_' . $gateway_id] ?? (method_exists($gateway, 'getTitle') ? $gateway->getTitle() : ucfirst(str_replace('_', ' ', $gateway_id)))); ?>"
709 placeholder="<?php echo esc_attr(method_exists($gateway, 'getTitle') ? $gateway->getTitle() : ucfirst(str_replace('_', ' ', $gateway_id))); ?>"
710 class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
711 <p class="mt-1 text-xs text-gray-500">
712 <?php _e('Leave blank to use the default name. This name will appear on invoices and payment forms.', 'easy-invoice'); ?>
713 </p>
714 </div>
715
716 <?php
717 $gateway_config = method_exists($gateway, 'getSettingsConfig') ? $gateway->getSettingsConfig() : [];
718 if (!empty($gateway_config['fields'])): ?>
719 <div class="grid grid-cols-1 md:grid-cols-6 gap-4">
720 <?php foreach ($gateway_config['fields'] as $option_key => $field_config): ?>
721 <?php
722 $current_value = $settings[$option_key] ?? ($field_config['default'] ?? '');
723 easy_invoice_render_field($option_key, $field_config, $current_value);
724 ?>
725 <?php endforeach; ?>
726 </div>
727 <?php endif; ?>
728 </div>
729
730 <input type="hidden" class="gateway-order-input" name="settings[easy_invoice_gateway_order][]" value="<?php echo esc_attr($gateway_id); ?>">
731 </div>
732 <?php endforeach; ?>
733 </div>
734 </div>
735 <?php elseif (!empty($section_data['fields'])): ?>
736 <?php
737 // Check if this section has subsections
738 if (!empty($section_data['subsections'])) {
739 // Handle sections with subsections (like invoice, quote, etc.)
740 foreach ($section_data['subsections'] as $subsection_id => $subsection_data) {
741 $subsection_title = $subsection_data['title'] ?? '';
742 $subsection_description = $subsection_data['description'] ?? '';
743 ?>
744 <div class="subsection-content mb-8">
745 <div class="mb-4">
746 <h3 class="text-lg font-medium text-gray-900"><?php echo esc_html($subsection_title); ?></h3>
747 <?php if (!empty($subsection_description)): ?>
748 <p class="text-sm text-gray-400"><?php echo esc_html($subsection_description); ?></p>
749 <?php endif; ?>
750 </div>
751 <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
752 <?php if (!empty($subsection_data['fields'])) {
753 foreach ($subsection_data['fields'] as $option_key => $field_config) {
754 $current_value = $settings[$option_key] ?? ($field_config['default'] ?? '');
755 easy_invoice_render_field($option_key, $field_config, $current_value);
756 }
757 }
758 ?>
759 </div>
760 </div>
761 <?php
762 }
763 } else {
764 // Handle regular sections without subsections
765 if ($section_id === 'tax') {
766 // Render Enable Tax checkbox full width
767 $enable_tax_key = 'easy_invoice_tax_enabled';
768 $enable_tax_field = $section_data['fields'][$enable_tax_key];
769 $current_value = $settings[$enable_tax_key] ?? ($enable_tax_field['default'] ?? '');
770 echo '<div class="mb-4">';
771 echo '<div class="flex items-center">';
772 echo ' <input type="checkbox" name="settings[' . esc_attr($enable_tax_key) . ']" id="' . esc_attr($enable_tax_key) . '" value="yes" ' . checked($current_value, 'yes', false) . ' class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">';
773 echo ' <label for="' . esc_attr($enable_tax_key) . '" class="ml-2 block text-sm text-gray-900">' . esc_html($enable_tax_field['label']) . '</label>';
774 echo '</div>';
775 if (!empty($enable_tax_field['description'])) {
776 echo '<p id="' . $field_id . '-description" class="text-gray-400 mt-1 text-xs">' . esc_html($enable_tax_field['description']) . '</p>';
777 }
778 echo '</div>';
779 // Render the other three fields in a 3-column grid
780 echo '<div class="grid grid-cols-1 md:grid-cols-3 gap-6">';
781 $tax_keys = ['easy_invoice_tax_entry_method', 'easy_invoice_tax_rate', 'easy_invoice_tax_name'];
782 $select_class = 'mt-1 block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md';
783 $input_class = 'mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm';
784 foreach ($tax_keys as $tax_key) {
785 $field_config = $section_data['fields'][$tax_key];
786 $current_value = $settings[$tax_key] ?? ($field_config['default'] ?? '');
787 echo '<div>';
788 if ($field_config['type'] !== 'checkbox') {
789 echo '<label for="' . esc_attr($tax_key) . '" class="block text-sm font-medium text-gray-700">' . esc_html($field_config['label']) . '</label>';
790 }
791 switch ($field_config['type']) {
792 case 'text':
793 case 'email':
794 case 'url':
795 case 'tel':
796 echo '<input type="' . esc_attr($field_config['type']) . '" name="settings[' . esc_attr($tax_key) . ']" id="' . esc_attr($tax_key) . '" value="' . esc_attr($current_value) . '" class="' . $input_class . '" placeholder="' . esc_attr($field_config['placeholder'] ?? '') . '">';
797 break;
798 case 'number':
799 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
800 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
801 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
802 echo '<input type="number" name="settings[' . esc_attr($tax_key) . ']" id="' . esc_attr($tax_key) . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="' . $input_class . '" placeholder="' . esc_attr($field_config['placeholder'] ?? '') . '">';
803 break;
804 case 'select':
805 echo '<select id="' . esc_attr($tax_key) . '" name="settings[' . esc_attr($tax_key) . ']" class="' . $select_class . '">';
806 if (!empty($field_config['options']) && is_array($field_config['options'])) {
807 foreach ($field_config['options'] as $opt_val => $opt_label) {
808 echo '<option value="' . esc_attr($opt_val) . '" ' . selected($current_value, $opt_val, false) . '>' . esc_html($opt_label) . '</option>';
809 }
810 }
811 echo '</select>';
812 break;
813 }
814 if (!empty($field_config['description'])) {
815 echo '<p class="mt-1 text-xs text-gray-400">' . esc_html($field_config['description']) . '</p>';
816 }
817 echo '</div>';
818 }
819 echo '</div>';
820
821 // Allow additional fields to be added to the tax section
822 $additional_tax_fields = apply_filters('easy_invoice_tax_section_additional_fields', [], $settings);
823 if (!empty($additional_tax_fields)) {
824 echo '<div class="mt-6 pt-6 border-t border-gray-200">';
825 echo '<h4 class="text-sm font-medium text-gray-900 mb-4">' . __('Additional Tax Settings', 'easy-invoice-pro') . '</h4>';
826 echo '<div class="grid grid-cols-1 md:grid-cols-2 gap-6">';
827 foreach ($additional_tax_fields as $field_key => $field_config) {
828 $current_value = $settings[$field_key] ?? ($field_config['default'] ?? '');
829 easy_invoice_render_field($field_key, $field_config, $current_value);
830 }
831 echo '</div>';
832 echo '</div>';
833 }
834 } else {
835 // Use a two-column grid for currency and company settings
836 $is_grid = ($section_id === 'currency' || $section_id === 'company');
837 // Use a 6-column grid for invoice and quote settings to allow specific field pairing
838 $is_invoice_grid = ($section_id === 'invoice');
839 $is_quote_grid = ($section_id === 'quote');
840 // Use a specific grid for advanced settings to improve spacing
841 $is_advanced_grid = ($section_id === 'advanced');
842 // Use a 3-column grid for text settings
843 $is_text_settings_grid = ($section_id === 'text_settings');
844 if ($is_grid) echo '<div class="grid grid-cols-1 md:grid-cols-2 gap-6">';
845 if ($is_invoice_grid) echo '<div class="grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-6">';
846 if ($is_quote_grid) echo '<div class="grid grid-cols-1 gap-y-6 gap-x-4 sm:grid-cols-6">';
847 if ($is_advanced_grid) echo '<div class="grid grid-cols-1 gap-6">';
848 if ($is_text_settings_grid) echo '<div class="grid grid-cols-1 md:grid-cols-3 gap-6">';
849 foreach ($section_data['fields'] as $option_key => $field_config) {
850 $current_value = $settings[$option_key] ?? ($field_config['default'] ?? '');
851 $field_id = esc_attr($option_key);
852 $field_type = $field_config['type'] ?? 'text';
853 $field_label = esc_html($field_config['label'] ?? '');
854 $field_placeholder = isset($field_config['placeholder']) ? esc_attr($field_config['placeholder']) : '';
855 $field_description = $field_config['description'] ?? '';
856 $field_name = 'settings[' . esc_attr($option_key) . ']';
857 $input_class = 'mt-1 block w-full border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm';
858 $select_class = 'mt-1 block w-full pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md';
859 $col_span_class = esc_attr($field_config['col_span'] ?? 'sm:col-span-6');
860 $form_group_class = '';
861 if ($is_grid) {
862 $form_group_class = '';
863 } elseif ($is_invoice_grid || $is_quote_grid || $is_advanced_grid || $is_text_settings_grid) {
864 $form_group_class = $col_span_class;
865 } else {
866 $form_group_class = $col_span_class;
867 }
868
869 // Handle conditional display
870 $conditional_class = '';
871 if (isset($field_config['depends_on']) && is_array($field_config['depends_on'])) {
872 $conditional_class = ' conditional-field';
873 foreach ($field_config['depends_on'] as $depends_key => $depends_value) {
874 $depends_field_name = 'settings[' . esc_attr($depends_key) . ']';
875 $conditional_class .= ' depends-on-' . esc_attr($depends_key) . '-' . esc_attr($depends_value);
876 }
877 }
878
879 echo '<div class="form-group ' . $form_group_class . $conditional_class . '">';
880 if ($field_type !== 'checkbox') {
881 echo '<label for="' . $field_id . '" class="block text-sm font-medium text-gray-700">' . $field_label . '</label>';
882 }
883
884 // Define required and aria_describedby variables
885 $required = !empty($field_config['required']) ? 'required' : '';
886 $aria_describedby = !empty($field_description) ? 'aria-describedby="' . $field_id . '-description"' : '';
887
888 switch ($field_type) {
889 case 'text':
890 case 'email':
891 case 'url':
892 case 'tel':
893 echo '<input type="' . esc_attr($field_type) . '" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
894 break;
895 case 'number':
896 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
897 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
898 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
899 echo '<input type="number" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>';
900 break;
901 case 'textarea':
902 echo '<textarea id="' . $field_id . '" name="' . $field_name . '" rows="3" class="' . $input_class . '" placeholder="' . $field_placeholder . '" ' . $required . ' ' . $aria_describedby . '>' . wp_kses_post($current_value) . '</textarea>';
903 break;
904 case 'select':
905 echo '<select id="' . $field_id . '" name="' . $field_name . '" class="' . $select_class . '" ' . $required . ' ' . $aria_describedby . '>';
906 if (!empty($field_config['options']) && is_array($field_config['options'])) {
907 foreach ($field_config['options'] as $opt_val => $opt_label) {
908 echo '<option value="' . esc_attr($opt_val) . '" ' . selected(strtolower($current_value), strtolower($opt_val), false) . '>' . esc_html($opt_label) . '</option>';
909 }
910 }
911 echo '</select>';
912 break;
913 case 'multiselect':
914 echo '<select id="' . $field_id . '" name="' . $field_name . '[]" class="' . $select_class . '" multiple="multiple" aria-label="' . esc_attr($field_label) . '">';
915 if (!empty($field_config['options']) && is_array($field_config['options'])) {
916 foreach ($field_config['options'] as $opt_val => $opt_label) {
917 $selected = is_array($current_value) && in_array($opt_val, $current_value) ? 'selected="selected"' : '';
918 echo '<option value="' . esc_attr($opt_val) . '" ' . $selected . '>' . esc_html($opt_label) . '</option>';
919 }
920 }
921 echo '</select>';
922 break;
923 case 'readonly':
924 echo '<input type="text" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . ' bg-gray-50" readonly>';
925 echo '<input type="hidden" name="' . $field_name . '" value="' . esc_attr($current_value) . '">';
926 break;
927 case 'checkbox':
928 echo '<div class="flex items-center">';
929 echo ' <input type="checkbox" name="' . $field_name . '" id="' . $field_id . '" value="yes" ' . checked($current_value, 'yes', false) . ' class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded">';
930 echo ' <label for="' . $field_id . '" class="ml-2 block text-sm text-gray-900">' . $field_label . '</label>';
931 echo '</div>';
932 if (!empty($field_description)) {
933 echo '<p id="' . $field_id . '-description" class="mt-2 text-sm text-gray-400 leading-relaxed">' . esc_html($field_description) . '</p>';
934 }
935 break;
936 case 'image':
937 echo '<div class="mt-1 flex items-center">';
938 echo ' <span class="inline-block h-12 w-12 rounded-full overflow-hidden bg-gray-100">';
939 echo ' <img id="' . $field_id . '-preview" src="' . esc_url($current_value) . '" alt="' . esc_attr($field_label) . '" class="h-full w-full object-cover' . (empty($current_value) ? ' hidden' : '') . '">';
940 echo ' </span>';
941 echo ' <button type="button" id="upload_image_button_' . $field_id . '" class="upload-logo-button ml-5 bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" data-uploader_title="' . esc_attr__('Choose Logo', 'easy-invoice') . '" data-uploader_button_text="' . esc_attr__('Select Logo', 'easy-invoice') . '">';
942 echo esc_html__('Change', 'easy-invoice');
943 echo '</button>';
944 echo ' <input type="hidden" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '">';
945 echo '</div>';
946 break;
947 case 'wp_editor':
948 wp_editor( $current_value, $field_id, ['textarea_name' => $field_name, 'teeny' => true, 'media_buttons' => false, 'textarea_rows' => 7, 'editor_class' => 'mt-1'] );
949 // Handle description for wp_editor specifically
950 if (!empty($field_description)) {
951 echo '<p class="mt-1 text-sm text-gray-400">' . esc_html($field_description) . '</p>';
952 }
953 break;
954 case 'color':
955 echo '<input type="color" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="h-10 w-20 border border-gray-300 rounded">';
956 break;
957 case 'range':
958 $min = isset($field_config['min']) ? ' min="' . esc_attr($field_config['min']) . '"' : '';
959 $max = isset($field_config['max']) ? ' max="' . esc_attr($field_config['max']) . '"' : '';
960 $step = isset($field_config['step']) ? ' step="' . esc_attr($field_config['step']) . '"' : '';
961 echo '<input type="range" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '"' . $min . $max . $step . ' class="w-full">';
962 echo '<span class="text-sm text-gray-400">' . esc_html($current_value) . '%</span>';
963 break;
964 case 'image_upload':
965 echo '<div class="image-upload-wrap">';
966 echo '<div class="flex items-center space-x-3">';
967 echo ' <input type="hidden" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '">';
968 echo ' <button type="button" class="upload-image-button bg-white py-2 px-3 border border-gray-300 rounded-md shadow-sm text-sm leading-4 font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" data-target="' . $field_id . '">';
969 echo esc_html__('Upload Image', 'easy-invoice');
970 echo '</button>';
971 echo '</div>';
972 echo '<div class="image-preview mt-2' . (empty($current_value) ? ' hidden' : '') . '">';
973 if (!empty($current_value)) {
974 echo '<img src="' . esc_url($current_value) . '" alt="Preview" style="max-width: 200px; max-height: 100px;">';
975 }
976 echo '</div>';
977 echo '</div>';
978 break;
979 case 'button':
980 $button_text = $field_config['button_text'] ?? $field_label;
981 $button_class = $field_config['button_class'] ?? 'button button-secondary';
982 $button_class_name = 'regenerate-invoice-numbers-button';
983 if ($option_key === 'easy_invoice_regenerate_quote_numbers') {
984 $button_class_name = 'regenerate-quote-numbers-button';
985 }
986 echo '<button type="button" id="' . $field_id . '" class="' . esc_attr($button_class) . ' ' . $button_class_name . '">';
987 echo esc_html($button_text);
988 echo '</button>';
989 break;
990 default:
991 echo '<input type="text" name="' . $field_name . '" id="' . $field_id . '" value="' . esc_attr($current_value) . '" class="' . $input_class . '" placeholder="' . $field_placeholder . '">';
992 break;
993 }
994 if ($field_type !== 'checkbox' && $field_type !== 'wp_editor' && !empty($field_description)) {
995 echo '<p class="mt-1 text-sm text-gray-400">' . esc_html($field_description) . '</p>';
996 }
997 echo '</div>';
998 }
999 if ($is_grid) echo '</div>';
1000 if ($is_invoice_grid) echo '</div>';
1001 if ($is_quote_grid) echo '</div>';
1002 if ($is_advanced_grid) echo '</div>';
1003 if ($is_text_settings_grid) echo '</div>';
1004 }
1005 }
1006 ?>
1007 <?php endif; ?>
1008 </div>
1009 </div>
1010 </div>
1011 <?php endforeach; ?>
1012
1013 <!-- Bottom Save Button -->
1014 <div class="mt-8 pt-6 border-t border-gray-200">
1015 <div class="flex items-center justify-start space-x-3">
1016 <button type="button" id="save-settings-bottom" class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition-colors duration-200" aria-label="<?php esc_attr_e('Save Settings', 'easy-invoice'); ?>">
1017 <i class="fas fa-save mr-2" aria-hidden="true"></i>
1018 <?php esc_html_e('Save Changes', 'easy-invoice'); ?>
1019 </button>
1020 </div>
1021 </div>
1022
1023 </form>
1024 </div>
1025 </div>
1026 </div>
1027 </div>
1028
1029 <script>
1030 document.addEventListener('DOMContentLoaded', function() {
1031 // Enter key functionality to save settings
1032 const settingsForm = document.getElementById('settings-form');
1033 const saveButton = document.getElementById('save-settings-bottom');
1034
1035 if (settingsForm && saveButton) {
1036 // Get both save buttons
1037 const topSaveButton = document.getElementById('save-settings');
1038 const bottomSaveButton = document.getElementById('save-settings-bottom');
1039
1040 // Function to trigger save
1041 function triggerSave() {
1042 // Try bottom button first, then top button
1043 if (bottomSaveButton) {
1044 bottomSaveButton.click();
1045 } else if (topSaveButton) {
1046 topSaveButton.click();
1047 }
1048 }
1049
1050 // Listen for Enter key on form inputs
1051 settingsForm.addEventListener('keydown', function(e) {
1052 // Check if Enter key is pressed and not in a textarea or select
1053 if (e.key === 'Enter' && e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'SELECT') {
1054 e.preventDefault();
1055 triggerSave();
1056 }
1057 });
1058
1059 // Also listen for Enter key on the entire form
1060 settingsForm.addEventListener('keypress', function(e) {
1061 if (e.key === 'Enter' && e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'SELECT') {
1062 e.preventDefault();
1063 triggerSave();
1064 }
1065 });
1066 }
1067
1068 // Email Settings submenu hover behavior for settings page
1069 const emailNavLink = document.querySelector('.nav-link[href*="section=email"]');
1070 const emailSubmenu = document.querySelector('.email-settings-submenu');
1071
1072 if (emailNavLink && emailSubmenu) {
1073 // Check if any Email Settings subsection is active
1074 const activeSubmenuLink = document.querySelector('.email-submenu-link.text-indigo-700');
1075 const isEmailSectionActive = emailNavLink.classList.contains('text-indigo-700');
1076 const isAnySubsectionActive = activeSubmenuLink !== null;
1077
1078 // If any subsection is active, show submenu permanently and disable hover effects
1079 if (isAnySubsectionActive || isEmailSectionActive) {
1080 emailSubmenu.style.display = 'block';
1081 emailSubmenu.style.opacity = '1';
1082 emailSubmenu.style.visibility = 'visible';
1083 emailSubmenu.style.maxHeight = '200px';
1084 emailSubmenu.classList.add('show');
1085 return; // Exit early, no hover effects needed
1086 }
1087
1088 // Only add hover effects if no subsection is active
1089 // Show submenu on hover
1090 emailNavLink.addEventListener('mouseenter', function() {
1091 emailSubmenu.style.display = 'block';
1092 emailSubmenu.classList.add('show');
1093 setTimeout(() => {
1094 emailSubmenu.style.opacity = '1';
1095 emailSubmenu.style.visibility = 'visible';
1096 emailSubmenu.style.maxHeight = '200px';
1097 }, 10);
1098 });
1099
1100 // Hide submenu when mouse leaves
1101 emailNavLink.addEventListener('mouseleave', function() {
1102 // Only hide if not hovering over submenu
1103 setTimeout(() => {
1104 if (!emailSubmenu.matches(':hover')) {
1105 emailSubmenu.style.opacity = '0';
1106 emailSubmenu.style.visibility = 'hidden';
1107 emailSubmenu.style.maxHeight = '0';
1108 emailSubmenu.classList.remove('show');
1109 setTimeout(() => {
1110 emailSubmenu.style.display = 'none';
1111 }, 200);
1112 }
1113 }, 100);
1114 });
1115
1116 // Keep submenu open when hovering over submenu items
1117 emailSubmenu.addEventListener('mouseenter', function() {
1118 emailSubmenu.style.opacity = '1';
1119 emailSubmenu.style.visibility = 'visible';
1120 emailSubmenu.style.maxHeight = '200px';
1121 emailSubmenu.classList.add('show');
1122 });
1123
1124 emailSubmenu.addEventListener('mouseleave', function() {
1125 emailSubmenu.style.opacity = '0';
1126 emailSubmenu.style.visibility = 'hidden';
1127 emailSubmenu.style.maxHeight = '0';
1128 emailSubmenu.classList.remove('show');
1129 setTimeout(() => {
1130 emailSubmenu.style.display = 'none';
1131 }, 200);
1132 });
1133 }
1134 });
1135 </script>
1136
1137 <style>
1138 #screen-meta-links{
1139 display:none;
1140 }
1141 /* Email Settings Submenu Styles for Settings Page */
1142 .email-settings-submenu {
1143 transition: all 0.3s ease;
1144 overflow: hidden;
1145 }
1146
1147 .email-settings-submenu.show {
1148 display: block !important;
1149 }
1150
1151 .email-settings-submenu.show ~ .nav-link .fas.fa-chevron-down,
1152 .email-settings-submenu:hover ~ .nav-link .fas.fa-chevron-down {
1153 transform: rotate(180deg);
1154 }
1155
1156 /* Custom color for settings navigation icons */
1157 .nav-link:hover svg {
1158 color: rgb(79 70 229) !important;
1159 }
1160
1161 /* Active state icon color */
1162 .bg-indigo-50 svg {
1163 color: rgb(79 70 229) !important;
1164 }
1165
1166 /* Hover state for non-active items */
1167 .nav-link:hover:not(.bg-indigo-50) svg {
1168 color: rgb(79 70 229) !important;
1169 }
1170
1171 /* Email submenu icon colors */
1172 .email-submenu-link:hover svg {
1173 color: rgb(79 70 229) !important;
1174 }
1175
1176 .email-submenu-link.bg-indigo-50 svg {
1177 color: rgb(79 70 229) !important;
1178 }
1179 </style>
1180