admin: label untyped phone and email values in the detail card
A TEL or EMAIL with no TYPE parameter rendered an empty dt, leaving the
value in the grid with no key beside it.

Assisted-by: GLM-5.3 via pi
change omuvvxkuqwptxpzpknuokuoqpupsokxl
commit 4ddd22046933d357281f3f64bfaa7050930c49c5
author Alpha Chen <alpha@kejadlen.dev>
date
parent uuluylmu
diff --git a/lib/pro_tacts/admin/contacts_show.rb b/lib/pro_tacts/admin/contacts_show.rb
index 64dc1ba..aff0af1 100644
--- a/lib/pro_tacts/admin/contacts_show.rb
+++ b/lib/pro_tacts/admin/contacts_show.rb
@@ -49,15 +49,17 @@ module ProTacts
           !@birthday.nil? || !@contact.notes.nil?
       end
 
+      # A missing TYPE parameter still gets a key: the fallback names
+      # the kind of value, so no row renders unlabeled in the grid.
       def rows
-        @contact.phones.each { |phone| row(phone.type, phone.value) }
-        @contact.emails.each { |email| row(email.type, email.value) }
+        @contact.phones.each { |phone| row(phone.type || "phone", phone.value) }
+        @contact.emails.each { |email| row(email.type || "email", email.value) }
         @contact.addresses.each { |address| row(address.type || "address", address_lines(address)) }
         row("birthday", @birthday) if @birthday
         row("notes", @contact.notes) if @contact.notes
       end
 
-      #: (String? type, String | Array[String] value) -> void
+      #: (String type, String | Array[String] value) -> void
       def row(type, value)
         dt(class: "type-label") { type }
         dd(class: "type-body-sm") { render_value(value) }
diff --git a/test/pro_tacts/admin/test_contacts_pages.rb b/test/pro_tacts/admin/test_contacts_pages.rb
index 50d2a5f..8a97c4a 100644
--- a/test/pro_tacts/admin/test_contacts_pages.rb
+++ b/test/pro_tacts/admin/test_contacts_pages.rb
@@ -106,6 +106,19 @@ class AdminContactsPagesTest < Minitest::Test
     end
   end
 
+  # A value with no TYPE parameter still gets a key — the fallback
+  # names the kind of value, so every row in the grid is labeled.
+  def test_show_labels_untyped_values_with_the_property_name
+    untyped = ADA.sub("TEL;TYPE=mobile:", "TEL:").sub("EMAIL;TYPE=home:", "EMAIL:")
+
+    with_contacts({"ada" => untyped}) do
+      get "/contacts/ada"
+
+      assert_includes last_response.body, '<dt class="type-label">phone</dt>'
+      assert_includes last_response.body, '<dt class="type-label">email</dt>'
+    end
+  end
+
   # Empty attributes do not render (docs/DESIGN.md) — a bare card shows
   # only the header, not a scaffold of blank rows.
   def test_show_hides_attributes_the_contact_has_no_data_for