mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-03 22:06:07 +00:00
Add warning modal to order cycle with attached schedule general setting form [OFN-11613]
This commit is contained in:
@@ -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?
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
|
||||
@@ -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')
|
||||
52
app/webpacker/controllers/order_cycle_controller.js
Normal file
52
app/webpacker/controllers/order_cycle_controller.js
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
91
spec/system/admin/order_cycles/edit_spec.rb
Normal file
91
spec/system/admin/order_cycles/edit_spec.rb
Normal 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
|
||||
Reference in New Issue
Block a user