Remove Angular and Stimulus Reflex from the Settings > Images section

This commit is contained in:
Cillian O'Ruanaidh
2025-04-18 11:49:53 +01:00
parent a8b5a79b4b
commit a9a4156251
17 changed files with 140 additions and 264 deletions

View File

@@ -55,12 +55,6 @@ angular.module("admin.enterprises")
else
alert ("#{manager.email}" + " " + t("is_already_manager"))
$scope.removeLogo = ->
$scope.performEnterpriseAction("removeLogo", "immediate_logo_removal_warning", "removed_logo_successfully")
$scope.removePromoImage = ->
$scope.performEnterpriseAction("removePromoImage", "immediate_promo_image_removal_warning", "removed_promo_image_successfully")
$scope.performEnterpriseAction = (enterpriseActionName, warning_message_key, success_message_key) ->
return unless confirm($scope.translation(warning_message_key))

View File

@@ -8,10 +8,4 @@ angular.module("admin.resources").factory 'EnterpriseResource', ($resource) ->
isArray: true
'update':
method: 'PUT'
'removeLogo':
url: '/api/v0/enterprises/:id/logo.json'
method: 'DELETE'
'removePromoImage':
url: '/api/v0/enterprises/:id/promo_image.json'
method: 'DELETE'
})

View File

@@ -39,17 +39,6 @@ angular.module("admin.resources").factory 'Enterprises', ($q, $filter, Enterpris
resetAttribute: (enterprise, attribute) ->
enterprise[attribute] = @pristineByID[enterprise.id][attribute]
performActionOnEnterpriseResource = (resourceAction) ->
(enterprise) ->
deferred = $q.defer()
resourceAction({id: enterprise.permalink}, ((data) =>
@pristineByID[enterprise.id] = angular.copy(data)
deferred.resolve(data)
), ((response) ->
deferred.reject(response)
))
deferred.promise
findByID: (id) ->
@byID[id]
@@ -61,5 +50,3 @@ angular.module("admin.resources").factory 'Enterprises', ($q, $filter, Enterpris
$filter('filter')(enterprises, term)
removeLogo: performActionOnEnterpriseResource(EnterpriseResource.removeLogo)
removePromoImage: performActionOnEnterpriseResource(EnterpriseResource.removePromoImage)

View File

@@ -69,13 +69,16 @@ module Admin
delete_custom_tab if params[:custom_tab] == 'false'
if @object.update(enterprise_params)
flash[:success] = flash_message_for(@object, :successfully_updated)
flash[:success] = flash_success_message
set_panel_if_attachment_removal
respond_with(@object) do |format|
format.html { redirect_to location_after_save }
format.js { render layout: false }
format.json {
render_as_json @object, ams_prefix: 'index', spree_current_user:
}
format.turbo_stream
end
else
respond_with(@object) do |format|
@@ -164,6 +167,34 @@ module Admin
private
def flash_success_message
if attachment_removal?
I18n.t("admin.controllers.enterprises.#{attachment_removal_parameter}_success")
else
flash_message_for(@object, :successfully_updated)
end
end
def set_panel_if_attachment_removal
return if !attachment_removal?
@panel = if attachment_removal_parameter == "remove_white_label_logo"
"white_label"
elsif ["remove_logo", "remove_promo_image"].include?(attachment_removal_parameter)
"images"
end
end
def attachment_removal?
attachment_removal_parameter.present?
end
def attachment_removal_parameter
if enterprise_params.keys.one? && enterprise_params.keys.first.to_s.start_with?("remove_")
enterprise_params.keys.first
end
end
def load_enterprise_set_on_index
return unless spree_current_user.admin?

View File

@@ -269,6 +269,21 @@ class Enterprise < ApplicationRecord
HtmlSanitizer.sanitize_and_enforce_link_target_blank(html)
end
def remove_logo=(value)
self.logo = nil if ActiveModel::Type::Boolean.new.cast(value)
end
def remove_promo_image=(value)
self.promo_image = nil if ActiveModel::Type::Boolean.new.cast(value)
end
def remove_white_label_logo=(value)
return if !ActiveModel::Type::Boolean.new.cast(value)
self.white_label_logo = nil
self.white_label_logo_link = nil # Link not needed if there's no logo
end
def contact
contact = users.where(enterprise_roles: { receives_notifications: true }).first
contact || owner

View File

@@ -1,12 +0,0 @@
# frozen_string_literal: true
module EnterpriseConcern
extend ActiveSupport::Concern
included do
before_reflex do
@enterprise = Enterprise.find_by(permalink: params[:id])
authorize! :update, @enterprise
end
end
end

View File

@@ -1,22 +0,0 @@
# frozen_string_literal: true
class WhiteLabelReflex < ApplicationReflex
include EnterpriseConcern
delegate :view_context, to: :controller
def remove_logo
@enterprise.update!(white_label_logo: nil)
# delete the white_label_logo_link attribute as well since it has no meaning without the logo
@enterprise.update!(white_label_logo_link: "")
f = ActionView::Helpers::FormBuilder.new(:enterprise, @enterprise, view_context, {})
html = render(partial: "admin/enterprises/form/white_label",
locals: { f:, enterprise: @enterprise })
morph "#white_label_panel", html
flash[:success] = I18n.t("admin.enterprises.form.white_label.remove_logo_success")
cable_ready.dispatch_event(name: "modal:close")
morph_admin_flashes
end
end

View File

@@ -39,7 +39,8 @@ module PermittedAttributes
:preferred_product_low_stock_display,
:hide_ofn_navigation, :white_label_logo, :white_label_logo_link,
:hide_groups_tab, :external_billing_id,
:enable_producers_to_edit_orders
:enable_producers_to_edit_orders,
:remove_logo, :remove_promo_image, :remove_white_label_logo
]
end
end

View File

@@ -1,27 +1,11 @@
.row.page-admin-enterprises-form__logo-field-group.image-field-group
.alpha.three.columns
= f.label :logo
%br
= t('.logo_size')
.omega.eight.columns
%img{ class: 'image-field-group__preview-image', "ng-src": '{{ Enterprise.logo.thumb }}', "ng-if": 'Enterprise.logo' }
%br
= f.file_field :logo
%a.button.red{ href: '', "ng-click": 'removeLogo()', "ng-if": 'Enterprise.logo' }
= t('.remove_logo')
= render "admin/shared/attachment_field", object: @enterprise, attachment_url: @enterprise.logo_url(:thumb), attachment_name: :logo, f: f
.row.page-admin-enterprises-form__promo-image-field-group.image-field-group
.alpha.three.columns
= f.label :promo_image, 'ofn-with-tip' => t('.promo_image_placeholder')
%br/
%span{ style: 'font-weight:bold' }= t('.promo_image_note1')
%br
= t('.promo_image_note2')
%br
= t('.promo_image_note3')
.omega.eight.columns
%img{ class: 'image-field-group__preview-image', "ng-src": '{{ Enterprise.promo_image.large }}', "ng-if": 'Enterprise.promo_image' }
= f.file_field :promo_image
%a.button.red{ href: '', "ng-click": 'removePromoImage()', "ng-if": 'Enterprise.promo_image' }
= t('.remove_promo_image')
= render "admin/shared/attachment_field", object: @enterprise, attachment_url: @enterprise.promo_image_url(:large), attachment_name: :promo_image, f: f do
%br/
= t('.promo_image_placeholder')
%br
%span{ style: 'font-weight:bold' }= t('.promo_image_note1')
%br
= t('.promo_image_note2')
%br
= t('.promo_image_note3')

View File

@@ -5,20 +5,9 @@
= f.label :hide_ofn_navigation, t('.hide_ofn_navigation')
.thirteen.columns
= f.check_box :hide_ofn_navigation, { "data-controller": "checkbox-display", "data-checkbox-display-target-id-value": "white_label_logo" }
%div{id: "white_label_logo"}
.row
.three.columns.alpha
= f.label :white_label_logo, t('.upload_logo')
%br
217 x 44 pixels
.thirteen.columns
= image_tag @object.white_label_logo_url if @object.white_label_logo.present?
%br
= f.file_field :white_label_logo, accept: "image/*"
- if @object.white_label_logo.present?
%button.button.small.red{ type: "button", "data-controller": "modal-link", "data-action": "click->modal-link#open", "data-modal-link-target-value": "remove_logo" }
= t('.remove_logo')
= render "admin/shared/attachment_field", object: @object, attachment_url: @object.white_label_logo_url, attachment_name: :white_label_logo, f: f
- if @object.white_label_logo.present?
.row
@@ -26,12 +15,6 @@
= f.label :white_label_logo_link, t('.white_label_logo_link_label')
.thirteen.columns
= f.text_field :white_label_logo_link
- if @object.white_label_logo.present?
= render ConfirmModalComponent.new(id: "remove_logo", confirm_reflexes: "click->WhiteLabel#remove_logo" ) do
.margin-bottom-30
= t('.remove_logo_confirm')
// Hide groups tab boolean attribute
@@ -50,7 +33,7 @@
= check_box_tag :custom_tab, "true", checked, { "data-controller": "checkbox-display", "data-checkbox-display-target-id-value": "custom_tab_form" }
%div{id: "custom_tab_form"}
= f.fields_for :custom_tab, @object.custom_tab do |custom_tab_form|
= f.fields_for :custom_tab, @object.custom_tab do |custom_tab_form|
.row
.three.columns.alpha
= custom_tab_form.label :title, t('.custom_tab_title')

View File

@@ -0,0 +1,4 @@
= turbo_stream.update "flashes" do
= render partial: "admin/shared/flashes", locals: { flashes: flash } if defined? flash
= turbo_stream.update "#{@panel}_panel" do
= render partial: "admin/enterprises/form/#{@panel}", locals: { f: ActionView::Helpers::FormBuilder.new(:enterprise, @enterprise, self, {}), enterprise: @enterprise }

View File

@@ -0,0 +1,20 @@
.row{ class: "page-admin-enterprises-form__#{attachment_name.to_s.dasherize}-field-group" }
.three.columns.alpha
= f.label attachment_name, t(".#{attachment_name}_label")
%br
- if block_given?
= yield
- else
= t(".#{attachment_name}_hint")
.thirteen.columns
= image_tag attachment_url, class: "image-field-group__preview-image" if object.send(attachment_name).present?
%br
= f.file_field attachment_name, accept: "image/*"
- if object.send(attachment_name).present?
%button.button.small.red{ type: "button", "data-controller": "modal-link", "data-action": "click->modal-link#open", "data-modal-link-target-value": "remove_#{attachment_name}" }
= t(".#{attachment_name}_remove")
- if object.send(attachment_name).present?
= render ConfirmModalComponent.new(id: "remove_#{attachment_name}", confirm_actions: "click->attachment-field#remove", controller: "attachment-field") do
.margin-bottom-30
= t(".#{attachment_name}_remove_confirm")

View File

@@ -0,0 +1,21 @@
import { Controller } from "stimulus";
export default class extends Controller {
async remove() {
const attachmentRemovalParameterKey = this.element.id; // e.g. 'remove_logo'
const action = this.element.closest("form").action;
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
const formData = new FormData();
formData.append(`enterprise[${attachmentRemovalParameterKey}]`, "1")
const response = await fetch(action, {
method: 'PATCH',
headers: {
Accept: 'text/vnd.turbo-stream.html',
'X-CSRF-Token': csrfToken,
},
body: formData
});
const responseTurboStream = await response.text();
Turbo.renderStreamMessage(responseTurboStream);
}
}

View File

@@ -1274,12 +1274,6 @@ en:
legend: "Images"
logo: Logo
logo_size: "300 x 300 pixels"
promo_image_placeholder: 'This image is displayed in "About Us"'
promo_image_note1: 'PLEASE NOTE:'
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
remove_logo: "Remove Image"
remove_promo_image: "Remove Image"
inventory_settings:
legend: "Inventory Settings"
text1: You may opt to manage stock levels and prices in via your
@@ -1457,10 +1451,6 @@ en:
white_label:
legend: "White Label"
hide_ofn_navigation: "Hide OFN navigation"
upload_logo: "Logo used in shopfront"
remove_logo: "Remove logo"
remove_logo_confirm: "Are you sure you want to remove this logo?"
remove_logo_success: "Logo removed"
white_label_logo_link_label: "Link for the logo used in shopfront"
hide_groups_tab: "Hide groups tab in shopfront"
create_custom_tab: "Create custom tab in shopfront"
@@ -1737,6 +1727,22 @@ en:
searching: Searching...
no_matches: No matches found
shared:
attachment_field:
logo_label: "Logo"
logo_hint: 300 x 300 pixels
logo_remove: "Remove Image"
logo_remove_confirm: "The logo will be removed immediately after you confirm."
promo_image_label: "Promo image"
promo_image_note1: 'PLEASE NOTE:'
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
promo_image_placeholder: 'This image is displayed in "About Us"'
promo_image_remove: "Remove Image"
promo_image_remove_confirm: "The promo image will be removed immediately after you confirm."
white_label_logo_label: "Logo used in shopfront"
white_label_logo_hint: 217 x 44 pixels
white_label_logo_remove: "Remove Image"
white_label_logo_remove_confirm: "Are you sure you want to remove this logo?"
user_guide_link:
user_guide: User Guide
enterprises_hubs_tabs:
@@ -2015,6 +2021,9 @@ en:
stripe_connect_cancelled: "Connection to Stripe has been cancelled"
stripe_connect_success: "Stripe account connected successfully"
stripe_connect_fail: Sorry, the connection of your Stripe account failed
remove_logo_success: "Logo removed"
remove_promo_image_success: "Promo image removed"
remove_white_label_logo_success: "Logo removed"
stripe_connect_settings:
resource: Stripe Connect configuration
@@ -3740,10 +3749,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
enterprises:
form:
images:
removed_logo_successfully: "Logo removed successfully"
immediate_logo_removal_warning: "The logo will be removed immediately after you confirm."
removed_promo_image_successfully: "Promo image removed successfully"
immediate_promo_image_removal_warning: "The promo image will be removed immediately after you confirm."
immediate_terms_and_conditions_removal_warning: "The Terms and Conditions file will be removed immediately after you confirm."
removed_terms_and_conditions_successfully: "Terms and Conditions file removed successfully"
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"

View File

@@ -25,72 +25,6 @@ describe "enterpriseCtrl", ->
it "stores enterprise", ->
expect(scope.Enterprise).toEqual enterprise
describe "removing logo", ->
deferred = null
beforeEach inject ($q) ->
spyOn(scope, "$emit")
deferred = $q.defer()
spyOn(window, "confirm").and.returnValue(true)
spyOn(Enterprises, "removeLogo").and.returnValue(deferred.promise)
spyOn(StatusMessage, "display").and.callThrough()
scope.removeLogo()
describe "when successful", ->
beforeEach inject ($rootScope) ->
deferred.resolve()
$rootScope.$digest()
it "emits an 'enterprise:updated' event", ->
expect(scope.$emit).toHaveBeenCalledWith("enterprise:updated", scope.Enterprise)
it "notifies user of success", ->
expect(StatusMessage.display).toHaveBeenCalledWith("success", "Logo removed successfully")
describe "when unsuccessful", ->
beforeEach inject ($rootScope) ->
deferred.reject({ data: { error: "Logo does not exist" } })
$rootScope.$digest()
it "does not emit an 'enterprise:updated' event", ->
expect(scope.$emit).not.toHaveBeenCalled()
it "notifies user of failure", ->
expect(StatusMessage.display).toHaveBeenCalledWith("failure", "Logo does not exist")
describe "removing promo image", ->
deferred = null
beforeEach inject ($q) ->
spyOn(scope, "$emit")
deferred = $q.defer()
spyOn(window, "confirm").and.returnValue(true)
spyOn(Enterprises, "removePromoImage").and.returnValue(deferred.promise)
spyOn(StatusMessage, "display").and.callThrough()
scope.removePromoImage()
describe "when successful", ->
beforeEach inject ($rootScope) ->
deferred.resolve()
$rootScope.$digest()
it "emits an 'enterprise:updated' event", ->
expect(scope.$emit).toHaveBeenCalledWith("enterprise:updated", scope.Enterprise)
it "notifies user of success", ->
expect(StatusMessage.display).toHaveBeenCalledWith("success", "Promo image removed successfully")
describe "when unsuccessful", ->
beforeEach inject ($rootScope) ->
deferred.reject({ data: { error: "Promo image does not exist" } })
$rootScope.$digest()
it "does not emit an 'enterprise:updated' event", ->
expect(scope.$emit).not.toHaveBeenCalled()
it "notifies user of failure", ->
expect(StatusMessage.display).toHaveBeenCalledWith("failure", "Promo image does not exist")
describe "adding managers", ->
u1 = u2 = u3 = null
beforeEach ->

View File

@@ -119,72 +119,3 @@ describe "Enterprises service", ->
Enterprises.resetAttribute(enterprise, "name")
expect(enterprise.name).toEqual "enterprise1"
describe "#removeLogo", ->
enterprise = null
describe "success", ->
resolved = false
beforeEach ->
enterprise = new EnterpriseResource({ id: 15, permalink: "enterprise1", name: "Enterprise 1", logo: {} })
$httpBackend.expectDELETE("/api/v0/enterprises/enterprise1/logo.json").respond 200, { id: 15, name: "Enterprise 1"}
Enterprises.removeLogo(enterprise).then( -> resolved = true)
$httpBackend.flush()
it "updates the pristine copy of the enterprise", ->
expect(Enterprises.pristineByID[15]).not.toBeUndefined()
expect(Enterprises.pristineByID[15]["id"]).toEqual(15)
expect(Enterprises.pristineByID[15]["logo"]).toBeUndefined()
it "resolves the promise", ->
expect(resolved).toBe(true)
describe "failure", ->
rejected = false
beforeEach ->
enterprise = new EnterpriseResource( { id: 15, permalink: "enterprise1", name: "Enterprise 1" } )
$httpBackend.expectDELETE("/api/v0/enterprises/enterprise1/logo.json").respond 409, { error: "obj" }
Enterprises.removeLogo(enterprise).catch( -> rejected = true)
$httpBackend.flush()
it "does not update the pristine copy of the enterprise", ->
expect(Enterprises.pristineByID[15]).toBeUndefined()
it "rejects the promise", ->
expect(rejected).toBe(true)
describe "#removePromoImage", ->
enterprise = null
describe "success", ->
resolved = false
beforeEach ->
enterprise = new EnterpriseResource({ id: 15, permalink: "enterprise1", name: "Enterprise 1", promo_image: {} })
$httpBackend.expectDELETE("/api/v0/enterprises/enterprise1/promo_image.json").respond 200, { id: 15, name: "Enterprise 1"}
Enterprises.removePromoImage(enterprise).then( -> resolved = true)
$httpBackend.flush()
it "updates the pristine copy of the enterprise", ->
expect(Enterprises.pristineByID[15]).not.toBeUndefined()
expect(Enterprises.pristineByID[15]["id"]).toEqual(15)
expect(Enterprises.pristineByID[15]["promo_image"]).toBeUndefined()
it "resolves the promise", ->
expect(resolved).toBe(true)
describe "failure", ->
rejected = false
beforeEach ->
enterprise = new EnterpriseResource( { id: 15, permalink: "enterprise1", name: "Enterprise 1" } )
$httpBackend.expectDELETE("/api/v0/enterprises/enterprise1/promo_image.json").respond 409, { error: "obj" }
Enterprises.removePromoImage(enterprise).catch( -> rejected = true)
$httpBackend.flush()
it "does not update the pristine copy of the enterprise", ->
expect(Enterprises.pristineByID[15]).toBeUndefined()
it "rejects the promise", ->
expect(rejected).toBe(true);

View File

@@ -63,12 +63,15 @@ RSpec.describe "Managing enterprise images" do
# Removing image
within ".page-admin-enterprises-form__logo-field-group" do
accept_alert(alert_text_logo) do
click_on "Remove Image"
end
click_button "Remove Image"
end
expect(page).to have_content("Logo removed successfully")
within ".reveal-modal" do
expect(page).to have_content(alert_text_logo)
click_button "Confirm"
end
expect(flash_message).to match(/Logo removed/)
within ".page-admin-enterprises-form__logo-field-group" do
expect_no_preview_image
@@ -104,12 +107,15 @@ RSpec.describe "Managing enterprise images" do
# Removing image
within ".page-admin-enterprises-form__promo-image-field-group" do
accept_alert(alert_text_promo) do
click_on "Remove Image"
end
click_on "Remove Image"
end
expect(page).to have_content("Promo image removed successfully")
within ".reveal-modal" do
expect(page).to have_content(alert_text_promo)
click_button "Confirm"
end
expect(page).to have_content("Promo image removed")
within ".page-admin-enterprises-form__promo-image-field-group" do
expect_no_preview_image