Add warning modal to order cycle with attached schedule general setting form [OFN-11613]

This commit is contained in:
wandji20
2024-07-09 18:20:36 +01:00
parent 193e17b625
commit 0de8a90b14
8 changed files with 216 additions and 12 deletions

View File

@@ -167,6 +167,8 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, $
if destination?
$window.location = destination
else
if ($window.adminOrderCycleUpdateCallback)
adminOrderCycleUpdateCallback(data.order_cycle);
StatusMessage.display 'success', t('js.order_cycles.update_success')
, (response) ->
if response.data.errors?

View File

@@ -70,7 +70,12 @@ module Admin
respond_to do |format|
flash[:success] = t('.success') if params[:reloading] == '1'
format.html { redirect_to_after_update_path }
format.json { render json: { success: true } }
format.json {
render json: { success: true, order_cycle: {
orders_open_at: @order_cycle.orders_open_at&.strftime('%Y-%m-%d %H:%M'),
orders_close_at: @order_cycle.orders_close_at&.strftime('%Y-%m-%d %H:%M')
} }
}
end
elsif request.format.html?
render :checkout_options

View File

@@ -11,7 +11,7 @@
= f.label :orders_open_at, t('.orders_open')
.omega.six.columns.fullwidth_inputs
- if viewing_as_coordinator_of?(@order_cycle)
= f.text_field :orders_open_at, data: { controller: "flatpickr", "flatpickr-enable-time-value": true }, 'ng-model' => 'order_cycle.orders_open_at', 'ng-if' => 'loaded()', 'change-warning' => 'order_cycle', class: "datetimepicker"
= f.text_field :orders_open_at, data: { controller: "flatpickr", "flatpickr-enable-time-value": true, action: 'order-cycle#toggleSaveBtns', 'order-cycle-target': 'input' }, 'ng-model' => 'order_cycle.orders_open_at', 'ng-if' => 'loaded()', 'change-warning' => 'order_cycle', class: "datetimepicker"
- else
{{ order_cycle.orders_open_at }}
@@ -24,7 +24,7 @@
= f.label :orders_close, t('.orders_close')
.six.columns.omega.fullwidth_inputs
- if viewing_as_coordinator_of?(@order_cycle)
= f.text_field :orders_close_at, data: { controller: "flatpickr", "flatpickr-enable-time-value": true }, 'ng-model' => 'order_cycle.orders_close_at', 'ng-if' => 'loaded()', 'change-warning' => 'order_cycle', class: "datetimepicker"
= f.text_field :orders_close_at, data: { controller: "flatpickr", "flatpickr-enable-time-value": true, action: 'order-cycle#toggleSaveBtns', 'order-cycle-target': 'input' }, 'ng-model' => 'order_cycle.orders_close_at', 'ng-if' => 'loaded()', 'change-warning' => 'order_cycle', class: "datetimepicker"
- else
{{ order_cycle.orders_close_at }}

View File

@@ -15,19 +15,46 @@
= t :edit_order_cycle
- ng_controller = @order_cycle.simple? ? 'AdminSimpleEditOrderCycleCtrl' : 'AdminEditOrderCycleCtrl'
- has_scheduled_order = @order_cycle.schedules.exists?
= admin_inject_order_cycle_instance(@order_cycle)
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.orderCycles', 'ng-controller' => ng_controller, name: 'order_cycle_form'} do |f|
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.orderCycles', 'ng-controller' => ng_controller, name: 'order_cycle_form', data: { controller: 'modal modal-link order-cycle', "modal-link-target-value": "linked-schedule-warning-modal", 'order-cycle-has-schedule-value': has_scheduled_order, 'order-cycle-init-vals-value': { 'order_cycle[orders_open_at]': @order_cycle.orders_open_at&.strftime('%Y-%m-%d %H:%M'), 'order_cycle[orders_close_at]': @order_cycle.orders_close_at&.strftime('%Y-%m-%d %H:%M') } } } do |f|
%save-bar{ dirty: "order_cycle_form.$dirty", persist: "true" }
%input.red{ type: "button", value: t('.save'), "ng-click": "submit($event, null)", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid" }
- if @order_cycle.simple?
%input.red{ type: "button", value: t('.save_and_back_to_list'), "ng-click": "submit($event, '#{main_app.admin_order_cycles_path}')", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid" }
- else
%input.red{ type: "button", value: t('.save_and_next'), "ng-click": "submit($event, '#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid" }
%input{ type: "button", value: t('.next'), "ng-click": "cancel('#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", "ng-disabled": "order_cycle_form.$dirty" }
%input{ type: "button", "ng-value": "order_cycle_form.$dirty ? '#{t('.cancel')}' : '#{t('.back_to_list')}'", "ng-click": "cancel('#{main_app.admin_order_cycles_path}')" }
%div#form-actions
%input.red{ type: "button", value: t('.save'), "ng-click": "submit($event, null)", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid" }
- if @order_cycle.simple?
%input.red{ type: "button", value: t('.save_and_back_to_list'), "ng-click": "submit($event, '#{main_app.admin_order_cycles_path}')", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid" }
- else
%input.red{ type: "button", value: t('.save_and_next'), "ng-click": "submit($event, '#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid" }
%input{ type: "button", value: t('.next'), "ng-click": "cancel('#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", "ng-disabled": "order_cycle_form.$dirty" }
%input{ type: "button", "ng-value": "order_cycle_form.$dirty ? '#{t('.cancel')}' : '#{t('.back_to_list')}'", "ng-click": "cancel('#{main_app.admin_order_cycles_path}')" }
%div#modal-actions{style: "display: none;"}
%input.red{ type: "button", value: t('.save'), "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid", data: { 'action': 'click->modal-link#open click->order-cycle#updateModalConfirmButton', 'target': 'save'} }
- if @order_cycle.simple?
%input.red{ type: "button", value: t('.save_and_back_to_list'), "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid", data: { 'action': 'click->modal-link#open click->order-cycle#updateModalConfirmButton', 'target': 'saveAndBack'} }
- else
%input.red{ type: "button", value: t('.save_and_next'), "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid", data: { 'action': 'click->modal-link#open click->order-cycle#updateModalConfirmButton', 'target': 'saveAndNext'} }
%input{ type: "button", value: t('.next'), "ng-click": "cancel('#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", "ng-disabled": "order_cycle_form.$dirty" }
%input{ type: "button", "ng-value": "order_cycle_form.$dirty ? '#{t('.cancel')}' : '#{t('.back_to_list')}'", "ng-click": "cancel('#{main_app.admin_order_cycles_path}')" }
- if @order_cycle.simple?
= render 'simple_form', f: f
- else
= render 'form', f: f
- if has_scheduled_order
= render ModalComponent.new(id: "linked-schedule-warning-modal", close_button: false) do
.content
.modal-body
%h6
= t('admin.order_cycles.edit.linked_schedule_warning_modal.title')
%div{ style: 'font-size: 1rem;' }
= t('admin.order_cycles.edit.linked_schedule_warning_modal.content')
%p.modal-actions.justify-end
%button.button.secondary#modal-confirm{ type: "button", 'data-action': 'click->modal#close', style: 'display: none;', data: { 'order-cycle-target': 'modalConfirm', request: 'save' }, "ng-click": "submit($event, null)" }
= t('admin.order_cycles.edit.linked_schedule_warning_modal.proceed')
%button.button.secondary#modal-confirm{ type: "button", 'data-action': 'click->modal#close', style: 'display: none;', data: { 'order-cycle-target': 'modalConfirm', request: 'saveAndNext' }, "ng-click": "submit($event, '#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')" }
= t('admin.order_cycles.edit.linked_schedule_warning_modal.proceed')
%button.button.secondary#modal-confirm{ type: "button", 'data-action': 'click->modal#close', style: 'display: none;', data: { 'order-cycle-target': 'modalConfirm', request: 'saveAndBack' }, "ng-click": "submit($event, '#{main_app.admin_order_cycles_path}')" }
= t('admin.order_cycles.edit.linked_schedule_warning_modal.proceed')
%button.button.primary{ type: "button", 'data-action': 'click->modal#close' }
= t('admin.order_cycles.edit.linked_schedule_warning_modal.cancel')

View File

@@ -0,0 +1,52 @@
import { Controller } from "stimulus";
export default class extends Controller {
static targets = ['input', 'modalConfirm'];
static values = { initVals: { type: Object, default: {} }, hasSchedule: { type: Boolean, default: false } };
connect() {
if(!this.hasScheduleValue) return;
// Attach update callback method
window.adminOrderCycleUpdateCallback = this.updateCallback.bind(this);
}
toggleSaveBtns() {
if(!this.hasScheduleValue) return;
// Check that datetime input value has a change
const dirty = this.inputTargets.some(ele =>
new Date(this.initValsValue[`${ele.name}`]).getTime() !== new Date(ele.value).getTime());
// Toggle save bar action button
if (dirty) {
this.element.querySelector('#form-actions').style.display = 'none';
this.element.querySelector('#modal-actions').style.display = 'unset';
} else {
this.element.querySelector('#form-actions').style.display = 'unset';
this.element.querySelector('#modal-actions').style.display = 'none';
}
}
updateModalConfirmButton(e) {
if(!this.hasScheduleValue) return;
// Display modal confirm button coresponding to save bar button clicked
this.modalConfirmTargets.forEach(ele => {
if (e.target.getAttribute('data-target') === ele.getAttribute('data-request')) {
ele.style.display = 'unset';
} else {
ele.style.display = 'none';
}
});
}
updateCallback(data) {
// Reset order values and update save bar buttons
this.initValsValue = { 'order_cycle[orders_open_at]': data.orders_open_at, 'order_cycle[orders_close_at]': data.orders_close_at };
this.toggleSaveBtns();
}
disconnect() {
// remove attached update callback method
delete window.adminOrderCycleUpdateCallback;
}
}

View File

@@ -62,3 +62,25 @@ form.order_cycle {
}
}
}
#linked-schedule-warning-modal {
.reveal-modal {
width: 28rem;
.content {
display: flex;
flex-direction: column;
gap: 2rem;
.modal-body {
display: flex;
flex-direction: column;
gap: 1rem;
}
.modal-actions {
gap: 1rem;
}
}
}
}

View File

@@ -1506,6 +1506,11 @@ en:
choose_products_from: "Choose Products From:"
re_notify_producers: Re notify producers
notify_producers_tip: This will send an email to each producer with the list of their orders.
linked_schedule_warning_modal:
title: 'Orders are linked to this order cycle.'
content: 'If you wish to create a new order cycle, it is recommended to duplicate the order cycle first and then change the dates.'
proceed: 'Proceed anyway'
cancel: 'Cancel'
incoming:
incoming: "Incoming"
supplier: "Supplier"

View File

@@ -0,0 +1,91 @@
# frozen_string_literal: true
require 'system_helper'
RSpec.describe '
As an administrator
I want to edit a specific order cycle
' do
include AdminHelper
include AuthenticationHelper
include WebHelper
let(:oc0) {
create(:simple_order_cycle, name: 'oc0',
orders_open_at: nil, orders_close_at: nil)
}
let(:oc1) { create(:order_cycle, name: 'oc1') }
context 'when cycle has attached schedule(s)' do
it "properly toggles order cycle save bar buttons to show warning modal" do
create(:schedule, name: 'Schedule1', order_cycles: [oc0])
# When I go to the admin order cycle edit page
login_as_admin
visit edit_admin_order_cycle_path(oc0)
expect(page).to have_selector("#linked-schedule-warning-modal")
expect(page).not_to have_selector("#modal-actions")
expect(page).to have_selector("#form-actions")
# change non-date range field
fill_in 'order_cycle_name', with: "OC0 name updated"
expect(page).to have_content('You have unsaved changes')
click_button('Save')
expect(page).not_to have_selector('#linked-schedule-warning-modal .reveal-modal.in')
expect(page).to have_content('Your order cycle has been updated.')
# change date range field value
time = DateTime.current
find('#order_cycle_orders_close_at').click
select_datetime_from_datepicker Time.zone.at(time)
# Enable savebar save buttons to open warning modal
expect(page.find('#order_cycle_orders_close_at').value).to eq time.strftime('%Y-%m-%d %H:%M')
expect(page).not_to have_selector("#form-actions")
expect(page).to have_selector("#modal-actions")
expect(page).to have_content('You have unsaved changes')
expect(page).not_to have_selector('#linked-schedule-warning-modal .reveal-modal.in')
# click save to open warning modal
click_button('Save')
expect(page).to have_selector('#linked-schedule-warning-modal .reveal-modal.in')
# confirm to close modal and update order cycle changed fields
click_button('Proceed anyway')
expect(page).not_to have_selector('#linked-schedule-warning-modal .reveal-modal.in')
expect(page.find('#order_cycle_orders_close_at').value).to eq time.strftime('%Y-%m-%d %H:%M')
end
end
context 'when cycle does not have attached schedule' do
it "does not render warning modal" do
# When I go to the admin order cycle edit page
login_as_admin
visit edit_admin_order_cycle_path(oc1)
expect(page).not_to have_selector("#linked-schedule-warning-modal")
expect(page).not_to have_selector("#modal-actions")
expect(page).to have_selector("#form-actions")
# change non-date range field value
fill_in 'order_cycle_name', with: "OC1 name updated"
expect(page).to have_content('You have unsaved changes')
# click save
click_button('Save')
expect(page).not_to have_selector('#linked-schedule-warning-modal .reveal-modal.in')
expect(page).to have_content('Your order cycle has been updated.')
# change date range field value
time = DateTime.current
find('#order_cycle_orders_close_at').click
select_datetime_from_datepicker Time.zone.at(time)
expect(page).to have_content('You have unsaved changes')
click_button('Save')
expect(page).not_to have_selector("#modal-actions")
expect(page).to have_content('Your order cycle has been updated.')
end
end
end