From bd3a19b04a463ecbb622acd475b6eda5c580303d Mon Sep 17 00:00:00 2001 From: Marcus Quinn Date: Tue, 25 Mar 2025 17:29:08 +0000 Subject: [PATCH] refactor: Improve access control settings UI and functionality - Fix double notification issue when toggling feature - Improve AJAX handling with better error handling - Create consistent component design for role checkboxes - Improve notification display and positioning - Enhance toggle component with better header/content styling - Add responsive design for all screen sizes - Ensure expansion/collapse works correctly --- admin/css/wp-allstars-admin.css | 96 +++++++++++++----- admin/includes/class-access-manager.php | 126 +++++++++++++++++++----- 2 files changed, 174 insertions(+), 48 deletions(-) diff --git a/admin/css/wp-allstars-admin.css b/admin/css/wp-allstars-admin.css index 614098d..0372af2 100644 --- a/admin/css/wp-allstars-admin.css +++ b/admin/css/wp-allstars-admin.css @@ -747,38 +747,35 @@ input:checked + .wp-toggle-slider:before { .wp-allstars-toggle-left label, .wp-allstars-setting-row label { position: relative; - padding-right: 80px; /* Increased padding to accommodate notification */ + padding-right: 20px; display: inline-block; - min-width: 200px; /* Ensure minimum width for labels */ } -/* Ensure toggle switches don't wrap with notifications */ -.wp-allstars-toggle-left { - display: flex; - align-items: center; - flex-wrap: nowrap; - gap: 10px; +.wp-setting-left label .wp-setting-notification, +.wp-allstars-toggle-left label .wp-setting-notification, +.wp-allstars-setting-row label .wp-setting-notification { + position: absolute; + right: -60px; + top: -5px; + transform: translateY(0); + line-height: 1.4; } -.wp-allstars-toggle-left label { - flex: 1; - margin: 0; - padding-right: 80px; -} - -/* Role Checkboxes */ +/* Role Checkboxes - Consistent component design */ .wp-allstars-role-checkboxes { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + display: flex; + flex-wrap: wrap; gap: 10px; margin-top: 10px; } .wp-allstars-role-checkbox { + flex: 0 0 calc(33.333% - 10px); + max-width: calc(33.333% - 10px); display: flex; align-items: center; gap: 8px; - padding: 8px; + padding: 8px 10px; background: #f8f9fa; border: 1px solid #ddd; border-radius: 4px; @@ -800,15 +797,19 @@ input:checked + .wp-toggle-slider:before { color: #50575e; } -/* Responsive adjustments for role checkboxes */ -@media screen and (max-width: 782px) { - .wp-allstars-role-checkboxes { - grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); - gap: 8px; - } - +/* Responsive adjustments */ +@media screen and (max-width: 992px) { .wp-allstars-role-checkbox { - padding: 6px; + flex: 0 0 calc(50% - 10px); + max-width: calc(50% - 10px); + } +} + +@media screen and (max-width: 782px) { + .wp-allstars-role-checkbox { + flex: 0 0 calc(50% - 8px); + max-width: calc(50% - 8px); + padding: 6px 8px; } .wp-allstars-role-checkbox span { @@ -816,6 +817,49 @@ input:checked + .wp-toggle-slider:before { } } +@media screen and (max-width: 480px) { + .wp-allstars-role-checkbox { + flex: 0 0 100%; + max-width: 100%; + } +} + +/* Enhanced toggle component */ +.wp-allstars-toggle { + position: relative; + overflow: hidden; +} + +.wp-allstars-toggle-header[aria-expanded="true"] { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +/* Better settings panel styling */ +.wp-allstars-toggle-settings { + padding: 20px; + background: #f8f9fa; + border-top: 1px solid #ddd; + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; +} + +.wp-allstars-setting-row { + margin-bottom: 20px; +} + +.wp-allstars-setting-row:last-child { + margin-bottom: 0; +} + +.wp-allstars-setting-row label { + display: block; + margin-bottom: 8px; + font-size: 14px; + font-weight: 600; + color: #1d2327; +} + @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } diff --git a/admin/includes/class-access-manager.php b/admin/includes/class-access-manager.php index a2486d5..ba1830d 100644 --- a/admin/includes/class-access-manager.php +++ b/admin/includes/class-access-manager.php @@ -62,6 +62,9 @@ class WP_Allstars_Access_Manager { var setting = $this.attr("id"); var value = $this.is(":checked"); + // Clear any existing notifications + $(".wp-setting-notification").remove(); + $.ajax({ url: ajaxurl, type: "POST", @@ -74,12 +77,42 @@ class WP_Allstars_Access_Manager { success: function(response) { if (response.success) { showSavedNotification($this); + + // Update UI based on toggle state + var $container = $this.closest(".wp-allstars-toggle"); + var $settingsArea = $container.find(".wp-allstars-toggle-settings"); + var $header = $container.find(".wp-allstars-toggle-header"); + + if (value) { + // Set default roles (subscriber, customer) as checked when enabled + $settingsArea.find("input[value=\'subscriber\'], input[value=\'customer\']").prop("checked", true); + // Expand the section if it was toggled on + if ($header.attr("aria-expanded") === "false") { + $header.attr("aria-expanded", "true"); + $settingsArea.slideDown(200); + } + } else { + // Clear all role checkboxes when disabled + $settingsArea.find("input[type=checkbox]").prop("checked", false); + // Optionally collapse the section if it was toggled off + // Uncomment this if you want the section to collapse when disabled + /* + if ($header.attr("aria-expanded") === "true") { + $header.attr("aria-expanded", "false"); + $settingsArea.slideUp(200); + } + */ + } } else { showErrorNotification($this); + // Revert the toggle to its previous state + $this.prop("checked", !value); } }, error: function() { showErrorNotification($this); + // Revert the toggle to its previous state + $this.prop("checked", !value); } }); }); @@ -91,6 +124,9 @@ class WP_Allstars_Access_Manager { var setting = $container.find("input").first().attr("name"); var selectedRoles = []; + // Clear any existing notifications + $(".wp-setting-notification").remove(); + $container.find("input:checked").each(function() { selectedRoles.push($(this).val()); }); @@ -106,28 +142,43 @@ class WP_Allstars_Access_Manager { }, success: function(response) { if (response.success) { - showSavedNotification($this); + // Find the main toggle for this section + var $mainToggle = $this.closest(".wp-allstars-toggle").find(".wp-toggle-switch input"); + + // Update the main toggle based on role selection + if (selectedRoles.length > 0) { + $mainToggle.prop("checked", true); + showSavedNotification($mainToggle); + } else { + $mainToggle.prop("checked", false); + showSavedNotification($mainToggle); + } } else { showErrorNotification($this); + // Revert the checkbox to its previous state + $this.prop("checked", !$this.prop("checked")); } }, error: function() { showErrorNotification($this); + // Revert the checkbox to its previous state + $this.prop("checked", !$this.prop("checked")); } }); }); function showSavedNotification($element) { - var $label = $element.closest(".wp-allstars-toggle-left").find("label"); - var $notification = $label.find(".wp-setting-notification"); + // Find the nearest toggle header for notification placement + var $toggleHeader = $element.closest(".wp-allstars-toggle").find(".wp-allstars-toggle-header"); + var $notification = $("").addClass("wp-setting-notification success").text("Saved"); - if ($notification.length === 0) { - $notification = $("").addClass("wp-setting-notification"); - $label.append($notification); - } + // Remove any existing notifications + $toggleHeader.find(".wp-setting-notification").remove(); - $notification.text("Saved").removeClass("error").addClass("success"); + // Add the notification + $toggleHeader.find("label").append($notification); + // Remove notification after delay setTimeout(function() { $notification.fadeOut(300, function() { $(this).remove(); @@ -136,22 +187,36 @@ class WP_Allstars_Access_Manager { } function showErrorNotification($element) { - var $label = $element.closest(".wp-allstars-toggle-left").find("label"); - var $notification = $label.find(".wp-setting-notification"); + // Find the nearest toggle header for notification placement + var $toggleHeader = $element.closest(".wp-allstars-toggle").find(".wp-allstars-toggle-header"); + var $notification = $("").addClass("wp-setting-notification error").text("Error Saving"); - if ($notification.length === 0) { - $notification = $("").addClass("wp-setting-notification"); - $label.append($notification); - } + // Remove any existing notifications + $toggleHeader.find(".wp-setting-notification").remove(); - $notification.text("Error Saving").removeClass("success").addClass("error"); + // Add the notification + $toggleHeader.find("label").append($notification); + // Remove notification after delay setTimeout(function() { $notification.fadeOut(300, function() { $(this).remove(); }); }, 2000); } + + // Toggle expandable settings panels + $(".wp-allstars-toggle-header").on("click", function() { + var $this = $(this); + var $settings = $this.closest(".wp-allstars-toggle").find(".wp-allstars-toggle-settings"); + var isExpanded = $this.attr("aria-expanded") === "true"; + + // Toggle aria-expanded attribute + $this.attr("aria-expanded", !isExpanded); + + // Toggle settings visibility + $settings.slideToggle(200); + }); }); '; @@ -165,11 +230,13 @@ class WP_Allstars_Access_Manager { // Verify nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'wp-allstars-nonce')) { wp_send_json_error('Invalid nonce'); + return; } // Check user capabilities if (!current_user_can('manage_options')) { wp_send_json_error('Insufficient permissions'); + return; } // Get and validate setting @@ -178,34 +245,49 @@ class WP_Allstars_Access_Manager { if (empty($setting)) { wp_send_json_error('Invalid setting'); + return; } // Handle different setting types + $result = false; switch ($setting) { case 'wp_allstars_hide_admin_bar': - $result = update_option('wp_allstars_hide_admin_bar_roles', $value ? array('guest', 'subscriber', 'customer') : array()); + // When the main toggle is changed, update the roles option + $default_roles = array('guest', 'subscriber', 'customer'); + $result = update_option('wp_allstars_hide_admin_bar_roles', $value ? $default_roles : array()); break; case 'wp_allstars_restrict_dashboard': - $result = update_option('wp_allstars_restrict_dashboard_roles', $value ? array('guest', 'subscriber', 'customer') : array()); + // When the main toggle is changed, update the roles option + $default_roles = array('guest', 'subscriber', 'customer'); + $result = update_option('wp_allstars_restrict_dashboard_roles', $value ? $default_roles : array()); break; - case 'wp_allstars_hide_admin_bar_roles': - case 'wp_allstars_restrict_dashboard_roles': + case 'wp_allstars_hide_admin_bar_roles[]': + // For role checkboxes, update the complete array if (is_array($value)) { $value = array_map('sanitize_text_field', $value); - $result = update_option($setting, $value); + $result = update_option('wp_allstars_hide_admin_bar_roles', $value); + } + break; + + case 'wp_allstars_restrict_dashboard_roles[]': + // For role checkboxes, update the complete array + if (is_array($value)) { + $value = array_map('sanitize_text_field', $value); + $result = update_option('wp_allstars_restrict_dashboard_roles', $value); } break; default: wp_send_json_error('Invalid setting name'); + return; } if ($result) { - wp_send_json_success(); + wp_send_json_success(array('message' => 'Setting updated successfully')); } else { - wp_send_json_error('Failed to save setting'); + wp_send_json_error(array('message' => 'Failed to save setting')); } }