Skip to content

Commit 49ce0a6

Browse files
authored
Merge branch 'main' into 4858-add-an-option-to-include-in-kind-values-in-export-of-donations-and-distributions-new
2 parents e3f8594 + d1c52ea commit 49ce0a6

80 files changed

Lines changed: 268 additions & 129 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,4 @@ package-lock.json
8888
out/
8989

9090
.vscode/
91+
.aider*

app/controllers/partners/requests_controller.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,11 @@ def fetch_items
8181
@requestable_items = PartnerFetchRequestableItemsService.new(partner_id: partner.id).call
8282
if Flipper.enabled?(:enable_packs)
8383
# hash of (item ID => hash of (request unit name => request unit plural name))
84-
@item_units = Item.where(id: @requestable_items.to_h.values).to_h do |i|
85-
[i.id, i.request_units.to_h { |u| [u.name, u.name.pluralize] }]
84+
item_ids = @requestable_items.to_h.values
85+
if item_ids.present?
86+
@item_units = Item.where(id: item_ids).to_h do |i|
87+
[i.id, i.request_units.to_h { |u| [u.name, u.name.pluralize] }]
88+
end
8689
end
8790
end
8891
end
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module Partners
2+
module ProfileHelper
3+
# Returns an array of filenames that are attached to the profile but not persisted.
4+
# This is to display to the user that the system remembers their file selections
5+
# even if there was a form validation error.
6+
# The method returns a JSON string (an array of filenames) to be used in a Stimulus controller.
7+
def attached_but_not_persisted_file_names(profile)
8+
filenames = profile.documents.attachments
9+
.select { |att| !att.persisted? }
10+
.map { |att| att.blob.filename.to_s }
11+
12+
filenames.to_json
13+
end
14+
15+
# Returns true if at least one document attachment is actually persisted
16+
def has_persisted_documents?(profile)
17+
profile.documents.attachments.any?(&:persisted?)
18+
end
19+
end
20+
end

app/javascript/controllers/file_input_controller.js

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import { Controller } from "@hotwired/stimulus";
55
*
66
* This controller:
77
* - Listens for file selection on an `<input type="file" multiple="multiple">`
8-
* - Displays selected file names in a custom list **when multiple files are selected
9-
* - Defaults to the browser’s built-in display for a single file selection
8+
* - Displays selected file names in a custom list when multiple files are selected
9+
* - If provided a `filenames` array, displays those file names as if user had just selected them.
10+
* This is useful for displaying previously selected files on page load with validation errors.
1011
*
1112
* Expected HTML structure should have a placeholder div for the selected file names:
1213
*
@@ -20,29 +21,60 @@ import { Controller } from "@hotwired/stimulus";
2021
export default class extends Controller {
2122
static targets = ["input", "list"];
2223

24+
static values = {
25+
filenames: Array
26+
}
27+
2328
connect() {
2429
this.inputTarget.addEventListener("change", () => this.updateFileList());
30+
31+
if (this.hasFilenamesValue && this.filenamesValue.length > 0) {
32+
this.updateFileListFromValue();
33+
}
34+
}
35+
36+
// Opens the hidden file input when "Choose Files" button is clicked
37+
triggerFileSelection() {
38+
this.inputTarget.click();
2539
}
2640

41+
// native file input selection
2742
updateFileList() {
2843
const files = this.inputTarget.files;
29-
this.listTarget.innerHTML = ""; // Clear previous list
3044

31-
// If no files or only one file is selected, let the native UI handle it
32-
if (files.length <= 1) {
45+
if (files.length === 0) {
3346
return;
3447
}
3548

49+
this.renderFileList(Array.from(files).map(file => file.name));
50+
}
51+
52+
updateFileListFromValue() {
53+
this.renderFileList(this.filenamesValue);
54+
}
55+
56+
renderFileList(fileNames) {
57+
// Clear previous list
58+
this.listTarget.innerHTML = "";
59+
60+
// Create subheader
61+
const header = document.createElement("p");
62+
header.textContent = "Selected files:";
63+
header.classList.add("font-weight-bold", "mb-1");
64+
65+
// Create file list
3666
const ul = document.createElement("ul");
3767
ul.classList.add("list-unstyled", "mt-2");
3868

39-
Array.from(files).forEach((file) => {
69+
fileNames.forEach((name) => {
4070
const li = document.createElement("li");
4171
li.classList.add("p-1", "rounded", "mb-1");
42-
li.textContent = file.name;
72+
li.textContent = name;
4373
ul.appendChild(li);
4474
});
4575

76+
// Append header and list to target container
77+
this.listTarget.appendChild(header);
4678
this.listTarget.appendChild(ul);
4779
}
4880
}

app/javascript/controllers/item_units_controller.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default class extends Controller {
4343
this.requestSelectTarget.style.display = 'inline';
4444
this.clearOptions()
4545
this.addOption('-1', 'Please select a unit')
46-
this.addOption('', 'Units')
46+
this.addOption('', 'units')
4747
for (const [index, [name, displayName]] of Object.entries(Object.entries(units))) {
4848
this.addOption(name, displayName)
4949
}

app/javascript/controllers/select2_controller.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,19 @@ export default class extends Controller {
2929
}
3030
}
3131
});
32+
33+
/**
34+
* This is a workaround to prevent select2 from filling in an existing
35+
* value even when you try to remove everything. This solution was found at
36+
* https://github.com/select2/select2/issues/3320#issuecomment-1440268574
37+
*/
38+
if ($(this.element).prop('multiple')) {
39+
select2.on("select2:unselecting", function (e) {
40+
$(this).on("select2:opening", function (ev) {
41+
ev.preventDefault();
42+
$(this).off("select2:opening");
43+
});
44+
});
45+
}
3246
}
3347
}

app/models/partners/item_request.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ def request_unit_is_supported
3838

3939
def name_with_unit(quantity_override = nil)
4040
if Flipper.enabled?(:enable_packs) && request_unit.present?
41-
"#{item.name} - #{request_unit.pluralize(quantity_override || quantity.to_i)}"
41+
"#{item&.name || name} - #{request_unit.pluralize(quantity_override || quantity.to_i)}"
4242
else
43-
item.name
43+
item&.name || name
4444
end
4545
end
4646
end

app/models/unit.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@
1010
#
1111
class Unit < ApplicationRecord
1212
belongs_to :organization
13-
validates :name, uniqueness: {scope: :organization}
13+
validates :name,
14+
uniqueness: {scope: :organization},
15+
format: {without: /\Aunits?\z/i, message: "'unit' is reserved."}
1416
end

app/pdfs/picklists_pdf.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def data_with_units(line_items)
145145
data + line_items.map do |line_item|
146146
[line_item.name,
147147
line_item.quantity,
148-
line_item.request_unit&.capitalize&.pluralize(line_item.quantity),
148+
line_item.request_unit&.pluralize(line_item.quantity),
149149
"[ ]",
150150
""]
151151
end

app/services/organization_update_service.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ def update(organization, params)
1818
org_params["partner_form_fields"] = org_params["partner_form_fields"].compact_blank
1919
end
2020

21-
if Flipper.enabled?(:enable_packs) && org_params[:request_unit_names]
21+
if Flipper.enabled?(:enable_packs)
22+
request_unit_names = org_params[:request_unit_names] || []
2223
# Find or create units for the organization
23-
request_unit_ids = org_params[:request_unit_names].compact_blank.map do |request_unit_name|
24+
request_unit_ids = request_unit_names.compact_blank.map do |request_unit_name|
2425
Unit.find_or_create_by(organization: organization, name: request_unit_name).id
2526
end
2627
org_params.delete(:request_unit_names)

0 commit comments

Comments
 (0)