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
57
58
59
60
61
62
63
64
65
66
require "pro_tacts/admin/phlex"

require "pro_tacts/admin/avatar"
require "pro_tacts/admin/format"

module ProTacts
  module Admin
    # The dashboard's ambient column: who has a birthday soon, in the
    # order they arrive, each row opening the contact's card. The
    # store's query has already decided the hard parts (arrival order,
    # the year wrap, which partial shapes land on a day at all); this
    # renders what it hands back, and a birthday without a year shows
    # its day without an age.
    class UpcomingBirthdays < Phlex::HTML
      LIMIT = 10

      #: (upcoming: Array[Store::UpcomingBirthday]) -> void
      def initialize(upcoming:)
        @upcoming = upcoming
      end

      def view_template
        section do
          h2(class: "type-label") { "upcoming birthdays" }
          if @upcoming.empty?
            p(class: "type-body-sm") { "No birthdays to show." }
          else
            ul(class: "card") do
              @upcoming.each do
                render_row(it)
              end
            end
          end
        end
      end

      private

      #: (Store::UpcomingBirthday upcoming) -> void
      def render_row(upcoming)
        contact = upcoming.contact
        li do
          a(href: "/contacts/#{contact.id}") do
            render Avatar.new(contact: contact, size: "lg")
            div(style: "flex: 1; min-width: 0;") do
              div(style: "font-weight: 550;") { contact.name || contact.id }
              div(class: "type-body-sm") { date_line(upcoming) }
            end
            span(class: "type-label") { Format.time_until(upcoming.occurs_on) }
          end
        end
      end

      # The birthday as the contact's own card shows it, with the age
      # it turns on the day when the year is there to know it from.
      #: (Store::UpcomingBirthday upcoming) -> String
      def date_line(upcoming)
        birthday = upcoming.contact.birthday
        text = Format.birthday(upcoming.contact).to_s
        return text if birthday.nil? || birthday.year.nil?

        "#{text} (turns #{upcoming.occurs_on.year - birthday.year})"
      end
    end
  end
end