1
1
defmodule AlgoraWeb.Org.BountiesLive do
2
2
@ moduledoc false
3
3
use AlgoraWeb , :live_view
4
+ use Ecto.Schema
5
+
6
+ import Ecto.Changeset
7
+ import Ecto.Query
4
8
5
9
alias Algora.Accounts.User
6
10
alias Algora.Bounties
7
11
alias Algora.Bounties.Bounty
8
12
alias Algora.Payments
13
+ alias Algora.Repo
14
+ alias Algora.Types.USD
15
+ alias Algora.Workspace
16
+
17
+ embedded_schema do
18
+ field :amount , USD
19
+ end
20
+
21
+ def edit_amount_changeset ( attrs \\ % { } ) do
22
+ % __MODULE__ { }
23
+ |> cast ( attrs , [ :amount ] )
24
+ |> validate_required ( [ :amount ] )
25
+ |> Algora.Validations . validate_money_positive ( :amount )
26
+ end
9
27
10
28
def mount ( _params , _session , socket ) do
11
- { :ok , socket }
29
+ { :ok ,
30
+ socket
31
+ |> assign ( :show_edit_modal , false )
32
+ |> assign ( :editing_bounty , nil )
33
+ |> assign ( :edit_form , to_form ( edit_amount_changeset ( ) ) ) }
12
34
end
13
35
14
36
def render ( assigns ) do
@@ -159,6 +181,26 @@ defmodule AlgoraWeb.Org.BountiesLive do
159
181
</ div >
160
182
<% end %>
161
183
</ td >
184
+ < td class = "[&:has([role=checkbox])]:pr-0 p-4 align-middle " >
185
+ < div class = "flex items-center gap-2 " >
186
+ < . button
187
+ phx-click = "edit-bounty-amount "
188
+ phx-value-id = { bounty . id }
189
+ variant = "secondary "
190
+ size = "sm "
191
+ >
192
+ Edit Amount
193
+ </ . button >
194
+ < . button
195
+ phx-click = "delete-bounty "
196
+ phx-value-id = { bounty . id }
197
+ variant = "destructive "
198
+ size = "sm "
199
+ >
200
+ Delete
201
+ </ . button >
202
+ </ div >
203
+ </ td >
162
204
</ tr >
163
205
<%= for { _group_id , claims } <- claim_groups do %>
164
206
< tr
@@ -268,6 +310,40 @@ defmodule AlgoraWeb.Org.BountiesLive do
268
310
</ div >
269
311
</ div >
270
312
</ div >
313
+
314
+ <!-- Edit Amount Drawer -->
315
+ < . drawer show = { @ show_edit_modal } direction = "right " on_cancel = "cancel-edit " >
316
+ < . drawer_header >
317
+ < . drawer_title > Edit Bounty Amount</ . drawer_title >
318
+ < . drawer_description >
319
+ Update the bounty amount for this issue
320
+ </ . drawer_description >
321
+ </ . drawer_header >
322
+ < . drawer_content >
323
+ < . form
324
+ for = { @ edit_form }
325
+ as = "edit_amount "
326
+ phx-submit = "save-bounty-amount "
327
+ phx-change = "validate-amount "
328
+ class = "space-y-4 "
329
+ >
330
+ < . input
331
+ label = "New Amount "
332
+ icon = "tabler-currency-dollar "
333
+ field = { @ edit_form [ :amount ] }
334
+ placeholder = "e.g., 1000 "
335
+ />
336
+ < div class = "flex gap-3 justify-end " >
337
+ < . button type = "button " variant = "secondary " phx-click = "cancel-edit " >
338
+ Cancel
339
+ </ . button >
340
+ < . button type = "submit " variant = "default " >
341
+ Save
342
+ </ . button >
343
+ </ div >
344
+ </ . form >
345
+ </ . drawer_content >
346
+ </ . drawer >
271
347
"""
272
348
end
273
349
@@ -287,6 +363,116 @@ defmodule AlgoraWeb.Org.BountiesLive do
287
363
end }
288
364
end
289
365
366
+ def handle_event ( "delete-bounty" , % { "id" => bounty_id } , socket ) do
367
+ bounty = Repo . get! ( Bounty , bounty_id )
368
+
369
+ case Bounties . delete_bounty ( bounty ) do
370
+ { :ok , _bounty } ->
371
+ { :noreply ,
372
+ socket
373
+ |> put_flash ( :info , "Bounty deleted successfully" )
374
+ |> assign_bounties ( ) }
375
+
376
+ { :error , _changeset } ->
377
+ { :noreply , put_flash ( socket , :error , "Failed to delete bounty" ) }
378
+ end
379
+ end
380
+
381
+ def handle_event ( "edit-bounty-amount" , % { "id" => bounty_id } , socket ) do
382
+ [ bounty ] = Bounties . list_bounties ( id: bounty_id )
383
+ changeset = edit_amount_changeset ( % { amount: bounty . amount } )
384
+
385
+ { :noreply ,
386
+ socket
387
+ |> assign ( :editing_bounty , bounty )
388
+ |> assign ( :edit_form , to_form ( changeset ) )
389
+ |> assign ( :show_edit_modal , true ) }
390
+ end
391
+
392
+ def handle_event ( "validate-amount" , params , socket ) do
393
+ form_params =
394
+ case params do
395
+ % { "edit_amount" => form_params } -> form_params
396
+ % { "bounties_live" => form_params } -> form_params
397
+ _ -> % { }
398
+ end
399
+
400
+ changeset =
401
+ form_params
402
+ |> edit_amount_changeset ( )
403
+ |> Map . put ( :action , :validate )
404
+
405
+ { :noreply , assign ( socket , :edit_form , to_form ( changeset ) ) }
406
+ end
407
+
408
+ def handle_event ( "save-bounty-amount" , params , socket ) do
409
+ form_params =
410
+ case params do
411
+ % { "edit_amount" => form_params } -> form_params
412
+ % { "bounties_live" => form_params } -> form_params
413
+ _ -> % { }
414
+ end
415
+
416
+ changeset = edit_amount_changeset ( form_params )
417
+
418
+ case apply_action ( changeset , :update ) do
419
+ { :ok , % { amount: amount } } ->
420
+ bounty =
421
+ Bounty
422
+ |> Repo . get ( socket . assigns . editing_bounty . id )
423
+ |> Repo . preload ( [ :owner , [ ticket: [ repository: :user ] ] ] )
424
+
425
+ with { :ok , installation } <-
426
+ Workspace . fetch_installation_by (
427
+ provider: "github" ,
428
+ connected_user_id: bounty . ticket . repository . user . id
429
+ ) ,
430
+ { :ok , bounty } <-
431
+ bounty
432
+ |> Bounty . changeset ( % { amount: amount } )
433
+ |> Repo . update ( ) ,
434
+ { :ok , cr } <-
435
+ Workspace . fetch_command_response ( bounty . ticket_id , :bounty ) ,
436
+ { :ok , _job } <-
437
+ Bounties . notify_bounty (
438
+ % {
439
+ owner: bounty . owner ,
440
+ bounty: bounty ,
441
+ ticket_ref: % {
442
+ owner: bounty . ticket . repository . user . provider_login ,
443
+ repo: bounty . ticket . repository . name ,
444
+ number: bounty . ticket . number
445
+ }
446
+ } ,
447
+ installation_id: installation . provider_id ,
448
+ command_id: cr . provider_command_id ,
449
+ command_source: cr . command_source
450
+ ) do
451
+ { :noreply ,
452
+ socket
453
+ |> assign ( :show_edit_modal , false )
454
+ |> assign ( :editing_bounty , nil )
455
+ |> assign ( :edit_form , to_form ( edit_amount_changeset ( ) ) )
456
+ |> put_flash ( :info , "Bounty amount updated successfully" )
457
+ |> assign_bounties ( ) }
458
+ else
459
+ { :error , _changeset } ->
460
+ { :noreply , put_flash ( socket , :error , "Failed to update bounty amount" ) }
461
+ end
462
+
463
+ { :error , changeset } ->
464
+ { :noreply , assign ( socket , :edit_form , to_form ( changeset ) ) }
465
+ end
466
+ end
467
+
468
+ def handle_event ( "cancel-edit" , _params , socket ) do
469
+ { :noreply ,
470
+ socket
471
+ |> assign ( :show_edit_modal , false )
472
+ |> assign ( :editing_bounty , nil )
473
+ |> assign ( :edit_form , to_form ( edit_amount_changeset ( ) ) ) }
474
+ end
475
+
290
476
def handle_event ( _event , _params , socket ) do
291
477
{ :noreply , socket }
292
478
end
@@ -387,4 +573,18 @@ defmodule AlgoraWeb.Org.BountiesLive do
387
573
end
388
574
389
575
defp page_size , do: 10
576
+
577
+ defp assign_bounties ( socket ) do
578
+ current_org = socket . assigns . current_org
579
+
580
+ bounties =
581
+ Bounties . list_bounties (
582
+ owner_id: current_org . id ,
583
+ limit: page_size ( ) ,
584
+ status: :open ,
585
+ current_user: socket . assigns [ :current_user ]
586
+ )
587
+
588
+ assign ( socket , :bounty_rows , to_bounty_rows ( bounties ) )
589
+ end
390
590
end
0 commit comments