Skip to content

Commit 9f5c1d9

Browse files
committed
feat: add platform metrics on admin page
1 parent 8c3b713 commit 9f5c1d9

File tree

1 file changed

+102
-18
lines changed

1 file changed

+102
-18
lines changed

lib/algora_web/live/admin/admin_live.ex

Lines changed: 102 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,104 @@ defmodule AlgoraWeb.Admin.AdminLive do
33
use AlgoraWeb, :live_view
44

55
import AlgoraWeb.Components.Activity
6+
import Ecto.Query
67

8+
alias Algora.Accounts.User
79
alias Algora.Activities
810
alias Algora.Admin.Mainthings
911
alias Algora.Admin.Mainthings.Mainthing
1012
alias Algora.Analytics
1113
alias Algora.Markdown
14+
alias Algora.Payments.Transaction
15+
alias Algora.Repo
16+
alias AlgoraWeb.Data.PlatformStats
1217
alias AlgoraWeb.LocalStore
1318

19+
defp get_total_paid_out do
20+
subtotal =
21+
Repo.one(
22+
from(t in Transaction,
23+
where: t.type == :credit,
24+
where: t.status == :succeeded,
25+
where: not is_nil(t.linked_transaction_id),
26+
select: sum(t.net_amount)
27+
)
28+
) || Money.new(0, :USD)
29+
30+
subtotal |> Money.add!(PlatformStats.get().extra_paid_out) |> Money.round(currency_digits: 0)
31+
end
32+
33+
defp get_completed_bounties_count do
34+
bounties_subtotal =
35+
Repo.one(
36+
from(t in Transaction,
37+
where: t.type == :credit,
38+
where: t.status == :succeeded,
39+
where: not is_nil(t.linked_transaction_id),
40+
where: not is_nil(t.bounty_id),
41+
select: count(fragment("DISTINCT (?, ?)", t.bounty_id, t.user_id))
42+
)
43+
) || 0
44+
45+
tips_subtotal =
46+
Repo.one(
47+
from(t in Transaction,
48+
where: t.type == :credit,
49+
where: t.status == :succeeded,
50+
where: not is_nil(t.linked_transaction_id),
51+
where: not is_nil(t.tip_id),
52+
select: count(fragment("DISTINCT (?, ?)", t.tip_id, t.user_id))
53+
)
54+
) || 0
55+
56+
bounties_subtotal + tips_subtotal + PlatformStats.get().extra_completed_bounties
57+
end
58+
59+
defp get_contributors_count do
60+
subtotal =
61+
Repo.one(
62+
from(t in Transaction,
63+
where: t.type == :credit,
64+
where: t.status == :succeeded,
65+
where: not is_nil(t.linked_transaction_id),
66+
select: count(fragment("DISTINCT ?", t.user_id))
67+
)
68+
) || 0
69+
70+
subtotal + PlatformStats.get().extra_contributors
71+
end
72+
73+
defp get_countries_count do
74+
Repo.one(
75+
from(u in User,
76+
join: t in Transaction,
77+
on: t.user_id == u.id,
78+
where: t.type == :credit,
79+
where: t.status == :succeeded,
80+
where: not is_nil(t.linked_transaction_id),
81+
where: not is_nil(u.country) and u.country != "",
82+
select: count(fragment("DISTINCT ?", u.country))
83+
)
84+
) || 0
85+
end
86+
87+
defp format_money(money), do: money |> Money.round(currency_digits: 0) |> Money.to_string!(no_fraction_if_integer: true)
88+
89+
defp format_number(number), do: Number.Delimit.number_to_delimited(number, precision: 0)
90+
1491
@impl true
1592
def mount(_params, _session, socket) do
1693
{:ok, analytics} = Analytics.get_company_analytics()
1794
funnel_data = Analytics.get_funnel_data()
1895
:ok = Activities.subscribe()
1996

97+
platform_metrics = [
98+
%{label: "Paid Out", value: format_money(get_total_paid_out())},
99+
%{label: "Completed Bounties", value: format_number(get_completed_bounties_count())},
100+
%{label: "Contributors", value: format_number(get_contributors_count())},
101+
%{label: "Countries", value: format_number(get_countries_count())}
102+
]
103+
20104
# Get user metrics for the last 30 days
21105
user_metrics = Analytics.Metrics.get_user_metrics(30, :daily)
22106

@@ -32,11 +116,11 @@ defmodule AlgoraWeb.Admin.AdminLive do
32116

33117
{:ok,
34118
socket
35-
|> assign(:ip_address, AlgoraWeb.Util.get_ip(socket))
36119
|> assign(:timezone, timezone)
37120
|> assign(:analytics, analytics)
38121
|> assign(:funnel_data, funnel_data)
39122
|> assign(:user_metrics, user_metrics)
123+
|> assign(:platform_metrics, platform_metrics)
40124
|> assign(:selected_period, :daily)
41125
|> assign(:notes_form, to_form(notes_changeset))
42126
|> assign(:notes_preview, (mainthing && Markdown.render_unsafe(mainthing.content)) || "")
@@ -59,9 +143,23 @@ defmodule AlgoraWeb.Admin.AdminLive do
59143
def render(assigns) do
60144
~H"""
61145
<div class="space-y-8 p-8" phx-hook="LocalStateStore" id="admin-page" data-storage="localStorage">
62-
<div class="text-sm text-muted-foreground">
63-
Connected from: <code class="font-mono">{@ip_address}</code>
64-
</div>
146+
<section id="user-metrics" class="scroll-mt-16 space-y-4">
147+
<h1 class="text-2xl font-bold">Metrics</h1>
148+
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
149+
<%= for metric <- @platform_metrics do %>
150+
<.stat_card title={metric.label} value={metric.value} />
151+
<% end %>
152+
</div>
153+
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
154+
<%= for {_date, metrics} <- Enum.take(@user_metrics, 1) do %>
155+
<.stat_card title="Organization Signups" value={metrics.org_signups} subtitle="Last 24h" />
156+
<.stat_card title="Organization Returns" value={metrics.org_returns} subtitle="Last 24h" />
157+
<.stat_card title="Developer Signups" value={metrics.dev_signups} subtitle="Last 24h" />
158+
<.stat_card title="Developer Returns" value={metrics.dev_returns} subtitle="Last 24h" />
159+
<% end %>
160+
</div>
161+
</section>
162+
65163
<section id="sql" class="scroll-mt-16">
66164
<div class="mb-4">
67165
<h1 class="text-2xl font-bold">SQL Query</h1>
@@ -220,20 +318,6 @@ defmodule AlgoraWeb.Admin.AdminLive do
220318
</div>
221319
</section>
222320
223-
<section id="user-metrics" class="scroll-mt-16">
224-
<div class="mb-4">
225-
<h1 class="text-2xl font-bold">User Activity</h1>
226-
</div>
227-
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
228-
<%= for {_date, metrics} <- Enum.take(@user_metrics, 1) do %>
229-
<.stat_card title="Organization Signups" value={metrics.org_signups} subtitle="Last 24h" />
230-
<.stat_card title="Organization Returns" value={metrics.org_returns} subtitle="Last 24h" />
231-
<.stat_card title="Developer Signups" value={metrics.dev_signups} subtitle="Last 24h" />
232-
<.stat_card title="Developer Returns" value={metrics.dev_returns} subtitle="Last 24h" />
233-
<% end %>
234-
</div>
235-
</section>
236-
237321
<section id="customers" class="scroll-mt-16">
238322
<div class="mb-4">
239323
<h1 class="text-2xl font-bold">Customers</h1>

0 commit comments

Comments
 (0)