Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[283] Eval Form: Cancelation modal #315

Merged
merged 9 commits into from
Dec 11, 2024
4 changes: 3 additions & 1 deletion app/javascript/controllers/evaluation_form_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ export default class extends Controller {

// Opens all accordions, remove existing points/weights, update max points/weights values
updateMaxPoints(e) {
const form = e.target.closest('form[data-controller="evaluation-form"]');
const form = e.target.closest(
'form[data-controller="evaluation-form modal"]'
);
const pointsWeights = form.querySelectorAll(".points-or-weight");
const weightedScale = e.target.value === "true";

Expand Down
10 changes: 8 additions & 2 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import DeleteEvaluatorModalController from "./delete_evaluator_modal_controller"
application.register("delete-evaluator-modal", DeleteEvaluatorModalController);

import UnassignEvaluatorSubmissionModalController from "./unassign_evaluator_submission_modal_controller";
application.register("unassign-evaluator-submission-modal", UnassignEvaluatorSubmissionModalController);
application.register(
"unassign-evaluator-submission-modal",
UnassignEvaluatorSubmissionModalController
);

import EvaluationCriteriaController from "./evaluation_criteria_controller";
application.register("evaluation-criteria", EvaluationCriteriaController);
Expand All @@ -17,4 +20,7 @@ import EvaluationFormController from "./evaluation_form_controller";
application.register("evaluation-form", EvaluationFormController);

import HotdogController from "./hotdog_controller";
application.register("hotdog", HotdogController);
application.register("hotdog", HotdogController);

import ModalController from "./modal_controller";
application.register("modal", ModalController);
87 changes: 87 additions & 0 deletions app/javascript/controllers/modal_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
static targets = ["modal"];
static values = {
modalId: String,
};

open(event) {
const modalId = event.currentTarget.dataset.modalTargetId;
const modal = this.modalTargets.find((modal) => modal.id === modalId);

this.openEvent = event;

event.preventDefault();

if (modal) {
modal.showModal();
} else {
console.warn(`Modal with ID '${modalId}' not found.`);
}
}

confirm(event) {
const modal = this._getModal(event);

if (modal) {
const confirmRedirect = modal.dataset.modalConfirmRedirect;
const confirmAction = modal.dataset.modalConfirmAction;

if (confirmRedirect) {
window.location.href = confirmRedirect;
} else if (confirmAction) {
this.invokeAction(confirmAction);
modal.close();
} else {
modal.close();
return true;
}
}
}

cancel(event) {
const modal = this._getModal(event);

if (modal) {
const cancelRedirect = modal.dataset.modalCancelRedirect;
const cancelAction = modal.dataset.modalCancelAction;

if (cancelRedirect) {
window.location.href = cancelRedirect;
} else if (cancelAction) {
this.invokeAction(cancelAction);
modal.close();
} else {
modal.close();
return false;
}
}
}

_getModal(event) {
return event.currentTarget.closest("dialog");
}

invokeAction(actionName) {
const [controllerName, action] = actionName.split("#");
const controllerElement = document.querySelector(
`[data-controller~="${controllerName}"]`
);

if (!controllerElement) {
console.warn(`Controller element for ${controllerName} not found.`);
}

const controller = this.application.getControllerForElementAndIdentifier(
controllerElement,
controllerName
);

if (controller && typeof controller[action] === "function") {
controller[action](this.openEvent);
} else {
console.warn(`Action ${actionName} not found on ${controllerName}`);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@

<% if !form_disabled %>
<div class="margin-top-2">
<%= button_tag type: "button", id: criteria_field_id(f, "delete_criteria", is_template), class: "delete-criteria-button usa-button usa-button--unstyled", title: "Delete criteria", data: {action: "click->evaluation-criteria#removeCriteria"} do %>
<%= button_tag type: "button", id: criteria_field_id(f, "delete_criteria", is_template), class: "delete-criteria-button usa-button usa-button--unstyled", title: "Delete criteria", data: {"action": "modal#open", "modal-target-id": "remove-criteria"} do %>
Remove criteria
<% end %>
</div>
Expand Down
26 changes: 22 additions & 4 deletions app/views/evaluation_forms/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%= form_with(model: evaluation_form, data: { controller: "evaluation-form" }) do |form| %>
<%= form_with(model: evaluation_form, data: { controller: "evaluation-form modal" }) do |form| %>
<% if evaluation_form.errors.any? %>
<div style="color: darkred">
<h2><%= pluralize(evaluation_form.errors.count, "error") %> prohibited this evaluation form from being saved:</h2>
Expand Down Expand Up @@ -200,7 +200,25 @@
Save
</button>
<div class="text-center width-full mobile-lg:width-auto margin-y-1 mobile-lg:margin-x-3">
<%= link_to "Cancel", evaluation_forms_path %>
</div>
<%= link_to "Cancel", "#", data: {"action": "modal#open", "modal-target-id": "cancel"} %>
</div>
</div>
<% end %>

<%= render "modals/confirmation",
id: "cancel",
heading: "Are you sure you want to cancel?",
description: "Your evaluation form will not be saved and any entered information will be lost.",
confirm_text: "Yes",
cancel_text: "Close",
confirm_redirect: evaluation_forms_path
%>

<%= render "modals/confirmation",
id: "remove-criteria",
heading: "Are you sure you want to remove this criteria?",
description: "",
confirm_text: "Yes",
cancel_text: "No",
confirm_action: "evaluation-criteria#removeCriteria"
%>
<% end %>
28 changes: 28 additions & 0 deletions app/views/modals/_confirmation.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<dialog
id="<%= id %>"
class="border-width-0 radius-lg"
aria-labelledby=<%= "#{id}-heading" %>
aria-describedby=<%= "#{id}-description" %>
data-modal-target="modal"
data-modal-confirm-redirect="<%= defined?(confirm_redirect) ? confirm_redirect : '' %>"
data-modal-cancel-redirect="<%= defined?(cancel_redirect) ? cancel_redirect : '' %>"
data-modal-confirm-action="<%= defined?(confirm_action) ? confirm_action : '' %>"
data-modal-cancel-action="<%= defined?(cancel_action) ? cancel_action : '' %>"
Comment on lines +7 to +10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

>
<div class="usa-modal__content">
<div class="usa-modal__main">
<h2 class="usa-modal__heading" id=<%= "#{id}-heading" %>>
<%= heading %>
</h2>
<div class="usa-prose">
<p id=<%= "#{id}-description" %>>
<%= description %>
</p>
</div>
<div class="usa-modal__footer">
<button id="modal-btn-confirm" class="usa-button" type="button" data-action="modal#confirm"><%= confirm_text %></button>
<button id="modal-btn-cancel" class="usa-button--unstyled" type="button" data-action="modal#cancel"><%= cancel_text %></button>
</div>
</div>
</div>
</dialog>
88 changes: 86 additions & 2 deletions spec/system/evaluation_form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,45 @@
expect(page).to(be_axe_clean)
end

it "shows a confirmation modal when clicking the cancel button" do
cpreisinger marked this conversation as resolved.
Show resolved Hide resolved
visit new_evaluation_form_path

click_link_or_button "Cancel"

assert_selector 'dialog#cancel', visible: true

expect(page).to(be_axe_clean)
end

it "redirects to evaluation form path when clicking yes in cancel modal" do
visit new_evaluation_form_path

click_link_or_button "Cancel"

assert_selector 'dialog#cancel', visible: true

within 'dialog#cancel' do
click_link_or_button 'Yes'
end

assert_current_path evaluation_forms_path
end

it "closes the cancel modal and does nothing if you click close" do
visit new_evaluation_form_path

click_link_or_button "Cancel"

assert_selector 'dialog#cancel', visible: true

within 'dialog#cancel' do
click_link_or_button 'Close'
end

assert_no_selector 'dialog#cancel', visible: true
assert_current_path new_evaluation_form_path
end

it 'allows creation of a valid form with all 3 criteria scoring types' do
visit new_evaluation_form_path

Expand Down Expand Up @@ -291,6 +330,45 @@
expect(page).to(be_axe_clean)
end

it "shows a confirmation modal when clicking the cancel button" do
visit edit_evaluation_form_path(evaluation_form)

click_link_or_button "Cancel"

assert_selector 'dialog#cancel', visible: true

expect(page).to(be_axe_clean)
end

it "redirects to evaluation form path when clicking yes in cancel modal" do
visit edit_evaluation_form_path(evaluation_form)

click_link_or_button "Cancel"

assert_selector 'dialog#cancel', visible: true

within 'dialog#cancel' do
click_link_or_button 'Yes'
end

assert_current_path evaluation_forms_path
end

it "closes the cancel modal and does nothing if you click close" do
visit edit_evaluation_form_path(evaluation_form)

click_link_or_button "Cancel"

assert_selector 'dialog#cancel', visible: true

within 'dialog#cancel' do
click_link_or_button 'Close'
end

assert_no_selector 'dialog#cancel', visible: true
assert_current_path edit_evaluation_form_path(evaluation_form)
end

it 'allows editing of an existing form values' do
visit edit_evaluation_form_path(evaluation_form)

Expand Down Expand Up @@ -377,7 +455,7 @@
visit edit_evaluation_form_path(closed_evaluation_form)

# Add expectation in spec to satisfy rubocop
expect(page).to have_css("form[data-controller='evaluation-form']")
expect(page).to have_css("form[data-controller='evaluation-form modal']")
check_all_non_hidden_inputs_disabled_except_end_date
end
end
Expand Down Expand Up @@ -519,6 +597,12 @@ def add_criterion

def remove_criterion(index)
click_link_or_button "evaluation_form_evaluation_criteria_attributes_#{index}_delete_criteria"

assert_selector 'dialog#remove-criteria', visible: true

within 'dialog#remove-criteria' do
click_link_or_button 'Yes'
end
end

def toggle_criteria_accordion(index)
Expand Down Expand Up @@ -791,7 +875,7 @@ def rebalance_criteria_weights

# Checks that all non hidden or end date fields are disabled
def check_all_non_hidden_inputs_disabled_except_end_date
within("form[data-controller='evaluation-form']") do
within("form[data-controller='evaluation-form modal']") do
all("input:not([type='hidden']), textarea, select").each do |field|
if field[:id] == "evaluation_form_closing_date"
expect(field).not_to be_disabled, "Expected #{field[:id]} to not be disabled"
Expand Down
Loading