From e0a511b50fc9d9dfa2ddec736a232d0a76ed260e Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Sat, 5 Jul 2025 17:38:20 -0700 Subject: [PATCH] fix field deletion & tone down header styling --- .../attribute_fields_controller.rb | 38 ++++- app/javascript/packs/template_editor.js | 89 +++++++++++ .../tailwind/_field_config.html.erb | 60 ++++++-- .../content/attributes_tailwind.html.erb | 140 +++++------------- 4 files changed, 205 insertions(+), 122 deletions(-) diff --git a/app/controllers/attribute_fields_controller.rb b/app/controllers/attribute_fields_controller.rb index a382ef4c..ebf261b0 100644 --- a/app/controllers/attribute_fields_controller.rb +++ b/app/controllers/attribute_fields_controller.rb @@ -1,6 +1,6 @@ class AttributeFieldsController < ContentController before_action :authenticate_user! - before_action :set_attribute_field, only: [:update, :edit] + before_action :set_attribute_field, only: [:update, :edit, :destroy] def create if initialize_object.save! @@ -19,12 +19,40 @@ class AttributeFieldsController < ContentController end def destroy - # Delete this field as usual -- sets @content - super + unless @attribute_field.deletable_by?(current_user) + respond_to do |format| + format.html { redirect_back fallback_location: root_path, alert: "You don't have permission to delete that!" } + format.json { render json: { success: false, error: "You don't have permission to delete that!" }, status: :forbidden } + end + return + end + # Store references before deletion + field_label = @attribute_field.label + related_category = @attribute_field.attribute_category + + # Delete the field + @attribute_field.destroy + # If the related category is now empty, delete it as well - related_category = @content.attribute_category - related_category.destroy if related_category.attribute_fields.empty? + if related_category.attribute_fields.empty? + related_category.destroy + end + + # Respond with success + respond_to do |format| + format.html { + redirect_to attribute_customization_tailwind_path(content_type: related_category.entity_type), + notice: "#{field_label} field deleted successfully" + } + format.json { + render json: { + success: true, + message: "#{field_label} field deleted successfully", + deleted_field_id: params[:id] + }, status: :ok + } + end end def edit diff --git a/app/javascript/packs/template_editor.js b/app/javascript/packs/template_editor.js index e1246e3d..5b541b9d 100644 --- a/app/javascript/packs/template_editor.js +++ b/app/javascript/packs/template_editor.js @@ -1,5 +1,94 @@ // Template Editor JavaScript +// Field Deletion Component function for Alpine.js (define before DOM ready) +window.fieldDeletionComponent = function() { + return { + showConfirmation: false, + deleting: false, + + deleteField() { + this.deleting = true; + + // Get field information from the current context + const fieldConfigContainer = document.getElementById('field-config-container'); + const fieldForm = fieldConfigContainer.querySelector('form[action*="/attribute_fields/"]'); + + if (!fieldForm) { + console.error('Field form not found'); + showNotification('Unable to delete field - form not found', 'error'); + this.deleting = false; + return; + } + + // Extract field ID from form action URL + const fieldIdMatch = fieldForm.action.match(/\/attribute_fields\/(\d+)/); + if (!fieldIdMatch) { + console.error('Field ID not found in form action'); + showNotification('Unable to delete field - ID not found', 'error'); + this.deleting = false; + return; + } + + const fieldId = fieldIdMatch[1]; + + // Perform deletion via AJAX + fetch(`/plan/attribute_fields/${fieldId}`, { + method: 'DELETE', + headers: { + 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content'), + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + }) + .then(response => { + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + return response.json(); + }) + .then(data => { + console.log('Field deleted successfully:', data); + + // Remove the field from the UI + const fieldItem = document.querySelector(`[data-field-id="${fieldId}"]`); + if (fieldItem) { + // Update field count in category header before removing + const categoryId = fieldItem.closest('.fields-container').dataset.categoryId; + fieldItem.remove(); + updateCategoryFieldCount(categoryId); + } + + // Update General Settings counts + updateGeneralSettingsCounts(); + + // Close the configuration panel + const alpineElement = document.querySelector('.attributes-editor'); + if (alpineElement && alpineElement._x_dataStack) { + const alpine = alpineElement._x_dataStack[0]; + if (alpine) { + alpine.selectedField = null; + alpine.configuring = false; + } + } + + // Show success notification + if (data.message) { + showNotification(data.message, 'success'); + } else { + showNotification('Field deleted successfully', 'success'); + } + + this.deleting = false; + }) + .catch(error => { + console.error('Failed to delete field:', error); + showNotification('Failed to delete field', 'error'); + this.deleting = false; + }); + } + }; +}; + // Template Reset Component function for Alpine.js (define before DOM ready) window.templateResetComponent = function() { return { diff --git a/app/views/content/attributes/tailwind/_field_config.html.erb b/app/views/content/attributes/tailwind/_field_config.html.erb index 1eaa0e49..c78ec380 100644 --- a/app/views/content/attributes/tailwind/_field_config.html.erb +++ b/app/views/content/attributes/tailwind/_field_config.html.erb @@ -429,18 +429,56 @@ warning Danger Zone -
-

- Deleting a field will permanently remove it and all its data from all <%= content_type.pluralize.downcase %>. -

+
+
+

+ Deleting a field will permanently remove it and all its data from all <%= content_type.pluralize.downcase %>. +

+ + +
- <%= link_to "Delete Field", - field, - class: 'w-full inline-block text-center px-3 py-1.5 border border-transparent rounded-md text-sm font-medium text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500', - method: :delete, - data: { - confirm: "Are you sure? This will delete this field AND all of its answers to EVERY page you've created. This action cannot be undone!" - } %> + +
+
+

+ warning + Confirm Field Deletion +

+

+ This will permanently delete "<%= field.label %>" and all answers you've written to this field across all of your <%= content_type.pluralize.downcase %> pages. +

+

+ This action cannot be undone! +

+
+ +
+ + +
+
<% end %> diff --git a/app/views/content/attributes_tailwind.html.erb b/app/views/content/attributes_tailwind.html.erb index b7589ebe..08faba37 100644 --- a/app/views/content/attributes_tailwind.html.erb +++ b/app/views/content/attributes_tailwind.html.erb @@ -34,69 +34,37 @@
- -
- + +
+
<%= image_tag "card-headers/#{@content_type.downcase.pluralize}.jpg", class: "hero-bg-image w-full h-full object-cover", alt: "#{@content_type.titleize} background" %> -
-
+ +
+
-
- -
-
-
- <%= @content_type_class.icon %> +
+
+ +
+
+ <%= @content_type_class.icon %>
-

+

<%= @content_type.titleize %> Template Editor

-

- Design your perfect <%= @content_type.titleize.downcase %> structure +

+ Edit the template used for your <%= @content_type.titleize.downcase %> pages. Adding or removing a field here will modify all of your already-created <%= @content_type.titleize.downcase %> pages also.

- - -
-

- This template will be used for all of your <%= @content_type.titleize.downcase %> pages. - You can customize categories and fields to fit your needs; adding or removing categories or - fields on this page will also add or remove them from all of your existing <%= @content_type.titleize.downcase %> pages. -

- - -
-
- drag_indicator - Drag to reorder -
-
- tune - Click to configure -
-
- add_circle - Add new elements -
-
-
- - -
-
-
-
-
-
@@ -217,91 +185,51 @@