File size: 7,330 Bytes
88211d3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
defmodule PlausibleWeb.Live.Components.Team do
  @moduledoc """
  Shared component base for listing team members/invitations
  alongside with the role dropdown.
  """
  use PlausibleWeb, :component
  import PlausibleWeb.Components.Generic

  alias Plausible.Auth.User

  attr(:user, User, required: true)
  attr(:label, :string, default: nil)
  attr(:role, :atom, default: nil)
  attr(:my_role, :atom, required: true)
  attr(:me?, :boolean, default: false)
  attr(:disabled, :boolean, default: false)
  attr(:remove_disabled, :boolean, default: false)

  def member(assigns) do
    ~H"""
    <div
      class="mt-6"
      id={"member-row-#{:erlang.phash2(@user.email)}"}
      data-test-kind={if @role == :guest, do: "guest", else: "member"}
      data-role-changed={
        JS.show(
          transition: {"duration-500", "opacity-0 shadow-2xl -translate-y-6", "opacity-100 shadow"},
          time: 400
        )
      }
    >
      <div class="flex items-center gap-x-5">
        <img src={User.profile_img_url(@user)} class="w-8 rounded-full bg-gray-300" />
        <div class="flex flex-col">
          <span class="text-sm font-medium">
            {@user.name}
            <span
              :if={@label}
              class="ml-1 dark:bg-indigo-600 dark:text-gray-200 bg-gray-150 text-gray-500 text-xs px-1 py-0.5 rounded-md"
            >
              {@label}
            </span>
          </span>
          <span class="text-gray-500 text-xs">
            {@user.email}
          </span>
        </div>
        <div class="flex-1 text-right">
          <.dropdown id={"role-dropdown-#{@user.email}"}>
            <:button class="role bg-transparent text-gray-900 dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700 focus-visible:outline-gray-100 whitespace-nowrap truncate inline-flex items-center gap-x-2 font-medium rounded-md px-3.5 py-2.5 text-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 disabled:bg-gray-400 dark:disabled:text-white dark:disabled:text-gray-400 dark:disabled:bg-gray-700">
              <span :if={@disabled} class="text-gray-400">
                {@role |> to_string() |> String.capitalize()}
              </span>
              <span :if={not @disabled}>
                {@role |> to_string() |> String.capitalize()}
              </span>
              <Heroicons.chevron_down :if={@disabled} mini class="text-gray-400 size-4 mt-0.5" />
              <Heroicons.chevron_down :if={not @disabled} mini class="size-4 mt-0.5" />
            </:button>
            <:menu class="dropdown-items max-w-60">
              <.role_item
                user={@user}
                id={"option-#{:erlang.phash2(@user.email)}-owner"}
                phx-value-email={@user.email}
                phx-value-name={@user.name}
                role={:owner}
                disabled={@disabled or @role == :owner}
                dispatch_animation?={@role == :guest}
              >
                Manage the team without restrictions
              </.role_item>
              <.role_item
                user={@user}
                id={"option-#{:erlang.phash2(@user.email)}-admin"}
                phx-value-email={@user.email}
                phx-value-name={@user.name}
                role={:admin}
                disabled={@disabled or @role == :admin}
                dispatch_animation?={@role == :guest}
              >
                Manage all team settings
              </.role_item>
              <.role_item
                user={@user}
                id={"option-#{:erlang.phash2(@user.email)}-editor"}
                phx-value-email={@user.email}
                phx-value-name={@user.name}
                role={:editor}
                disabled={@disabled or @role == :editor}
                dispatch_animation?={@role == :guest}
                data-confirm={if @me?, do: lower_role_warning()}
              >
                Create and view new sites
              </.role_item>
              <.role_item
                user={@user}
                id={"option-#{:erlang.phash2(@user.email)}-billing"}
                phx-value-email={@user.email}
                phx-value-name={@user.name}
                role={:billing}
                disabled={@disabled or @role == :billing}
                dispatch_animation?={@role == :guest}
                data-confirm={if @me?, do: lower_role_warning()}
              >
                Manage subscription
              </.role_item>
              <.role_item
                user={@user}
                id={"option-#{:erlang.phash2(@user.email)}-viewer"}
                phx-value-email={@user.email}
                phx-value-name={@user.name}
                role={:viewer}
                disabled={@disabled or @role == :viewer}
                dispatch_animation?={@role == :guest}
                data-confirm={if @me?, do: lower_role_warning()}
              >
                View all sites under your team
              </.role_item>
              <.dropdown_divider />

              <.dropdown_item
                id={"#{:erlang.phash2(@user.email)}-remove"}
                href="#"
                disabled={@disabled or @remove_disabled}
                phx-click="remove-member"
                phx-value-email={@user.email}
                phx-value-name={@user.name}
                data-confirm="Are you sure you want to remove this member from the team?"
              >
                <div class={
                  not @remove_disabled &&
                    "text-red-600 hover:text-red-600 dark:text-red-500 hover:dark:text-red-400"
                }>
                  Remove member
                </div>
                <div class="text-gray-500 dark:text-gray-400 text-xs/5">
                  Remove member from your team
                </div>
              </.dropdown_item>
            </:menu>
          </.dropdown>
        </div>
      </div>
    </div>
    """
  end

  attr(:role, :atom, required: true)
  attr(:disabled, :boolean, default: false)
  attr(:dispatch_animation?, :boolean, default: false)
  attr(:rest, :global)
  attr(:user, :map, default: %{email: nil})
  attr(:id, :string, default: nil)

  slot(:inner_block, required: true)

  def role_item(assigns) do
    click =
      cond do
        phx_click = assigns.rest[:"phx-click"] ->
          phx_click

        assigns.dispatch_animation? ->
          JS.hide(
            transition: {"duration-500", "opacity-100", "opacity-0"},
            to: "#member-row-#{:erlang.phash2(assigns.user.email)}",
            time: 500
          )
          |> JS.push("update-role")

        true ->
          "update-role"
      end

    assigns = assign(assigns, :click, click)

    ~H"""
    <.dropdown_item
      id={@id}
      href="#"
      phx-click={@click}
      phx-value-role={@role}
      disabled={@disabled}
      {@rest}
    >
      <div>{@role |> Atom.to_string() |> String.capitalize()}</div>
      <div class="text-gray-500 dark:text-gray-400 text-xs/5">
        {render_slot(@inner_block)}
      </div>
    </.dropdown_item>
    """
  end

  defp lower_role_warning() do
    "You're about to lower your own role. Some team management features will no longer be accessible to you, and you'll need to ask a team owner to restore your access. Do you want to continue?"
  end
end