diff --git a/app/helpers/record_helper.rb b/app/helpers/record_helper.rb
index 020777e3..ba6a7274 100644
--- a/app/helpers/record_helper.rb
+++ b/app/helpers/record_helper.rb
@@ -139,6 +139,51 @@ def deduplicate_subjects(subjects)
subjects.map { |subject| subject['value'].uniq(&:downcase) }.uniq { |values| values.map(&:downcase) }
end
+ # Formats availability information for display.
+ # Expects:
+ # - status: a string indicating availability status
+ # - location: an array with three elements: [library name, location name, call number]
+ # - other_availability: a boolean string indicating if there is availability at other locations
+ def availability(status, location, other_availability)
+ blurb = case status.downcase
+ # `available` is a common status used in Alma/Primo VE for items that are not checked out and should be
+ # on the shelf
+ when 'available'
+ "#{icon('check')} Available in #{location(location)}"
+ # `check_holdings`: unclear when (or if) this is used. Bento handled this so we did too assuming it was
+ # meaningful
+ when 'check_holdings'
+ "#{icon('question')} May be available in #{location(location)}"
+ # 'unavailable' is used for items that are checked out, missing, or otherwise not on the shelf
+ when 'unavailable'
+ "#{icon('times')} Not currently available in #{location(location)}"
+ # Unclear if there are other statuses we should handle here. For now we log and display a generic message.
+ else
+ Rails.logger.error("Unhandled availability status: #{status.inspect}")
+ "#{icon('question')} Uncertain availability in #{location(location)} #{status}"
+ end
+
+ blurb += ' and other locations.' if other_availability.present?
+
+ # We are generating HTML in this helper, so we need to mark it as safe or it will be escaped in the view.
+ blurb.html_safe
+ end
+
+ # Fontawesome helper. Currently only takes the icon name and assumes solid sharp style.
+ # Could be extended later to default to these styles but allow overrides if appropriate.
+ # Also defaults to aria-hidden true, which is probably what we want for icons used
+ # purely for decoration. If an icon is used in a more meaningful way, we may want to extend this helper
+ # to allow passing in additional aria attributes.
+ def icon(fa)
+ ""
+ end
+
+ # Formats location information for availability display.
+ # Expects an array with three elements: [library name, location name, call number]
+ def location(loc)
+ "#{loc[:name]} #{loc[:collection]} (#{loc[:call_number]})"
+ end
+
private
def render_kind_value(list)
diff --git a/app/models/normalize_primo_record.rb b/app/models/normalize_primo_record.rb
index 9ea61873..f0b3ea0b 100644
--- a/app/models/normalize_primo_record.rb
+++ b/app/models/normalize_primo_record.rb
@@ -275,12 +275,18 @@ def publisher
@record['pnx']['addata']['pub'].first
end
+ # Current logic in this method should likely move to `holdings` field
def location
return unless @record['delivery']
return unless @record['delivery']['bestlocation']
loc = @record['delivery']['bestlocation']
- ["#{loc['mainLocation']} #{loc['subLocation']}", loc['callNumber']]
+
+ {
+ name: loc['mainLocation'],
+ collection: loc['subLocation'],
+ call_number: loc['callNumber']
+ }
end
def subjects
diff --git a/app/views/search/_result_primo.html.erb b/app/views/search/_result_primo.html.erb
index cf696c47..5096b4ff 100644
--- a/app/views/search/_result_primo.html.erb
+++ b/app/views/search/_result_primo.html.erb
@@ -40,6 +40,9 @@
<%= link_to link['kind'].titleize, link['url'], class: 'button' %>
<% end %>
<% end %>
+ <% if result[:availability].present? %>
+ <%= availability(result[:availability], result[:location], result[:other_availability]) %>
+ <% end %>
diff --git a/test/helpers/record_helper_test.rb b/test/helpers/record_helper_test.rb
index cbec11b6..36c9d8ea 100644
--- a/test/helpers/record_helper_test.rb
+++ b/test/helpers/record_helper_test.rb
@@ -341,4 +341,28 @@ class RecordHelperTest < ActionView::TestCase
subjects = []
assert_nil deduplicate_subjects(subjects)
end
+
+ test 'availability helper handles known statuses correctly' do
+ location = {
+ name: 'Main Library',
+ collection: 'First Floor',
+ call_number: 'QA76.73.R83 2023'
+ }
+
+ available_blurb = availability('available', location, false)
+ assert_includes available_blurb, 'Available in'
+ assert_includes available_blurb, location(location)
+
+ check_holdings_blurb = availability('check_holdings', location, false)
+ assert_includes check_holdings_blurb, 'May be available in'
+ assert_includes check_holdings_blurb, location(location)
+
+ unavailable_blurb = availability('unavailable', location, false)
+ assert_includes unavailable_blurb, 'Not currently available in'
+ assert_includes unavailable_blurb, location(location)
+
+ unknown_blurb = availability('unknown_status', location, false)
+ assert_includes unknown_blurb, 'Uncertain availability in'
+ assert_includes unknown_blurb, location(location)
+ end
end
diff --git a/test/models/normalize_primo_record_test.rb b/test/models/normalize_primo_record_test.rb
index bc6ebd55..4f23d610 100644
--- a/test/models/normalize_primo_record_test.rb
+++ b/test/models/normalize_primo_record_test.rb
@@ -174,7 +174,7 @@ def cdi_record
test 'returns best location with call number' do
normalized = NormalizePrimoRecord.new(full_record, 'test').normalize
- expected_location = ['Hayden Library Stacks', 'QA76.73.R83 2023']
+ expected_location = { name: 'Hayden Library', collection: 'Stacks', call_number: 'QA76.73.R83 2023' }
assert_equal expected_location, normalized[:location]
end