@@ -3,20 +3,104 @@ defmodule AlgoraWeb.Admin.AdminLive do
3
3
use AlgoraWeb , :live_view
4
4
5
5
import AlgoraWeb.Components.Activity
6
+ import Ecto.Query
6
7
8
+ alias Algora.Accounts.User
7
9
alias Algora.Activities
8
10
alias Algora.Admin.Mainthings
9
11
alias Algora.Admin.Mainthings.Mainthing
10
12
alias Algora.Analytics
11
13
alias Algora.Markdown
14
+ alias Algora.Payments.Transaction
15
+ alias Algora.Repo
16
+ alias AlgoraWeb.Data.PlatformStats
12
17
alias AlgoraWeb.LocalStore
13
18
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
+
14
91
@ impl true
15
92
def mount ( _params , _session , socket ) do
16
93
{ :ok , analytics } = Analytics . get_company_analytics ( )
17
94
funnel_data = Analytics . get_funnel_data ( )
18
95
:ok = Activities . subscribe ( )
19
96
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
+
20
104
# Get user metrics for the last 30 days
21
105
user_metrics = Analytics.Metrics . get_user_metrics ( 30 , :daily )
22
106
@@ -32,11 +116,11 @@ defmodule AlgoraWeb.Admin.AdminLive do
32
116
33
117
{ :ok ,
34
118
socket
35
- |> assign ( :ip_address , AlgoraWeb.Util . get_ip ( socket ) )
36
119
|> assign ( :timezone , timezone )
37
120
|> assign ( :analytics , analytics )
38
121
|> assign ( :funnel_data , funnel_data )
39
122
|> assign ( :user_metrics , user_metrics )
123
+ |> assign ( :platform_metrics , platform_metrics )
40
124
|> assign ( :selected_period , :daily )
41
125
|> assign ( :notes_form , to_form ( notes_changeset ) )
42
126
|> assign ( :notes_preview , ( mainthing && Markdown . render_unsafe ( mainthing . content ) ) || "" )
@@ -59,9 +143,23 @@ defmodule AlgoraWeb.Admin.AdminLive do
59
143
def render ( assigns ) do
60
144
~H"""
61
145
< 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
+
65
163
< section id = "sql " class = "scroll-mt-16 " >
66
164
< div class = "mb-4 " >
67
165
< h1 class = "text-2xl font-bold " > SQL Query</ h1 >
@@ -220,20 +318,6 @@ defmodule AlgoraWeb.Admin.AdminLive do
220
318
</ div >
221
319
</ section >
222
320
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
-
237
321
< section id = "customers " class = "scroll-mt-16 " >
238
322
< div class = "mb-4 " >
239
323
< h1 class = "text-2xl font-bold " > Customers</ h1 >
0 commit comments