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 %>. +
+ + ++ 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! +
+- 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. -
- - -