Skip to content

Commit a86dc57

Browse files
committed
handle all types of claim payment statuses
1 parent fd671f7 commit a86dc57

File tree

3 files changed

+180
-73
lines changed

3 files changed

+180
-73
lines changed

lib/algora_web/components/ui/stat_card.ex

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ defmodule AlgoraWeb.Components.UI.StatCard do
66

77
attr :href, :string, default: nil
88
attr :title, :string
9-
attr :value, :string
9+
attr :value, :string, default: nil
1010
attr :subtext, :string, default: nil
1111
attr :icon, :string, default: nil
1212

13+
slot :inner_block
14+
1315
def stat_card(assigns) do
1416
~H"""
1517
<%= if @href do %>
@@ -35,7 +37,13 @@ defmodule AlgoraWeb.Components.UI.StatCard do
3537
<.icon :if={@icon} name={@icon} class="h-6 w-6 text-muted-foreground" />
3638
</div>
3739
<div class="p-6 pt-0">
38-
<div class="text-2xl font-bold font-display">{@value}</div>
40+
<div class="text-2xl font-bold font-display">
41+
<%= if @value do %>
42+
{@value}
43+
<% else %>
44+
{render_slot(@inner_block)}
45+
<% end %>
46+
</div>
3947
<p :if={@subtext} class="text-xs text-muted-foreground">{@subtext}</p>
4048
</div>
4149
</div>

lib/algora_web/live/claim_live.ex

Lines changed: 113 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ defmodule AlgoraWeb.ClaimLive do
3131
|> Enum.map(& &1.amount)
3232
|> Enum.reduce(Money.zero(:USD, no_fraction_if_integer: true), &Money.add!(&1, &2))
3333

34-
credits =
34+
debits =
3535
claims
3636
|> Enum.flat_map(& &1.transactions)
37-
|> Enum.filter(&(&1.type == :credit and &1.status == :succeeded))
37+
|> Enum.filter(&(&1.type == :debit and &1.status == :succeeded))
3838

3939
total_paid =
40-
credits
40+
debits
4141
|> Enum.map(& &1.net_amount)
4242
|> Enum.reduce(Money.zero(:USD, no_fraction_if_integer: true), &Money.add!(&1, &2))
4343

@@ -49,6 +49,47 @@ defmodule AlgoraWeb.ClaimLive do
4949
_ -> primary_claim.source.description
5050
end
5151

52+
pledges =
53+
primary_claim.target.bounties
54+
|> Enum.group_by(& &1.owner.id)
55+
|> Map.new(fn {owner_id, bounties} ->
56+
{owner_id,
57+
{hd(bounties).owner,
58+
Enum.reduce(bounties, Money.zero(:USD, no_fraction_if_integer: true), &Money.add!(&1.amount, &2))}}
59+
end)
60+
61+
payments =
62+
debits
63+
|> Enum.group_by(& &1.user_id)
64+
|> Map.new(fn {user_id, debits} ->
65+
{user_id, Enum.reduce(debits, Money.zero(:USD, no_fraction_if_integer: true), &Money.add!(&1.net_amount, &2))}
66+
end)
67+
68+
sponsors =
69+
pledges
70+
|> Enum.map(fn {sponsor_id, {sponsor, pledged}} ->
71+
paid = Map.get(payments, sponsor_id, Money.zero(:USD, no_fraction_if_integer: true))
72+
tipped = Money.sub!(paid, pledged)
73+
74+
status =
75+
cond do
76+
Money.equal?(paid, pledged) -> :paid
77+
Money.positive?(tipped) -> :overpaid
78+
Money.positive?(paid) -> :partial
79+
primary_claim.status == :approved -> :pending
80+
true -> :none
81+
end
82+
83+
%{
84+
sponsor: sponsor,
85+
status: status,
86+
pledged: pledged,
87+
paid: paid,
88+
tipped: tipped
89+
}
90+
end)
91+
|> Enum.sort_by(&{&1.pledged, &1.paid, &1.sponsor.name}, :desc)
92+
5293
{:ok,
5394
socket
5495
|> assign(:page_title, primary_claim.source.title)
@@ -59,7 +100,8 @@ defmodule AlgoraWeb.ClaimLive do
59100
|> assign(:bounties, primary_claim.target.bounties)
60101
|> assign(:prize_pool, prize_pool)
61102
|> assign(:total_paid, total_paid)
62-
|> assign(:source_body_html, source_body_html)}
103+
|> assign(:source_body_html, source_body_html)
104+
|> assign(:sponsors, sponsors)}
63105
end
64106
end
65107

@@ -91,8 +133,16 @@ defmodule AlgoraWeb.ClaimLive do
91133
</div>
92134
</div>
93135
<div class="mt-4 grid grid-cols-2 gap-8">
94-
<.stat_card title="Total Paid" value={Money.to_string!(@total_paid)} />
95-
<.stat_card title="Prize Pool" value={Money.to_string!(@prize_pool)} />
136+
<.stat_card title="Total Paid">
137+
<div class="text-success">
138+
{Money.to_string!(@total_paid)}
139+
</div>
140+
</.stat_card>
141+
<.stat_card title="Prize Pool">
142+
<div class="text-success">
143+
{Money.to_string!(@prize_pool)}
144+
</div>
145+
</.stat_card>
96146
</div>
97147
</div>
98148
</.header>
@@ -118,7 +168,6 @@ defmodule AlgoraWeb.ClaimLive do
118168
</.card_header>
119169
<.card_content>
120170
<div class="space-y-6">
121-
<%!-- Pull Request Details --%>
122171
<div class="space-y-4">
123172
<.link
124173
href={@source.url}
@@ -172,23 +221,72 @@ defmodule AlgoraWeb.ClaimLive do
172221
</.card_header>
173222
<.card_content>
174223
<div class="divide-y divide-border">
175-
<%= for bounty <- Enum.sort_by(@bounties, &{&1.amount, &1.inserted_at}, :desc) do %>
224+
<%= for sponsor <- @sponsors do %>
176225
<div class="flex items-center justify-between py-4">
177226
<div class="flex items-center gap-4">
178227
<.avatar>
179-
<.avatar_image src={bounty.owner.avatar_url} />
228+
<.avatar_image src={sponsor.sponsor.avatar_url} />
180229
<.avatar_fallback>
181-
{String.first(bounty.owner.name)}
230+
{String.first(sponsor.sponsor.name)}
182231
</.avatar_fallback>
183232
</.avatar>
184233
<div>
185-
<p class="font-medium">{bounty.owner.name}</p>
186-
<p class="text-sm text-muted-foreground">@{bounty.owner.handle}</p>
234+
<p class="font-medium">{sponsor.sponsor.name}</p>
235+
<p class="text-sm text-muted-foreground">@{sponsor.sponsor.handle}</p>
236+
</div>
237+
</div>
238+
<div class="text-right">
239+
<div class="text-sm font-medium">
240+
<%= case sponsor.status do %>
241+
<% :overpaid -> %>
242+
<div class="text-success">
243+
<span class="text-base font-semibold font-display tabular-nums">
244+
{Money.to_string!(Money.sub!(sponsor.paid, sponsor.tipped))}
245+
</span>
246+
paid
247+
</div>
248+
<div class="text-success">
249+
<span class="text-base font-semibold font-display tabular-nums">
250+
+{Money.to_string!(sponsor.tipped)}
251+
</span>
252+
tip!
253+
</div>
254+
<% :paid -> %>
255+
<div class="text-success">
256+
<span class="text-base font-semibold font-display tabular-nums">
257+
{Money.to_string!(sponsor.paid)}
258+
</span>
259+
paid
260+
</div>
261+
<% :partial -> %>
262+
<div class="text-success">
263+
<span class="text-base font-semibold font-display tabular-nums">
264+
{Money.to_string!(sponsor.paid)}
265+
</span>
266+
paid
267+
</div>
268+
<div class="text-muted-foreground">
269+
<span class="text-base font-semibold font-display tabular-nums">
270+
{Money.to_string!(Money.sub!(sponsor.pledged, sponsor.paid))}
271+
</span>
272+
pending
273+
</div>
274+
<% :pending -> %>
275+
<div class="text-muted-foreground">
276+
<span class="text-base font-semibold font-display tabular-nums">
277+
{Money.to_string!(sponsor.pledged)}
278+
</span>
279+
pending
280+
</div>
281+
<% :none -> %>
282+
<div class="text-success">
283+
<span class="text-base font-semibold font-display tabular-nums">
284+
{Money.to_string!(sponsor.pledged)}
285+
</span>
286+
</div>
287+
<% end %>
187288
</div>
188289
</div>
189-
<.badge variant="success" class="font-display">
190-
{Money.to_string!(bounty.amount)}
191-
</.badge>
192290
</div>
193291
<% end %>
194292
</div>

priv/repo/seeds.exs

Lines changed: 57 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -467,33 +467,22 @@ for {repo_name, issues} <- repos do
467467
url: "https://github.com/piedpiper/#{repo_name}/issues/#{index}"
468468
})
469469

470-
amount = Money.new!(Enum.random([500, 1000, 1500, 2000]), :USD)
471-
472470
claimed = rem(index, 2) > 0
473471
paid = claimed and rem(index, 3) > 0
474472

475-
bounty =
476-
insert!(:bounty, %{
477-
ticket_id: issue.id,
478-
owner_id: pied_piper.id,
479-
creator_id: richard.id,
480-
amount: amount,
481-
status: if(paid, do: :paid, else: :open)
482-
})
483-
484-
pied_piper_members
485-
|> Enum.take_random(Enum.random(0..(length(pied_piper_members) - 1)))
486-
|> Enum.each(fn member ->
487-
amount = Money.new!(Enum.random([500, 1000, 1500, 2000]), :USD)
488-
489-
insert!(:bounty, %{
490-
ticket_id: issue.id,
491-
owner_id: member.id,
492-
creator_id: member.id,
493-
amount: amount,
494-
status: :open
495-
})
496-
end)
473+
bounties =
474+
[2000, 500, 400, 300, 200, 100]
475+
|> Enum.map(&Money.new!(&1, :USD))
476+
|> Enum.zip([pied_piper | pied_piper_members])
477+
|> Enum.map(fn {amount, sponsor} ->
478+
insert!(:bounty, %{
479+
ticket_id: issue.id,
480+
owner_id: sponsor.id,
481+
creator_id: sponsor.id,
482+
amount: amount,
483+
status: if(paid, do: :paid, else: :open)
484+
})
485+
end)
497486

498487
if claimed do
499488
pull_request =
@@ -535,7 +524,12 @@ for {repo_name, issues} <- repos do
535524

536525
group_id = Nanoid.generate()
537526

538-
for {user, share} <- [{carver, Decimal.new("0.5")}, {aly, Decimal.new("0.3")}, {big_head, Decimal.new("0.2")}] do
527+
claimants =
528+
[carver, aly, big_head]
529+
|> Enum.zip(["0.5", "0.3", "0.2"])
530+
|> Enum.map(fn {user, share} -> {user, Decimal.new(share)} end)
531+
532+
for {user, share} <- claimants do
539533
claim =
540534
insert!(:claim, %{
541535
group_id: group_id,
@@ -548,38 +542,45 @@ for {repo_name, issues} <- repos do
548542
url: "https://github.com/piedpiper/#{repo_name}/pull/#{index}"
549543
})
550544

551-
# Create transaction pairs for paid claims
552545
if paid do
553-
debit_id = Nanoid.generate()
554-
credit_id = Nanoid.generate()
555-
556-
Repo.transact(fn ->
557-
insert!(:transaction, %{
558-
id: debit_id,
559-
linked_transaction_id: credit_id,
560-
bounty_id: bounty.id,
561-
claim_id: claim.id,
562-
type: :debit,
563-
status: :succeeded,
564-
net_amount: Money.mult!(amount, share),
565-
user_id: pied_piper.id,
566-
succeeded_at: claim.inserted_at
567-
})
568-
569-
insert!(:transaction, %{
570-
id: credit_id,
571-
linked_transaction_id: debit_id,
572-
bounty_id: bounty.id,
573-
claim_id: claim.id,
574-
type: :credit,
575-
status: :succeeded,
576-
net_amount: Money.mult!(amount, share),
577-
user_id: user.id,
578-
succeeded_at: claim.inserted_at
579-
})
580-
581-
{:ok, :ok}
582-
end)
546+
for {pct_paid, bounty} <-
547+
["1.25", "1.0", "1.0", "0.5", "0.0", "0.0"]
548+
|> Enum.map(&Decimal.new/1)
549+
|> Enum.zip(bounties) do
550+
debit_id = Nanoid.generate()
551+
credit_id = Nanoid.generate()
552+
553+
net_paid = Money.mult!(bounty.amount, Decimal.mult(share, pct_paid))
554+
555+
# Create transaction pairs for paid claims
556+
Repo.transact(fn ->
557+
insert!(:transaction, %{
558+
id: debit_id,
559+
linked_transaction_id: credit_id,
560+
bounty_id: bounty.id,
561+
claim_id: claim.id,
562+
type: :debit,
563+
status: :succeeded,
564+
net_amount: net_paid,
565+
user_id: bounty.owner_id,
566+
succeeded_at: claim.inserted_at
567+
})
568+
569+
insert!(:transaction, %{
570+
id: credit_id,
571+
linked_transaction_id: debit_id,
572+
bounty_id: bounty.id,
573+
claim_id: claim.id,
574+
type: :credit,
575+
status: :succeeded,
576+
net_amount: net_paid,
577+
user_id: user.id,
578+
succeeded_at: claim.inserted_at
579+
})
580+
581+
{:ok, :ok}
582+
end)
583+
end
583584
end
584585
end
585586
end

0 commit comments

Comments
 (0)