Skip to content

Commit a2ea340

Browse files
Merge pull request #5750 from Sinkleberg/5603-align-distribution-line-items
Fix distribution line-item labels on narrow screens (#5603)
2 parents 3eb4e2f + 251d060 commit a2ea340

5 files changed

Lines changed: 159 additions & 50 deletions

File tree

‎app/assets/stylesheets/application.scss‎

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -200,33 +200,6 @@ div.low_priority_warning {
200200
text-align: center;
201201
}
202202

203-
.distribution-title {
204-
display: flex;
205-
}
206-
207-
legend.with-request {
208-
float: none;
209-
width: 80%;
210-
display: inline-block;
211-
}
212-
213-
div.distribution-request-unit {
214-
display: inline-block;
215-
flex: 1;
216-
text-align: right;
217-
margin-right: 20px;
218-
font-size: 1.5em;
219-
}
220-
221-
.li-requested {
222-
font-size: 1.5em;
223-
width: 100px;
224-
min-width: 100px;
225-
text-align: right;
226-
margin-right: 20px;
227-
white-space: nowrap;
228-
}
229-
230203
.git-version {
231204
color: gray;
232205
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
.distribution-line-items {
2+
.distribution-line-item-row {
3+
margin-top: .5rem;
4+
}
5+
6+
.distribution-line-item-inputs {
7+
display: grid;
8+
grid-template-columns: minmax(0, 1fr) 11rem;
9+
gap: 1rem;
10+
11+
&.with-request {
12+
grid-template-columns: minmax(0, 1fr) 11rem 7rem;
13+
}
14+
}
15+
16+
.li-name,
17+
.li-quantity,
18+
.li-requested {
19+
min-width: 0;
20+
}
21+
22+
.distribution-line-item-inputs label,
23+
.form-label {
24+
display: block;
25+
font-weight: bold;
26+
margin-bottom: .5rem;
27+
white-space: nowrap;
28+
}
29+
30+
.distribution-requested-value {
31+
display: flex;
32+
align-items: center;
33+
min-height: calc(1.5em + .75rem + 2px);
34+
}
35+
36+
@media (max-width: 575.98px) {
37+
.distribution-line-item-inputs,
38+
.distribution-line-item-inputs.with-request {
39+
grid-template-columns: minmax(0, 1fr);
40+
gap: 0;
41+
}
42+
43+
.li-requested {
44+
margin-bottom: 1rem;
45+
}
46+
}
47+
}

‎app/views/distributions/_form.html.erb‎

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,15 @@
4343

4444
<%= f.input :comment, label: "Comment" %>
4545

46-
<fieldset style="margin-bottom: 2rem">
47-
<div class="distribution-title">
48-
<legend class="<%= 'with-request' if distribution.request %>">Items in this distribution</legend>
49-
<% if distribution.request %>
50-
<div class="distribution-request-unit">Quantity - Total Units</div>
51-
<div class="distribution-request-unit">Requested</div>
52-
<% end %>
53-
</div>
46+
<fieldset class="distribution-line-items" style="margin-bottom: 2rem">
47+
<legend>Items in this distribution</legend>
5448
<div id="distribution_line_items" data-capture-barcode="true" class="line-item-fields">
55-
<%= render 'line_items/line_item_fields', form: f, changes_disallowed: @changes_disallowed %>
49+
<%= render 'line_items/line_item_fields', form: f, changes_disallowed: @changes_disallowed, distribution: true %>
5650
</div>
5751
<% unless @changes_disallowed %>
5852
<div class="row links justify-content-end">
5953
<%= add_element_button "Add Another Item", container_selector: "#distribution_line_items" , id: "__add_line_item" do %>
60-
<%= render 'line_items/line_item_fields', form: f, object: LineItem.new %>
54+
<%= render 'line_items/line_item_fields', form: f, object: LineItem.new, distribution: true %>
6155
<% end %>
6256
</div>
6357
<% end %>

‎app/views/line_items/_line_item_fields.html.erb‎

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<% if local_assigns[:changes_disallowed] %>
22
<div class="alert alert-warning">This <%= form.object.class.name.downcase %> is too old to edit inventory. You can only change non-inventory fields.</div>
33
<% end %>
4+
<% distribution = local_assigns[:distribution] %>
45
<%= form.simple_fields_for :line_items, defined?(object) ? object : nil do |field| %>
56
<% requested = field.object.requested_item %>
67
<section class="nested-fields line_item_section">
7-
<div class="row mt-2 d-flex flex-row align-items-center justify-content-between">
8-
<div class='d-flex flex-column justify-content-center'>
8+
<div class="<%= distribution ? 'distribution-line-item-row' : 'row mt-2 d-flex flex-row align-items-center justify-content-between' %>">
9+
<div class="<%= distribution ? 'distribution-line-item-details' : 'd-flex flex-column justify-content-center' %>">
910
<% if requested.blank? %>
1011
<% unless local_assigns[:changes_disallowed] %>
1112
<div class='d-flex flex-row align-items-center'>
@@ -16,35 +17,40 @@
1617
<label class='my-1 mx-auto font-weight-normal'>OR</label>
1718
<% end %>
1819
<% end %>
19-
<div class='d-flex flex-row'>
20+
<div class="<%= distribution ? class_names('distribution-line-item-inputs', 'with-request': form.object.request) : 'd-flex flex-row' %>">
2021
<span class="li-name w-100">
2122
<%= field.input :item_id,
2223
disabled: requested.present? || local_assigns[:changes_disallowed],
2324
collection: @item_labels_with_quantities || @items, prompt: "Choose an item",
2425
include_blank: "",
25-
label: false,
26+
label: distribution ? "Item" : false,
2627
input_html: { class: "my-0 line_item_name", "data-controller": "select2", "data-select2-config-value": '{"width": "100%"}' } %>
2728
<% if requested.present? %>
2829
<%= field.input :item_id, as: :hidden %>
2930
<% end %>
3031
</span>
31-
<div class="li-quantity mx-2">
32+
<div class="<%= class_names('li-quantity', 'mx-2': !distribution) %>">
3233
<%= field.input :quantity,
3334
as: :string,
3435
disabled: local_assigns[:changes_disallowed],
3536
placeholder: "Quantity",
36-
label: false,
37+
label: distribution ? "Quantity - Total Units" : false,
3738
input_html: { class: "quantity my-0", data: { quantity: "" } } %>
3839
</div>
3940
<% if form.object.respond_to?(:request) && form.object.request %>
40-
<div class="li-requested mx-2">
41-
<% if requested&.request_unit.present? %>
42-
<%= pluralize(requested.quantity, requested.request_unit) %>
43-
<% elsif requested %>
44-
<%= requested.quantity %>
45-
<% else %>
46-
N/A
41+
<div class="<%= class_names('li-requested', 'mx-2': !distribution) %>">
42+
<% if distribution %>
43+
<div class="form-label">Requested</div>
4744
<% end %>
45+
<div class="<%= 'distribution-requested-value' if distribution %>">
46+
<% if requested&.request_unit.present? %>
47+
<%= pluralize(requested.quantity, requested.request_unit) %>
48+
<% elsif requested %>
49+
<%= requested.quantity %>
50+
<% else %>
51+
N/A
52+
<% end %>
53+
</div>
4854
</div>
4955
<% end %>
5056
</div>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
RSpec.describe "Distribution line item layout", type: :system do
2+
let(:organization) { create(:organization) }
3+
let(:user) { create(:user, organization:) }
4+
let(:partner) { create(:partner, organization:, name: "Layout Partner") }
5+
let(:storage_location) { create(:storage_location, organization:, name: "Layout Storage") }
6+
let(:item) { create(:item, organization:, name: "Layout Diapers") }
7+
8+
before do
9+
sign_in(user)
10+
TestInventory.create_inventory(organization, storage_location.id => {item.id => 100})
11+
end
12+
13+
shared_examples "responsive line items" do
14+
it "keeps each label with its field at narrow and desktop widths" do
15+
select "Layout Storage", from: "From storage location"
16+
expect(page).to have_css("#__add_line_item:not(.disabled)")
17+
[375, 600, 1200].each do |width|
18+
current_window.resize_to(width, 900)
19+
expect(page).to have_css(".li-name .select2-container")
20+
21+
layout = page.evaluate_script(<<~JS)
22+
(() => {
23+
const row = document.querySelector('.distribution-line-item-inputs');
24+
const bounds = element => element.getBoundingClientRect();
25+
const fields = [...row.children];
26+
return {
27+
labelsFit: fields.every(field => {
28+
const label = field.querySelector('label, .form-label');
29+
const text = document.createRange();
30+
text.selectNodeContents(label);
31+
return bounds(label).height < parseFloat(getComputedStyle(label).fontSize) * 2 &&
32+
label.scrollWidth <= field.clientWidth + 1 &&
33+
bounds(text).left >= bounds(field).left - 1 &&
34+
bounds(text).right <= bounds(field).right + 1;
35+
}),
36+
gridFitsViewport: bounds(row).left >= 0 &&
37+
bounds(row).right <= document.documentElement.clientWidth + 1,
38+
fieldsFit: fields.every(field => bounds(field).left >= bounds(row).left &&
39+
bounds(field).right <= bounds(row).right + 1),
40+
labelsAlign: fields.every(field => {
41+
const label = field.querySelector('label, .form-label');
42+
const value = field.querySelector('.select2-container, input, .distribution-requested-value');
43+
return Math.abs(bounds(label).left - bounds(value).left) <= 1 &&
44+
bounds(label).bottom <= bounds(value).top + 1;
45+
}),
46+
dropdownFits: bounds(row.querySelector('.select2-container')).width <=
47+
bounds(row.querySelector('.li-name')).width + 1
48+
};
49+
})()
50+
JS
51+
52+
expect(layout).to eq("labelsFit" => true, "gridFitsViewport" => true, "fieldsFit" => true, "labelsAlign" => true, "dropdownFits" => true)
53+
end
54+
55+
current_window.resize_to(375, 900)
56+
click_on "Add Another Item"
57+
expect(page).to have_css(".distribution-line-item-inputs", count: 2)
58+
within all(".distribution-line-item-inputs").last do
59+
expect(page).to have_field("Item")
60+
fill_in "Quantity - Total Units", with: "5"
61+
expect(page).to have_field("Quantity - Total Units", with: "5")
62+
find(".select2-selection").click
63+
end
64+
find(".select2-results__option", text: "Layout Diapers").click
65+
within all(".line_item_section").last do
66+
expect(page).to have_content("Layout Diapers")
67+
click_on "Remove"
68+
end
69+
expect(page).to have_css(".distribution-line-item-inputs", count: 1)
70+
end
71+
end
72+
73+
context "on a regular distribution" do
74+
before { visit new_distribution_path }
75+
76+
include_examples "responsive line items"
77+
end
78+
79+
context "when fulfilling a request" do
80+
before do
81+
request = create(:request, organization:, partner:, request_items: [{"item_id" => item.id, "quantity" => 10}])
82+
create(:item_request, request:, item:, quantity: 10)
83+
visit request_path(request)
84+
click_on "Fulfill request"
85+
end
86+
87+
include_examples "responsive line items"
88+
end
89+
end

0 commit comments

Comments
 (0)