Skip to content

Commit b5c1248

Browse files
refactor: reuse shared confirmation controller for kit creation modal
1 parent 84a3ad2 commit b5c1248

9 files changed

Lines changed: 142 additions & 115 deletions

File tree

app/controllers/kits_controller.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ def new
1919
@kit.line_items.build
2020
end
2121

22+
def validate
23+
@kit = current_organization.kits.new(kit_params)
24+
@kit.line_items.combine!
25+
@kit.valid?
26+
@kit.errors.add(:base, "At least one item is required") if @kit.line_items.empty?
27+
28+
if @kit.errors.none?
29+
body = render_to_string(template: "kits/validate", formats: [:html], layout: false)
30+
render json: {valid: true, body: body}
31+
else
32+
render json: {valid: false}
33+
end
34+
end
35+
2236
def create
2337
kit_creation = KitCreateService.new(organization_id: current_organization.id, kit_params: kit_params)
2438
kit_creation.call

app/javascript/controllers/confirmation_controller.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ import { Controller } from "@hotwired/stimulus"
1515
1616
* If the user clicks the "Yes..." button from the modal, it submits the form.
1717
* If the user clicks the "No..." button from the modal, it closes and user remains on the same url.
18+
*
19+
* The button that opened the modal is remembered and passed back into requestSubmit, so that any other
20+
* Stimulus controller composed onto the same form (e.g. duplicate-items) still sees it as `event.submitter`
21+
* when the form is eventually (re)submitted.
1822
*/
1923
export default class extends Controller {
2024
static targets = [
@@ -29,6 +33,8 @@ export default class extends Controller {
2933
openModal(event) {
3034
event.preventDefault();
3135

36+
this.submitter = event.currentTarget;
37+
3238
const formData = new FormData(this.formTarget);
3339
const formObject = this.buildNestedObject(formData);
3440

@@ -49,15 +55,15 @@ export default class extends Controller {
4955
this.modalTarget.innerHTML = data.body;
5056
$(this.modalTarget).modal("show");
5157
} else {
52-
this.formTarget.requestSubmit();
58+
this.formTarget.requestSubmit(this.submitter);
5359
}
5460
})
5561
.catch((error) => {
5662
// Something went wrong in communication to server validation endpoint
5763
// In this case, just submit the form as if the user had clicked Save.
5864
// NICE TO HAVE: Send to bugsnag but need to install/configure https://www.npmjs.com/package/@bugsnag/js
5965
console.log(`=== ConfirmationController ERROR ${error}`);
60-
this.formTarget.requestSubmit();
66+
this.formTarget.requestSubmit(this.submitter);
6167
});
6268
}
6369

@@ -106,6 +112,6 @@ export default class extends Controller {
106112
$(this.modalTarget).find('#modalYes').prop('disabled', true);
107113
$(this.modalTarget).find('#modalNo').prop('disabled', true);
108114
$(this.modalTarget).modal("hide");
109-
this.formTarget.requestSubmit();
115+
this.formTarget.requestSubmit(this.submitter);
110116
}
111117
}

app/javascript/controllers/kit_confirmation_controller.js

Lines changed: 0 additions & 98 deletions
This file was deleted.

app/views/kits/_form.html.erb

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<%= simple_form_for @kit, remote: request.xhr?, data: { controller: "form-input duplicate-items kit-confirmation" }, html: { class: 'form-horizontal' } do |f| %>
1+
<%= simple_form_for @kit, remote: request.xhr?, data: { controller: "form-input duplicate-items", confirmation_target: "form" }, html: { class: 'form-horizontal' } do |f| %>
22
<section class="content">
33
<div class="container-fluid">
44
<div class="row">
@@ -36,8 +36,7 @@
3636
<p><b>NB: You will not be able to change the composition of the kit once saved. Partner visibility and name can be changed via the kit's item.</b></p>
3737
<%= submit_button({}, {
3838
"duplicate-items-target": "itemSubmitButton",
39-
"kit-confirmation-target": "submitButton",
40-
action: "click->kit-confirmation#openModal"
39+
action: "click->confirmation#openModal"
4140
}) %>
4241
</div>
4342
</div>
@@ -46,3 +45,14 @@
4645
</div>
4746
</section>
4847
<% end %>
48+
49+
<%# Confirmation modal: See confirmation_controller.js for how this gets displayed %>
50+
<%# and app/controllers/kits_controller.rb#validate for how it gets populated. %>
51+
<div id="kitConfirmationModal"
52+
class="modal confirm"
53+
aria-labelledby="kitConfirmationModal"
54+
aria-hidden="true"
55+
tabindex="-1"
56+
data-bs-backdrop="static"
57+
data-confirmation-target="modal">
58+
</div>

app/views/kits/new.html.erb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@
2020
</div>
2121
</section>
2222

23-
<%= render 'form' %>
23+
<div data-controller="confirmation" data-confirmation-pre-check-path-value="<%= validate_kits_path(format: :json) %>">
24+
<%= render 'form' %>
25+
</div>
2426
<%= render partial: "barcode_items/barcode_modal" %>

app/views/kits/validate.html.erb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<div class="modal-dialog modal-lg">
2+
<div class="modal-content">
3+
<div class="modal-header">
4+
<h5 class="modal-title">Kit Creation Confirmation</h5>
5+
<button id="modalClose" type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
6+
</div>
7+
<div class="modal-body">
8+
<p class="lead">You are about to create a kit named
9+
<span class="fw-bolder fst-italic" data-testid="kit-confirmation-name"><%= @kit.name %></span>
10+
with value
11+
<span class="fw-bolder fst-italic" data-testid="kit-confirmation-value">$<%= format("%.2f", @kit.value_in_dollars) %></span>
12+
</p>
13+
<table class="table">
14+
<thead>
15+
<tr>
16+
<th>Item Name</th>
17+
<th>Quantity</th>
18+
</tr>
19+
</thead>
20+
<tbody>
21+
<% @kit.line_items.each do |line_item| %>
22+
<tr>
23+
<td><%= line_item.name %></td>
24+
<td><%= line_item.quantity %></td>
25+
</tr>
26+
<% end %>
27+
</tbody>
28+
</table>
29+
<p>Please confirm that this is the correct composition of the kit. Note: You will
30+
<span class="text-danger fw-bold">not</span> be able to edit the items contained in the kit.</p>
31+
</div>
32+
<div class="modal-footer">
33+
<button id="modalNo" type="button" class="btn btn-secondary" data-bs-dismiss="modal" aria-label="No I need to make changes">No, I need to make changes</button>
34+
<button id="modalYes" type="button" class="btn btn-success" data-action="confirmation#submitForm">Yes, it's correct</button>
35+
</div>
36+
</div>
37+
</div>

config/routes.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ def set_up_flipper
187187
end
188188

189189
resources :kits do
190+
collection do
191+
post :validate
192+
end
190193
member do
191194
get :allocations
192195
post :allocate

spec/requests/kit_requests_spec.rb

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,64 @@
1919
end
2020
end
2121

22+
describe "POST #validate" do
23+
let(:item) { create(:item, organization: organization) }
24+
25+
it "returns valid and the confirmation modal body for a valid kit" do
26+
post validate_kits_url(format: :json), params: {
27+
kit: {
28+
name: "A new kit",
29+
value_in_dollars: "10.10",
30+
line_items_attributes: {"0": {item_id: item.id, quantity: 5}}
31+
}
32+
}
33+
34+
expect(response).to be_successful
35+
json = JSON.parse(response.body)
36+
expect(json["valid"]).to eq(true)
37+
expect(json["body"]).to include("A new kit")
38+
expect(json["body"]).to include("$10.10")
39+
expect(json["body"]).to include(item.name)
40+
end
41+
42+
it "returns invalid when the name is blank" do
43+
post validate_kits_url(format: :json), params: {
44+
kit: {
45+
name: "",
46+
value_in_dollars: "10.10",
47+
line_items_attributes: {"0": {item_id: item.id, quantity: 5}}
48+
}
49+
}
50+
51+
expect(response).to be_successful
52+
json = JSON.parse(response.body)
53+
expect(json["valid"]).to eq(false)
54+
expect(json["body"]).to be_nil
55+
end
56+
57+
it "returns invalid when there are no line items" do
58+
post validate_kits_url(format: :json), params: {
59+
kit: {name: "A new kit", value_in_dollars: "10.10"}
60+
}
61+
62+
expect(response).to be_successful
63+
json = JSON.parse(response.body)
64+
expect(json["valid"]).to eq(false)
65+
end
66+
67+
it "does not persist the kit" do
68+
expect {
69+
post validate_kits_url(format: :json), params: {
70+
kit: {
71+
name: "A new kit",
72+
value_in_dollars: "10.10",
73+
line_items_attributes: {"0": {item_id: item.id, quantity: 5}}
74+
}
75+
}
76+
}.not_to change(Kit, :count)
77+
end
78+
end
79+
2280
describe "GET #index" do
2381
before do
2482
# this shouldn't be shown

spec/system/kit_system_spec.rb

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@
7272

7373
item = Item.last
7474
quantity_per_kit = 5
75-
select item.name, from: "kit_item_line_items_attributes_0_item_id"
76-
find(:css, '#kit_item_line_items_attributes_0_quantity').set(quantity_per_kit)
75+
select item.name, from: "kit_line_items_attributes_0_item_id"
76+
find(:css, '#kit_line_items_attributes_0_quantity').set(quantity_per_kit)
7777

7878
click_button "Save"
7979

@@ -86,7 +86,7 @@
8686
expect(page).to have_current_path(new_kit_path)
8787
expect(page).to have_no_content("Kit created successfully")
8888
expect(page).to have_field("Name", with: kit_traits[:name])
89-
expect(page).to have_field("kit_item_line_items_attributes_0_quantity", with: quantity_per_kit.to_s)
89+
expect(page).to have_field("kit_line_items_attributes_0_quantity", with: quantity_per_kit.to_s)
9090
end
9191

9292
it "can add items correctly" do
@@ -247,7 +247,6 @@
247247
describe "when missing required fields" do
248248
it "displays error indicating missing field and preserves filled out fields" do
249249
visit new_kit_path
250-
kit_traits = attributes_for(:kit)
251250

252251
find(:css, '#kit_value_in_dollars').set('10.10')
253252

@@ -258,13 +257,9 @@
258257

259258
click_button "Save"
260259

261-
expect(page).to have_css("#kitConfirmationModal", visible: true)
262-
within "#kitConfirmationModal" do
263-
click_button "Yes, it's correct"
264-
end
265-
260+
expect(page).to have_no_css("#kitConfirmationModal", visible: true)
266261
expect(page.find(".alert")).to have_content "Name can't be blank"
267-
expect(page).to have_content(kit_traits[:quantity])
262+
expect(page).to have_field("kit_line_items_attributes_0_quantity", with: quantity_per_kit.to_s)
268263
expect(page).to have_content(item.name)
269264
end
270265
end

0 commit comments

Comments
 (0)