Merge pull request #9510 from binarygit/convert-enterprises/edit-page-to-stimulus

Convert enterprises/edit page to stimulus
This commit is contained in:
Filipe
2022-08-17 18:11:59 +01:00
committed by GitHub
21 changed files with 223 additions and 196 deletions

View File

@@ -1,15 +0,0 @@
angular.module("admin.enterprise_groups")
.controller "sideMenuCtrl", ($scope, SideMenu) ->
$scope.menu = SideMenu
$scope.select = SideMenu.select
$scope.menu.setItems [
{ name: 'primary_details', label: t('primary_details'), icon_class: "icon-user" }
{ name: 'users', label: t('users'), icon_class: "icon-user" }
{ name: 'about', label: t('about'), icon_class: "icon-pencil" }
{ name: 'images', label: t('images'), icon_class: "icon-picture" }
{ name: 'contact', label: t('admin_enterprise_groups_contact'), icon_class: "icon-phone" }
{ name: 'web', label: t('admin_enterprise_groups_web'), icon_class: "icon-globe" }
]
$scope.select(0)

View File

@@ -1,49 +0,0 @@
angular.module("admin.enterprises")
.controller "sideMenuCtrl", ($scope, $parse, enterprise, SideMenu, enterprisePermissions) ->
$scope.Enterprise = enterprise
$scope.menu = SideMenu
$scope.select = SideMenu.select
$scope.menu.setItems [
{ name: 'primary_details', label: t('primary_details'), icon_class: "icon-home" }
{ name: 'address', label: t('address'), icon_class: "icon-map-marker" }
{ name: 'contact', label: t('contact'), icon_class: "icon-phone" }
{ name: 'social', label: t('social'), icon_class: "icon-twitter" }
{ name: 'about', label: t('about'), icon_class: "icon-pencil" }
{ name: 'business_details', label: t('business_details'), icon_class: "icon-briefcase" }
{ name: 'images', label: t('images'), icon_class: "icon-picture" }
{ name: 'properties', label: t('properties'), icon_class: "icon-tags", show: "showProperties()" }
{ name: 'shipping_methods', label: t('shipping_methods'), icon_class: "icon-truck", show: "showShippingMethods()" }
{ name: 'payment_methods', label: t('payment_methods'), icon_class: "icon-money", show: "showPaymentMethods()" }
{ name: 'enterprise_fees', label: t('enterprise_fees'), icon_class: "icon-tasks", show: "showEnterpriseFees()" }
{ name: 'enterprise_permissions', label: t('enterprise_permissions'), icon_class: "icon-plug" }
{ name: 'inventory_settings', label: t('inventory_settings'), icon_class: "icon-list-ol", show: "enterpriseIsShop()" }
{ name: 'tag_rules', label: t('tag_rules'), icon_class: "icon-random", show: "enterpriseIsShop()" }
{ name: 'shop_preferences', label: t('shop_preferences'), icon_class: "icon-shopping-cart", show: "enterpriseIsShop()" }
{ name: 'users', label: t('users'), icon_class: "icon-user" }
]
SideMenu.init()
$scope.showItem = (item) ->
if item.show?
$parse(item.show)($scope)
else
true
$scope.showProperties = ->
!!$scope.Enterprise.is_primary_producer
$scope.showShippingMethods = ->
enterprisePermissions.can_manage_shipping_methods && $scope.Enterprise.sells != "none"
$scope.showPaymentMethods = ->
enterprisePermissions.can_manage_payment_methods && $scope.Enterprise.sells != "none"
$scope.showEnterpriseFees = ->
enterprisePermissions.can_manage_enterprise_fees && ($scope.Enterprise.sells != "none" || $scope.Enterprise.is_primary_producer)
$scope.enterpriseIsShop = ->
$scope.Enterprise.sells != "none"
$scope.menu.redirect_function('enterprise_permissions', '/admin/enterprise_relationships')

View File

@@ -7,6 +7,7 @@ require 'open_food_network/order_cycle_permissions'
module Admin
class EnterprisesController < Admin::ResourceController
include GeocodeEnterpriseAddress
include CablecarResponses
# These need to run before #load_resource so that @object is initialised with sanitised values
prepend_before_action :override_owner, only: :create
@@ -44,7 +45,11 @@ module Admin
def edit
@object = Enterprise.where(permalink: params[:id]).
includes(users: [:ship_address, :bill_address]).first
super
if params[:stimulus]
@enterprise.is_primary_producer = params[:is_primary_producer]
@enterprise.sells = params[:enterprise_sells]
render operations: cable_car.morph("#side_menu", partial("admin/shared/side_menu"))
end
end
def welcome

View File

@@ -0,0 +1,17 @@
# frozen_string_literal: true
module Admin
module EnterpriseGroupsHelper
def enterprise_group_side_menu_items
[
{ name: 'primary_details', label: 'primary_details', icon_class: "icon-user",
selected: "selected" },
{ name: 'users', label: 'users', icon_class: "icon-user" },
{ name: 'about', label: 'about', icon_class: "icon-pencil" },
{ name: 'images', label: 'images', icon_class: "icon-picture" },
{ name: 'contact', label: 'admin_enterprise_groups_contact', icon_class: "icon-phone" },
{ name: 'web', label: 'admin_enterprise_groups_web', icon_class: "icon-globe" },
]
end
end
end

View File

@@ -13,5 +13,34 @@ module Admin
def select_only_item(producers)
producers.size == 1 ? producers.first.id : nil
end
def enterprise_side_menu_items(enterprise)
is_shop = enterprise.sells != "none"
show_properties = !!enterprise.is_primary_producer
show_shipping_methods = can?(:manage_shipping_methods, enterprise) && is_shop
show_payment_methods = can?(:manage_payment_methods, enterprise) && is_shop
show_enterprise_fees = can?(:manage_enterprise_fees,
enterprise) && (is_shop || enterprise.is_primary_producer)
[
{ name: 'primary_details', icon_class: "icon-home", show: true, selected: 'selected' },
{ name: 'address', icon_class: "icon-map-marker", show: true },
{ name: 'contact', icon_class: "icon-phone", show: true },
{ name: 'social', icon_class: "icon-twitter", show: true },
{ name: 'about', icon_class: "icon-pencil", show: true, form_name: "about_us" },
{ name: 'business_details', icon_class: "icon-briefcase", show: true },
{ name: 'images', icon_class: "icon-picture", show: true },
{ name: 'properties', icon_class: "icon-tags", show: show_properties },
{ name: 'shipping_methods', icon_class: "icon-truck", show: show_shipping_methods },
{ name: 'payment_methods', icon_class: "icon-money", show: show_payment_methods },
{ name: 'enterprise_fees', icon_class: "icon-tasks", show: show_enterprise_fees },
{ name: 'enterprise_permissions', icon_class: "icon-plug", show: true,
href: admin_enterprise_relationships_path },
{ name: 'inventory_settings', icon_class: "icon-list-ol", show: is_shop },
{ name: 'tag_rules', icon_class: "icon-random", show: is_shop },
{ name: 'shop_preferences', icon_class: "icon-shopping-cart", show: is_shop },
{ name: 'users', icon_class: "icon-user", show: true }
]
end
end
end

View File

@@ -1,7 +1,7 @@
= render 'spree/shared/error_messages', target: @enterprise
= form_for [main_app, :admin, @enterprise_group] do |f|
.row{ ng: {app: 'admin.enterprise_groups', controller: 'enterpriseGroupCtrl'} }
.row{ ng: {app: 'admin.enterprise_groups', controller: 'enterpriseGroupCtrl'}, data: { controller: 'tabs-and-panels', "tabs-and-panels-class-name-value": "selected" } }
.sixteen.columns.alpha
.four.columns.alpha
= render 'admin/shared/side_menu'

View File

@@ -1,5 +1,5 @@
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='about'" } }
%legend {{menu.selected.label}}
%fieldset.alpha.no-border-bottom#about_panel{ data: { "tabs-and-panels-target": "panel" } }
%legend= t('about')
= f.field_container :long_description do
%text-angular{'id' => 'enterprise_group_long_description', 'name' => 'enterprise_group[long_description]', 'class' => 'text-angular', "textangular-links-target-blank" => true,
'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]"}

View File

@@ -1,6 +1,6 @@
= f.fields_for :address do |af|
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='contact'" } }
%legend {{menu.selected.label}}
%fieldset.alpha.no-border-bottom#contact_panel{ data: { "tabs-and-panels-target": "panel" } }
%legend= t('admin_enterprise_groups_contact')
.row
.alpha.three.columns
= af.label :phone

View File

@@ -1,5 +1,5 @@
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='images'" } }
%legend {{menu.selected.label}}
%fieldset.alpha.no-border-bottom#images_panel{ data: { "tabs-and-panels-target": "panel" } }
%legend= t('images')
.row
.alpha.three.columns
= f.label :logo, 'ofn-with-tip' => t('admin_enterprise_groups_data_powertip_logo')

View File

@@ -1,5 +1,5 @@
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='primary_details'" } }
%legend {{menu.selected.label}}
%fieldset.alpha.no-border-bottom#primary_details_panel{ data: { "tabs-and-panels-target": "panel default" } }
%legend= t('primary_details')
= f.field_container :name do
= f.label :name
%br/

View File

@@ -1,5 +1,5 @@
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='users'" } }
%legend {{menu.selected.label}}
%fieldset.alpha.no-border-bottom#users_panel{ data: { "tabs-and-panels-target": "panel" } }
%legend= t('users')
.row
.three.columns.alpha
=f.label :owner_id, t(:admin_enterprise_groups_owner)

View File

@@ -1,5 +1,5 @@
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='web'" } }
%legend {{menu.selected.label}}
%fieldset.alpha.no-border-bottom#web_panel{ data: { "tabs-and-panels-target": "panel" } }
%legend= t('admin_enterprise_groups_web')
.row
.alpha.three.columns
= f.label :website

View File

@@ -1,63 +1,21 @@
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='primary_details'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/primary_details', f: f
- enterprise_side_menu_items(@enterprise).each do |item|
- case item[:name]
- when 'primary_details'
%fieldset.alpha.no-border-bottom{ id: "#{item[:name]}_panel", data: { controller: "primary-details", "primary-details-primary-producer-value": @enterprise.is_primary_producer.to_s, "primary-details-enterprise-sells-value": @enterprise.sells, "tabs-and-panels-target": "panel default" }}
%legend= t("#{ item[:name] }")
= render "admin/enterprises/form/#{ item[:form_name] || item[:name] }", f: f
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='users'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/users', f: f
- when 'address'
= f.fields_for :address do |af|
%fieldset.alpha.no-border-bottom{ id: "#{item[:name]}_panel", data: { "tabs-and-panels-target": "panel" }}
%legend= t("#{ item[:name] }")
= render 'admin/enterprises/form/address', af: af
= f.fields_for :address do |af|
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='address'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/address', af: af
- when 'enterprise_permissions'
%fieldset.alpha.no-border-bottom{ id: "#{item[:name]}_panel", data: { "tabs-and-panels-target": "panel" }}
%legend= t("#{ item[:name] }")
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='contact'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/contact', f: f
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='social'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/social', f: f
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='business_details'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/business_details', f: f
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='about'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/about_us', f: f
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='images'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/images', f: f
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='properties'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/properties', f: f
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='shipping_methods'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/shipping_methods', f: f
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='payment_methods'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/payment_methods', f: f
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='enterprise_fees'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/enterprise_fees', f: f
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='enterprise_permissions'" } }
%legend {{menu.selected.label}}
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='inventory_settings'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/inventory_settings', f: f
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='shop_preferences'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/shop_preferences', f: f
%fieldset.alpha.no-border-bottom{ ng: { if: "menu.selected.name=='tag_rules'" } }
%legend {{menu.selected.label}}
= render 'admin/enterprises/form/tag_rules', f: f
- else
%fieldset.alpha.no-border-bottom{ id: "#{item[:name]}_panel", data: { "tabs-and-panels-target": "panel" }}
%legend= t("#{ item[:name] }")
= render "admin/enterprises/form/#{ item[:form_name] || item[:name] }", f: f

View File

@@ -10,7 +10,8 @@
%input.red{ type: "button", value: t(:update), ng: { click: "submit()", disabled: "!enterprise_form.$dirty" } }
%input{ type: "button", ng: { value: "enterprise_form.$dirty ? '#{t(:cancel)}' : '#{t(:close)}'", click: "cancel('#{main_app.admin_enterprises_path}')" } }
.row
.row{ data: {
controller: "tabs-and-panels", "tabs-and-panels-class-name-value": "selected" }}
.sixteen.columns.alpha
.four.columns.alpha
= render 'admin/shared/side_menu'

View File

@@ -12,14 +12,13 @@
%a= t('admin.whats_this')
.eight.columns.omega
= f.collection_select :group_ids, @groups, :id, :name, {}, class: "select2 fullwidth", multiple: true, placeholder: t('.groups_placeholder')
.row
.three.columns.alpha
%label= t('.primary_producer')
%div{'ofn-with-tip' => t('.primary_producer_tip')}
%a= t('admin.whats_this')
.five.columns.omega
= f.check_box :is_primary_producer, 'ng-model' => 'Enterprise.is_primary_producer'
= f.check_box :is_primary_producer, data: { action: "change->primary-details#primaryProducerChanged" }
= f.label :is_primary_producer, t('.producer')
- if spree_current_user.admin?
.row
@@ -28,13 +27,13 @@
%div{'ofn-with-tip' => t('.sells_tip')}
%a= t('admin.whats_this')
.two.columns
= f.radio_button :sells, "none", 'ng-model' => 'Enterprise.sells'
= f.radio_button :sells, "none", 'ng-model' => 'Enterprise.sells', data: {action: "change->primary-details#enterpriseSellsChanged"}
= f.label :sells, t('.none'), value: "none"
.two.columns
= f.radio_button :sells, "own", 'ng-model' => 'Enterprise.sells'
= f.radio_button :sells, "own", 'ng-model' => 'Enterprise.sells', data: {action: "change->primary-details#enterpriseSellsChanged"}
= f.label :sells, t('.own'), value: "own"
.four.columns.omega
= f.radio_button :sells, "any", 'ng-model' => 'Enterprise.sells'
= f.radio_button :sells, "any", 'ng-model' => 'Enterprise.sells', data: {action: "change->primary-details#enterpriseSellsChanged"}
= f.label :sells, t('.any'), value: "any"
.row
.three.columns.alpha

View File

@@ -1,8 +1,13 @@
.side_menu{ ng: { controller: 'sideMenuCtrl' } }
%a.menu_item{ href: "", id: "{{ item.name.toLowerCase().replace(' ', '_') }}",
ng: { repeat: '(index,item) in menu.items | filter:{visible:true}',
click: 'select(index)',
show: '!showItem || showItem(item)',
class: '{ selected: item.selected }' } }
%i{ class: "{{item.icon_class}}" }
%span {{ item.label }}
.side_menu#side_menu
- if @enterprise
- enterprise_side_menu_items(@enterprise).each do |item|
- next unless item[:show]
%a.menu_item{ href: item[:href] || "##{item[:name]}_panel", id: item[:name], data: { action: "tabs-and-panels#changeActivePanel tabs-and-panels#changeActiveTab", "tabs-and-panels-target": "tab" }, class: item[:selected] }
%i{ class: item[:icon_class] }
%span= t("#{item[:name] }")
- else
- enterprise_group_side_menu_items.each do |item|
%a.menu_item{ href: "##{item[:name]}_panel", class: item[:selected], id: item[:name], data: { action: "tabs-and-panels#changeActivePanel tabs-and-panels#changeActiveTab", "tabs-and-panels-target": "tab" } }
%i{ class: item[:icon_class] }
%span= t("#{item[:label] }")

View File

@@ -0,0 +1,30 @@
import { Controller } from "stimulus";
import CableReady from "cable_ready";
export default class extends Controller {
static values = { primaryProducer: String, enterpriseSells: String };
primaryProducerChanged(event) {
this.primaryProducerValue = event.currentTarget.checked;
this.makeRequest();
}
enterpriseSellsChanged(event) {
if (event.currentTarget.checked) {
this.enterpriseSellsValue = event.currentTarget.value;
this.makeRequest();
}
}
makeRequest() {
fetch(
`?stimulus=true&enterprise_sells=${this.enterpriseSellsValue}&is_primary_producer=${this.primaryProducerValue}`,
{
method: "GET",
headers: { "Content-type": "application/json; charset=UTF-8" },
}
)
.then((data) => data.json())
.then(CableReady.perform);
}
}

View File

@@ -0,0 +1,40 @@
import { Controller } from "stimulus";
export default class extends Controller {
static targets = ["tab", "panel", "default"];
static values = { className: String };
connect() {
// hide all active panel
this.panelTargets.forEach((panel) => {
panel.style.display = "none";
});
// only display the default panel
this.defaultTarget.style.display = "block";
}
changeActivePanel(event) {
const newActivePanel = this.panelTargets.find(
(panel) => panel.id == `${event.currentTarget.id}_panel`
);
this.currentActivePanel.style.display = "none";
newActivePanel.style.display = "block";
}
changeActiveTab(event) {
this.currentActiveTab.classList.remove(`${this.classNameValue}`);
event.currentTarget.classList.add(`${this.classNameValue}`);
}
get currentActiveTab() {
return this.tabTargets.find((tab) => tab.classList.contains("selected"));
}
get currentActivePanel() {
return this.panelTargets.find(
(panel) => panel.id == `${this.currentActiveTab.id}_panel`
);
}
}

View File

@@ -0,0 +1,48 @@
/**
* @jest-environment jsdom
*/
import { Application } from "stimulus";
import tabs_and_panels_controller from "../../../app/webpacker/controllers/tabs_and_panels_controller";
describe("EnterprisePanelController", () => {
beforeAll(() => {
const application = Application.start();
application.register("tabs-and-panels", tabs_and_panels_controller);
});
describe("#tabs-and-panels", () => {
beforeEach(() => {
document.body.innerHTML = `
<div data-controller="tabs-and-panels" data-tabs-and-panels-class-name-value="selected">
<a id="peek" href="#" data-action="tabs-and-panels#changeActivePanel tabs-and-panels#changeActiveTab" class="selected" data-tabs-and-panels-target="tab">Peek</a>
<a id="ka" href="#" data-action="tabs-and-panels#changeActivePanel tabs-and-panels#changeActiveTab" data-tabs-and-panels-target="tab">Ka</a>
<a id="boo" href="#" data-action="tabs-and-panels#changeActivePanel tabs-and-panels#changeActiveTab" data-tabs-and-panels-target="tab">Boo</a>
<div id="peek_panel" data-tabs-and-panels-target="panel default">Peek me</div>
<div id="ka_panel" data-tabs-and-panels-target="panel">Ka you</div>
<div id="boo_panel" data-tabs-and-panels-target="panel">Boo three</div>
</div>`;
});
it("displays only the default panel", () => {
const peekPanel = document.getElementById("peek_panel");
const kaPanel = document.getElementById("ka_panel");
const booPanel = document.getElementById("boo_panel");
expect(peekPanel.style.display).toBe("block");
expect(kaPanel.style.display).toBe("none");
expect(booPanel.style.display).toBe("none");
});
it("displays appropriate panel when associated tab is clicked", () => {
const kaPanel = document.getElementById("ka_panel");
const ka = document.getElementById("ka");
expect(kaPanel.style.display).toBe("none");
ka.click();
expect(kaPanel.style.display).toBe("block");
});
});
});

View File

@@ -1,41 +0,0 @@
describe "menuCtrl", ->
ctrl = null
scope = null
enterprise = null
SideMenu = SideMenu
beforeEach ->
module('admin.enterprises')
enterprise =
payment_method_ids: [ 1, 3 ]
shipping_method_ids: [ 2, 4 ]
# PaymentMethods =
# paymentMethods: [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 } ]
# ShippingMethods =
# shippingMethods: [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4 } ]
inject ($rootScope, $controller, _SideMenu_) ->
scope = $rootScope
SideMenu = _SideMenu_
spyOn(SideMenu, "init").and.callThrough()
spyOn(SideMenu, "select").and.callThrough()
spyOn(SideMenu, "setItems").and.callThrough()
ctrl = $controller 'sideMenuCtrl', {$scope: scope, enterprise: enterprise, SideMenu: SideMenu, enterprisePermissions: {}}
describe "initialisation", ->
it "stores enterprise", ->
expect(scope.Enterprise).toEqual enterprise
it "sets the item list", ->
expect(SideMenu.setItems).toHaveBeenCalled
expect(scope.menu.items).toBe SideMenu.items
it "sets the initally selected value", ->
expect(SideMenu.init).toHaveBeenCalled()
describe "selecting an item", ->
it "selects an item by performing setting the selected property on the item to true", ->
scope.select 4
expect(SideMenu.select).toHaveBeenCalledWith 4
expect(scope.menu.items[4].selected).toBe true

View File

@@ -108,7 +108,7 @@ describe '
description_input = page.find("text-angular#enterprise_long_description div[id^='taTextElement']")
description_input.native.send_keys('This is an interesting long description')
# Check Angularjs switching of sidebar elements
# Check StimulusJs switching of sidebar elements
accept_alert do
click_link "Primary Details"
end
@@ -485,7 +485,7 @@ describe '
end
choose "enterprise_preferred_shopfront_product_sorting_method_by_category"
find("#s2id_autogen7").click
find("#s2id_enterprise_preferred_shopfront_taxon_order").click
find(".select2-result-label", text: "Tricky Taxon").click
click_button 'Update'
expect(flash_message).to eq('Enterprise "First Distributor" has been successfully updated!')
@@ -506,7 +506,7 @@ describe '
end
choose "enterprise_preferred_shopfront_product_sorting_method_by_producer"
find("#s2id_autogen8").click
find("#s2id_enterprise_preferred_shopfront_producer_order").click
find(".select2-result-label", text: "First Supplier").click
click_button 'Update'
expect(flash_message).to eq('Enterprise "First Distributor" has been successfully updated!')