diff --git a/app/assets/javascripts/admin/admin_ofn.js.coffee b/app/assets/javascripts/admin/admin_ofn.js.coffee index 39ca45a89f..bf21d3f0c3 100644 --- a/app/assets/javascripts/admin/admin_ofn.js.coffee +++ b/app/assets/javascripts/admin/admin_ofn.js.coffee @@ -12,5 +12,6 @@ angular.module("ofn.admin", [ "admin.orders" ]).config ($httpProvider, $locationProvider, $qProvider) -> $httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*" + # for the next line, you should also probably check file: app/assets/javascripts/admin/utils/utils.js.coffee $locationProvider.hashPrefix('') $qProvider.errorOnUnhandledRejections(false) diff --git a/app/assets/javascripts/admin/utils/utils.js.coffee b/app/assets/javascripts/admin/utils/utils.js.coffee index b8e1198e76..0cd9678eaf 100644 --- a/app/assets/javascripts/admin/utils/utils.js.coffee +++ b/app/assets/javascripts/admin/utils/utils.js.coffee @@ -1,3 +1,4 @@ angular.module("admin.utils", ["templates", "ngSanitize"]).config ($httpProvider, $locationProvider) -> + # for the next line, you should also probably check file: app/assets/javascripts/admin/admin_ofn.js.coffee $locationProvider.hashPrefix('') $httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*" diff --git a/app/components/confirm_modal_component.rb b/app/components/confirm_modal_component.rb index d942ed5551..3a73af0e68 100644 --- a/app/components/confirm_modal_component.rb +++ b/app/components/confirm_modal_component.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true class ConfirmModalComponent < ModalComponent - def initialize(id:, confirm_actions: nil, controllers: nil, message: nil) + def initialize(id:, confirm_actions: nil, controllers: nil, message: nil, confirm_reflexes: nil) super(id: id, close_button: true) @confirm_actions = confirm_actions + @confirm_reflexes = confirm_reflexes @controllers = controllers @message = message end diff --git a/app/components/confirm_modal_component/confirm_modal_component.html.haml b/app/components/confirm_modal_component/confirm_modal_component.html.haml index 7da8ccebc6..0c507885ce 100644 --- a/app/components/confirm_modal_component/confirm_modal_component.html.haml +++ b/app/components/confirm_modal_component/confirm_modal_component.html.haml @@ -7,4 +7,4 @@ .modal-actions %input{ class: "button icon-plus #{close_button_class}", type: 'button', value: t('js.admin.modals.cancel'), "data-action": "click->modal#close" } - %input{ class: "button icon-plus primary", type: 'button', value: t('js.admin.modals.confirm'), "data-action": @confirm_actions } + %input{ class: "button icon-plus primary", type: 'button', value: t('js.admin.modals.confirm'), "data-action": @confirm_actions, "data-reflex": @confirm_reflexes } diff --git a/app/controllers/concerns/white_label.rb b/app/controllers/concerns/white_label.rb index 180d138237..63fff5a525 100644 --- a/app/controllers/concerns/white_label.rb +++ b/app/controllers/concerns/white_label.rb @@ -10,5 +10,12 @@ module WhiteLabel # if the distributor has the hide_ofn_navigation preference set to true # then we should hide the OFN navigation @hide_ofn_navigation = distributor.hide_ofn_navigation + + # if the distributor has the hide_ofn_navigation preference + # set to false, there is no need to check the white_label_logo preference + return unless @hide_ofn_navigation + + @white_label_logo = distributor.white_label_logo + @white_label_distributor = distributor end end diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 2716bde87c..2dd3afd545 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -15,6 +15,10 @@ class Enterprise < ApplicationRecord medium: { resize_to_fill: [720, 156] }, large: { resize_to_fill: [1200, 260] }, }.freeze + WHITE_LABEL_LOGO_SIZES = { + default: { gravity: "Center", resize_to_fill: [217, 44] }, + mobile: { gravity: "Center", resize_to_fill: [75, 26] }, + }.freeze VALID_INSTAGRAM_REGEX = %r{\A[a-zA-Z0-9._]{1,30}([^/-]*)\z} searchable_attributes :sells, :is_primary_producer, :name @@ -84,6 +88,7 @@ class Enterprise < ApplicationRecord has_one_attached :logo has_one_attached :promo_image has_one_attached :terms_and_conditions + has_one_attached :white_label_logo validates :logo, processable_image: true, @@ -302,6 +307,14 @@ class Enterprise < ApplicationRecord ) end + def white_label_logo_url(name = :default) + return unless white_label_logo.variable? + + Rails.application.routes.url_helpers.url_for( + white_label_logo.variant(WHITE_LABEL_LOGO_SIZES[name]) + ) + end + def website strip_url self[:website] end diff --git a/app/reflexes/concerns/enterprise_concern.rb b/app/reflexes/concerns/enterprise_concern.rb new file mode 100644 index 0000000000..f508652fbd --- /dev/null +++ b/app/reflexes/concerns/enterprise_concern.rb @@ -0,0 +1,12 @@ +# 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 diff --git a/app/reflexes/white_label_reflex.rb b/app/reflexes/white_label_reflex.rb new file mode 100644 index 0000000000..4412028c92 --- /dev/null +++ b/app/reflexes/white_label_reflex.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class WhiteLabelReflex < ApplicationReflex + include EnterpriseConcern + delegate :view_context, to: :controller + + def remove_logo + @enterprise.update!(white_label_logo: nil) + + f = ActionView::Helpers::FormBuilder.new(:enterprise, @enterprise, view_context, {}) + + html = with_locale { + render(partial: "admin/enterprises/form/white_label", + locals: { f: f, enterprise: @enterprise }) + } + morph "#white_label_panel", html + + flash[:success] = with_locale { + I18n.t("admin.enterprises.form.white_label.remove_logo_success") + } + cable_ready.dispatch_event(name: "modal:close") + morph "#flashes", render(partial: "shared/flashes", locals: { flashes: flash }) + end +end diff --git a/app/serializers/api/admin/enterprise_serializer.rb b/app/serializers/api/admin/enterprise_serializer.rb index 9afed8e532..d74bd19cd6 100644 --- a/app/serializers/api/admin/enterprise_serializer.rb +++ b/app/serializers/api/admin/enterprise_serializer.rb @@ -14,7 +14,7 @@ module Api :logo, :promo_image, :terms_and_conditions, :terms_and_conditions_file_name, :terms_and_conditions_updated_at, :preferred_invoice_order_by_supplier, :preferred_product_low_stock_display, - :visible, :hide_ofn_navigation + :visible, :hide_ofn_navigation, :white_label_logo has_one :owner, serializer: Api::Admin::UserSerializer has_many :users, serializer: Api::Admin::UserSerializer @@ -29,6 +29,10 @@ module Api attachment_urls(object.promo_image, Enterprise::PROMO_IMAGE_SIZES) end + def white_label_logo + attachment_urls(object.white_label_logo, Enterprise::WHITE_LABEL_LOGO_SIZES) + end + def terms_and_conditions return unless object.terms_and_conditions.attached? diff --git a/app/serializers/api/enterprise_shopfront_serializer.rb b/app/serializers/api/enterprise_shopfront_serializer.rb index 12ca4d1b79..717ca394c7 100644 --- a/app/serializers/api/enterprise_shopfront_serializer.rb +++ b/app/serializers/api/enterprise_shopfront_serializer.rb @@ -10,7 +10,7 @@ module Api :phone, :whatsapp_phone, :whatsapp_url, :visible, :email_address, :hash, :logo, :promo_image, :path, :category, :active, :producers, :orders_close_at, :hubs, :taxons, :supplied_taxons, :pickup, :delivery, :preferred_product_low_stock_display, - :hide_ofn_navigation + :hide_ofn_navigation, :white_label_logo has_one :address, serializer: Api::AddressSerializer has_many :supplied_properties, serializer: Api::PropertySerializer @@ -49,6 +49,10 @@ module Api enterprise.promo_image_url(:large) end + def white_label_logo + enterprise.white_label_logo_url + end + def path enterprise_shop_path(enterprise) end diff --git a/app/services/permitted_attributes/enterprise.rb b/app/services/permitted_attributes/enterprise.rb index c72a24cfa7..cd0e704392 100644 --- a/app/services/permitted_attributes/enterprise.rb +++ b/app/services/permitted_attributes/enterprise.rb @@ -35,7 +35,7 @@ module PermittedAttributes :show_customer_names_to_suppliers, :preferred_shopfront_product_sorting_method, :preferred_invoice_order_by_supplier, :preferred_product_low_stock_display, - :hide_ofn_navigation + :hide_ofn_navigation, :white_label_logo, ] end end diff --git a/app/views/admin/enterprises/form/_white_label.html.haml b/app/views/admin/enterprises/form/_white_label.html.haml index b083ec7700..eb15cb1934 100644 --- a/app/views/admin/enterprises/form/_white_label.html.haml +++ b/app/views/admin/enterprises/form/_white_label.html.haml @@ -1,6 +1,23 @@ +- @object ||= enterprise + .row .three.columns.alpha = f.label :hide_ofn_navigation, t('.hide_ofn_navigation') .three.columns - = f.check_box :hide_ofn_navigation + = f.check_box :hide_ofn_navigation, { "data-controller": "checkbox-display", "data-checkbox-display-target-id-value": "white_label_logo" } +.row{id: "white_label_logo"} + .three.columns.alpha + = f.label :white_label_logo, t('.upload_logo') + .three.columns + = image_tag @object.white_label_logo_url if @object.white_label_logo.present? + = f.file_field :white_label_logo, accept: "image/*" + - if @object.white_label_logo.variable? + %button.button.small{ type: "button", "data-controller": "modal-link", "data-action": "click->modal-link#open", "data-modal-link-target-value": "remove_logo" } + = t('.remove_logo') + + +- if @object.white_label_logo.variable? + = render ConfirmModalComponent.new(id: "remove_logo", confirm_reflexes: "click->WhiteLabel#remove_logo" ) do + .margin-bottom-30 + = t('.remove_logo_confirm') diff --git a/app/views/shared/menu/_large_menu.html.haml b/app/views/shared/menu/_large_menu.html.haml index ec64ecdcf5..cfb7aa0640 100644 --- a/app/views/shared/menu/_large_menu.html.haml +++ b/app/views/shared/menu/_large_menu.html.haml @@ -3,7 +3,10 @@ %ul.nav-logo %li.ofn-logo %a{href: main_app.root_path} - %img{src: ContentConfig.url_for(:logo)} + - if @white_label_logo&.variable? + = image_tag @white_label_distributor.white_label_logo_url(:default) + - else + %img{src: ContentConfig.url_for(:logo)} %li.powered-by %img{src: '/favicon.ico'} %span diff --git a/app/views/shared/menu/_mobile_menu.html.haml b/app/views/shared/menu/_mobile_menu.html.haml index aca1fa70d6..75540b5ed9 100644 --- a/app/views/shared/menu/_mobile_menu.html.haml +++ b/app/views/shared/menu/_mobile_menu.html.haml @@ -6,7 +6,10 @@ %section.left .ofn-logo %a{href: main_app.root_path} - %img{src: ContentConfig.url_for(:logo_mobile), srcset: ContentConfig.url_for(:logo_mobile_svg), width: "75", height: "26"} + - if @white_label_logo&.variable? + = image_tag @white_label_distributor.white_label_logo_url(:mobile) + - else + %img{src: ContentConfig.url_for(:logo_mobile), srcset: ContentConfig.url_for(:logo_mobile_svg), width: "75", height: "26"} %section.right{"ng-cloak" => true} %span.cart-span{"ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"} diff --git a/app/webpacker/controllers/checkbox_display_controller.js b/app/webpacker/controllers/checkbox_display_controller.js new file mode 100644 index 0000000000..ae82b46224 --- /dev/null +++ b/app/webpacker/controllers/checkbox_display_controller.js @@ -0,0 +1,37 @@ +import { Controller } from "stimulus"; + +export default class extends Controller { + static values = { targetId: String }; + + connect() { + this.element.addEventListener("change", this.change.bind(this)); + if (this.element.checked) { + this.showTarget(); + } else { + this.hideTarget(); + } + } + + disconnect() { + this.element.removeEventListener("change", this.change.bind(this)); + } + + change(event) { + // if the checkbox is checked, display the target + if (this.element.checked) { + this.showTarget(); + } else { + this.hideTarget(); + } + } + + showTarget() { + let target = document.getElementById(this.targetIdValue); + target.style.display = "block"; + } + + hideTarget() { + let target = document.getElementById(this.targetIdValue); + target.style.display = "none"; + } +} diff --git a/config/locales/en.yml b/config/locales/en.yml index 37e31bca99..e9fba7e4f8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1161,6 +1161,10 @@ 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" actions: edit_profile: Settings properties: Properties diff --git a/spec/javascripts/stimulus/checkbox_display_controller_test.js b/spec/javascripts/stimulus/checkbox_display_controller_test.js new file mode 100644 index 0000000000..2af8fad59c --- /dev/null +++ b/spec/javascripts/stimulus/checkbox_display_controller_test.js @@ -0,0 +1,39 @@ +/** + * @jest-environment jsdom + */ + +import { Application } from "stimulus"; +import checkbox_display_controller from "../../../app/webpacker/controllers/checkbox_display_controller"; + +describe("CheckboxDisplayController", () => { + beforeAll(() => { + const application = Application.start(); + application.register("checkbox-display", checkbox_display_controller); + }); + + describe("#toggle", () => { + beforeEach(() => { + document.body.innerHTML = `