1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
require "pro_tacts/admin/phlex"

module ProTacts
  module Admin
    # What a row's Save will write, at the top of the walk's editor: the
    # card as a new contact, or folded into one the book already has
    # that it looks like (Import::Match,
    # docs/plans/2026-09-23-merging-on-import.md). Rendered only where
    # there is a contact to offer — a toggle with one side is not a
    # choice.
    #
    # Gloss's segmented tabs, a filter over one record rather than
    # navigation between pages, and links rather than buttons: each
    # side is its own rendering of the editor, over the arriving card
    # or over the contact it would update (Import::Merge), so choosing
    # one is a GET for that screen. The form carries the choice back
    # as `into`, the contact the save updates; none is a new contact.
    class ImportTarget < Phlex::HTML
      # @rbs @row: String
      # @rbs @matches: Array[::ProTacts::Contact]
      # @rbs @into: ::ProTacts::Contact?

      # `row` is the row's own screen, `matches` the contacts it looks
      # like, and `into` the one this screen is updating, if any.
      #: (row: String, matches: Array[::ProTacts::Contact], into: ::ProTacts::Contact?) -> void
      def initialize(row:, matches:, into:)
        @row = row
        @matches = matches
        @into = into
      end

      # A div around the tablist, because the form it sits in is a
      # column that stretches its children and the segments are a
      # track of their own width, centered over the editor (the
      # `.import-target` rule in admin.css).
      def view_template
        div(class: "import-target") do
          div(role: "tablist", aria_label: "Import as", data: {variant: "segmented"}) do
            tab("#{@row}?into=", "new contact", @into.nil?)
            @matches.each do |match|
              tab("#{@row}?into=#{match.id}", "update #{match.name || match.id}", @into&.id == match.id)
            end
          end
          input(type: "hidden", name: "into", value: @into.id) if @into
        end
      end

      private

      #: (String href, String label, bool selected) -> void
      def tab(href, label, selected)
        a(href:, role: "tab", aria_selected: selected.to_s) { label }
      end
    end
  end
end