@@ -2,23 +2,12 @@ defmodule AlgoraWeb.Org.BountiesLive do
2
2
@ moduledoc false
3
3
use AlgoraWeb , :live_view
4
4
5
+ alias Algora.Accounts.User
5
6
alias Algora.Bounties
6
7
alias Algora.Bounties.Bounty
7
8
8
9
def mount ( _params , _session , socket ) do
9
- open_bounties = Bounties . list_bounties ( owner_id: socket . assigns . current_org . id , limit: 10 , status: :open )
10
- paid_bounties = Bounties . list_bounties ( owner_id: socket . assigns . current_org . id , limit: 10 , status: :paid )
11
-
12
- # TODO:
13
- claims = [ ]
14
-
15
- { :ok ,
16
- socket
17
- |> assign ( :open_bounties , open_bounties )
18
- |> assign ( :paid_bounties , paid_bounties )
19
- |> assign ( :claims , claims )
20
- |> assign ( :open_count , length ( open_bounties ) )
21
- |> assign ( :completed_count , length ( paid_bounties ) ) }
10
+ { :ok , socket }
22
11
end
23
12
24
13
def render ( assigns ) do
@@ -88,7 +77,7 @@ defmodule AlgoraWeb.Org.BountiesLive do
88
77
< div class = "scrollbar-thin w-full overflow-auto " >
89
78
< table class = "w-full caption-bottom text-sm " >
90
79
< tbody class = "[&_tr:last-child]:border-0 " >
91
- <%= for bounty <- ( if @ current_tab == :open , do: @ open_bounties , else: @ paid_bounties ) do %>
80
+ <%= for % { bounty: bounty , claims: claims } <- @ bounties do %>
92
81
< tr
93
82
class = "bg-white/[2%] from-white/[2%] via-white/[2%] to-white/[2%] border-b border-white/15 bg-gradient-to-br transition-colors data-[state=selected]:bg-gray-100 hover:bg-gray-100/50 dark:data-[state=selected]:bg-gray-800 dark:hover:bg-white/[2%] "
94
83
data-state = "false "
@@ -128,13 +117,13 @@ defmodule AlgoraWeb.Org.BountiesLive do
128
117
</ div >
129
118
</ td >
130
119
< td class = "[&:has([role=checkbox])]:pr-0 p-4 align-middle " >
131
- <%= if length ( @ claims ) > 0 do %>
120
+ <%= if length ( claims ) > 0 do %>
132
121
< div class = "group flex cursor-pointer flex-col items-center gap-1 " >
133
122
< div class = "flex cursor-pointer justify-center -space-x-3 " >
134
- <%= for claim <- @ claims do %>
123
+ <%= for claim <- claims do %>
135
124
< div class = "relative h-10 w-10 flex-shrink-0 rounded-full ring-4 ring-gray-800 group-hover:brightness-110 " >
136
125
< img
137
- alt = { claim . user . username }
126
+ alt = { User . handle ( claim . user ) }
138
127
loading = "lazy "
139
128
decoding = "async "
140
129
class = "rounded-full "
@@ -146,9 +135,7 @@ defmodule AlgoraWeb.Org.BountiesLive do
146
135
</ div >
147
136
< div class = "flex items-center gap-0.5 " >
148
137
< div class = "whitespace-nowrap text-sm font-medium text-gray-300 group-hover:text-gray-100 " >
149
- { length ( @ claims ) } { if length ( @ claims ) == 1 ,
150
- do: "claim" ,
151
- else: "claims" }
138
+ { length ( claims ) } { ngettext ( "claim" , "claims" , length ( claims ) ) }
152
139
</ div >
153
140
< svg
154
141
xmlns = "http://www.w3.org/2000/svg "
@@ -168,26 +155,19 @@ defmodule AlgoraWeb.Org.BountiesLive do
168
155
</ div >
169
156
<% end %>
170
157
</ td >
171
- < td class = "[&:has([role=checkbox])]:pr-0 p-4 align-middle " >
172
- < div class = "min-w-[180px] " >
173
- < div class = "flex items-center justify-end gap-2 " >
174
- <!-- Add action buttons here (edit, delete, menu) -->
175
- </ div >
176
- </ div >
177
- </ td >
178
158
</ tr >
179
- <%= for claim <- @ claims do %>
159
+ <%= for claim <- claims do %>
180
160
< tr
181
161
class = "border-b border-white/15 bg-gray-950/50 transition-colors data-[state=selected]:bg-gray-100 hover:bg-gray-100/50 dark:data-[state=selected]:bg-gray-800 dark:hover:bg-gray-950/50 "
182
162
data-state = "false "
183
163
>
184
- < td class = "[&:has([role=checkbox])]:pr-0 p-4 align-middle " >
164
+ < td class = "[&:has([role=checkbox])]:pr-0 p-4 align-middle w-full " >
185
165
< div class = "min-w-[250px] " >
186
166
< div class = "flex items-center gap-3 " >
187
167
< div class = "flex -space-x-3 " >
188
168
< div class = "relative h-10 w-10 flex-shrink-0 rounded-full ring-4 ring-gray-800 " >
189
169
< img
190
- alt = { claim . user . username }
170
+ alt = { User . handle ( claim . user ) }
191
171
loading = "lazy "
192
172
decoding = "async "
193
173
class = "rounded-full "
@@ -198,7 +178,7 @@ defmodule AlgoraWeb.Org.BountiesLive do
198
178
</ div >
199
179
< div >
200
180
< div class = "text-sm font-medium text-gray-200 " >
201
- { claim . user . username }
181
+ { User . handle ( claim . user ) }
202
182
</ div >
203
183
< div class = "text-xs text-gray-400 " >
204
184
{ Algora.Util . time_ago ( claim . inserted_at ) }
@@ -207,23 +187,15 @@ defmodule AlgoraWeb.Org.BountiesLive do
207
187
</ div >
208
188
</ div >
209
189
</ td >
210
- < td class = "[&:has([role=checkbox])]:pr-0 p-4 align-middle " > </ td >
211
190
< td class = "[&:has([role=checkbox])]:pr-0 p-4 align-middle " >
212
191
< div class = "min-w-[180px] " >
213
192
< div class = "flex items-center justify-end gap-4 " >
214
- < . link
215
- rel = "noopener "
216
- class = "inline-flex h-10 items-center justify-center rounded-md bg-gray-100 px-4 py-2 text-sm font-medium text-gray-900 hover:bg-gray-100/80 dark:bg-white/15 dark:text-gray-50 dark:hover:bg-white/20 "
217
- href = { claim . pull_request_url }
218
- >
219
- View
220
- </ . link >
221
- < . link
222
- class = "inline-flex h-10 items-center justify-center rounded-md bg-emerald-600 px-4 py-2 text-sm font-medium text-white hover:bg-emerald-600/90 "
223
- href = "# "
224
- >
225
- Reward
226
- </ . link >
193
+ < . button variant = "secondary " >
194
+ < . link href = { claim . source . url } > View</ . link >
195
+ </ . button >
196
+ < . button >
197
+ < . link href = { ~p" /claims/#{ claim . group_id } " } > Reward</ . link >
198
+ </ . button >
227
199
</ div >
228
200
</ div >
229
201
</ td >
@@ -247,7 +219,42 @@ defmodule AlgoraWeb.Org.BountiesLive do
247
219
end
248
220
249
221
def handle_params ( params , _uri , socket ) do
250
- { :noreply , assign ( socket , :current_tab , get_current_tab ( params ) ) }
222
+ limit = 10
223
+ current_org = socket . assigns . current_org
224
+ current_tab = get_current_tab ( params )
225
+
226
+ # TODO: fetch only bounties for the current tab
227
+ open_bounties = Bounties . list_bounties ( owner_id: current_org . id , limit: limit , status: :open )
228
+ paid_bounties = Bounties . list_bounties ( owner_id: current_org . id , limit: limit , status: :paid )
229
+
230
+ # TODO: fetch stats in one query
231
+ open_count = length ( open_bounties )
232
+ paid_count = length ( paid_bounties )
233
+
234
+ bounties =
235
+ case current_tab do
236
+ :open -> open_bounties
237
+ :completed -> paid_bounties
238
+ end
239
+
240
+ claims_by_ticket =
241
+ bounties
242
+ |> Enum . map ( & & 1 . ticket . id )
243
+ |> Bounties . list_claims ( )
244
+ |> Enum . group_by ( & & 1 . target_id )
245
+
246
+ bounties =
247
+ Enum . map ( bounties , fn bounty ->
248
+ # TODO: group claims by group_id
249
+ % { bounty: bounty , claims: Map . get ( claims_by_ticket , bounty . ticket . id , [ ] ) }
250
+ end )
251
+
252
+ { :noreply ,
253
+ socket
254
+ |> assign ( :current_tab , current_tab )
255
+ |> assign ( :bounties , bounties )
256
+ |> assign ( :open_count , open_count )
257
+ |> assign ( :completed_count , paid_count ) }
251
258
end
252
259
253
260
defp get_current_tab ( params ) do
0 commit comments