Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1e76647
feat: add GitHub funding section to HomeLive
zcesur Mar 15, 2025
46e69d4
feat: implement bounty and tip submission forms in HomeLive
zcesur Mar 15, 2025
0e25e03
feat: enhance GitHub funding section in HomeLive
zcesur Mar 15, 2025
9933b16
refactor: update link components in HomeLive
zcesur Mar 15, 2025
ecf6a00
feat: expand HomeLive with new contract and hiring features
zcesur Mar 15, 2025
39b2335
feat: add FAQ section and enhance HomeLive layout
zcesur Mar 15, 2025
2e4eb80
add notes section on admin
zcesur Mar 17, 2025
9b468e5
reorganize
zcesur Mar 17, 2025
65549d2
feat: integrate bounties into analytics
zcesur Mar 17, 2025
75e3827
feat: update admin analytics layout and navigation
zcesur Mar 17, 2025
a17dbde
feat: enhance company analytics layout with floating period selector
zcesur Mar 17, 2025
d4fede6
refactor: update analytics layout and navigation structure
zcesur Mar 17, 2025
87f857f
refactor: restructure user and admin navigation components
zcesur Mar 17, 2025
a3a8c87
refactor: update admin routing and navigation links
zcesur Mar 17, 2025
c342a19
feat: implement admin live view with analytics and notes functionality
zcesur Mar 17, 2025
c3be27a
refactor: enhance user navigation layout and contact display
zcesur Mar 17, 2025
1809928
refactor: improve admin page conditionals and enhance leaderboard logic
zcesur Mar 17, 2025
fec630d
feat: enhance notes functionality in admin live view
zcesur Mar 17, 2025
5e45b07
refactor: improve notes section layout and responsiveness in admin li…
zcesur Mar 17, 2025
45ebec0
Merge branch 'main' of github.com:algora-io/console into vibe/code
zcesur Mar 17, 2025
78a3b2c
refactor: update admin dashboard layout and enhance user navigation
zcesur Mar 17, 2025
c1f3698
refactor: enhance section layout in admin live view for improved navi…
zcesur Mar 17, 2025
e8c359b
refactor: rename analytics section to metrics and update navigation
zcesur Mar 17, 2025
c2e431d
refactor: update analytics module to use bounties instead of contracts
zcesur Mar 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .iex.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ alias Algora.Accounts.Identity
alias Algora.Accounts.User
alias Algora.Admin
alias Algora.Admin.Migration
alias Algora.Analytics
alias Algora.Bounties
alias Algora.Bounties.Claim
alias Algora.Contracts
Expand Down
42 changes: 42 additions & 0 deletions lib/algora/admin/mainthing/mainthing.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
defmodule Algora.Admin.Mainthings do
@moduledoc false

import Ecto.Query

alias Algora.Admin.Mainthings.Mainthing
alias Algora.Repo

@doc """
Gets the latest mainthing entry.
"""
def get_latest do
Mainthing
|> last(:inserted_at)
|> Repo.one()
end

@doc """
Creates a new mainthing entry.
"""
def create(attrs \\ %{}) do
%Mainthing{}
|> Mainthing.changeset(attrs)
|> Repo.insert()
end

@doc """
Updates a mainthing entry.
"""
def update(%Mainthing{} = mainthing, attrs) do
mainthing
|> Mainthing.changeset(attrs)
|> Repo.update()
end

@doc """
Deletes a mainthing entry.
"""
def delete(%Mainthing{} = mainthing) do
Repo.delete(mainthing)
end
end
19 changes: 19 additions & 0 deletions lib/algora/admin/mainthing/schemas/mainthing.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
defmodule Algora.Admin.Mainthings.Mainthing do
@moduledoc false
use Algora.Schema

import Ecto.Changeset

typed_schema "mainthings" do
field :content, :string, null: false

timestamps()
end

def changeset(mainthing, attrs) do
mainthing
|> cast(attrs, [:content])
|> validate_required([:content])
|> generate_id()
end
end
46 changes: 25 additions & 21 deletions lib/algora/analytics/analytics.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Algora.Analytics do
import Ecto.Query

alias Algora.Accounts.User
alias Algora.Contracts.Contract
alias Algora.Bounties.Bounty
alias Algora.Repo

require Algora.SQL
Expand Down Expand Up @@ -42,41 +42,45 @@ defmodule Algora.Analytics do
}

contracts_query =
from u in Contract,
where: u.inserted_at >= ^previous_period_start,
from b in Bounty,
where: b.inserted_at >= ^previous_period_start,
select: %{
count_current: u.id |> count() |> filter(u.inserted_at < ^from and u.inserted_at >= ^period_start),
count_current: b.id |> count() |> filter(b.inserted_at < ^from and b.inserted_at >= ^period_start),
count_previous:
u.id |> count() |> filter(u.inserted_at < ^period_start and u.inserted_at >= ^previous_period_start),
b.id |> count() |> filter(b.inserted_at < ^period_start and b.inserted_at >= ^previous_period_start),
success_current:
u.id
b.id
|> count()
|> filter(
u.inserted_at < ^from and u.inserted_at >= ^period_start and (u.status == :active or u.status == :paid)
b.inserted_at < ^from and b.inserted_at >= ^period_start and (b.status == :open or b.status == :paid)
),
success_previous:
u.id
b.id
|> count()
|> filter(
u.inserted_at < ^period_start and u.inserted_at >= ^previous_period_start and
(u.status == :active or u.status == :paid)
b.inserted_at < ^period_start and b.inserted_at >= ^previous_period_start and
(b.status == :open or b.status == :paid)
)
}

companies_query =
from u in User,
where: u.inserted_at >= ^period_start and u.type == :organization,
right_join: c in Contract,
on: c.client_id == u.id,
group_by: u.id,
where: u.inserted_at >= ^period_start,
where: u.type == :organization,
where: u.featured,
left_join: b in Bounty,
on: b.owner_id == u.id,
distinct: [u.id],
group_by: [u.id, b.id],
order_by: [desc: b.inserted_at],
select: %{
id: u.id,
name: u.name,
handle: u.handle,
joined_at: u.inserted_at,
total_contracts: c.id |> count() |> filter(c.inserted_at >= ^period_start),
successful_contracts:
c.id |> count() |> filter(c.status == :active or (c.status == :paid and c.inserted_at >= ^period_start)),
total_bounties: b.id |> count() |> filter(b.inserted_at >= ^period_start),
successful_bounties:
b.id |> count() |> filter(b.status == :open or (b.status == :paid and b.inserted_at >= ^period_start)),
last_active_at: u.updated_at,
avatar_url: u.avatar_url
}
Expand Down Expand Up @@ -112,15 +116,15 @@ defmodule Algora.Analytics do
avg_time_to_fill: 0.0,
time_to_fill_change: -0.0,
time_to_fill_trend: :down,
contract_success_rate: current_success_rate,
previous_contract_success_rate: previous_success_rate,
bounty_success_rate: current_success_rate,
previous_bounty_success_rate: previous_success_rate,
success_rate_change: current_success_rate - previous_success_rate,
success_rate_trend: calculate_trend(current_success_rate, previous_success_rate),
companies:
Enum.map(companies, fn company ->
Map.merge(company, %{
success_rate: calculate_success_rate(company.successful_contracts, company.total_contracts),
status: if(company.successful_contracts > 0, do: :active, else: :inactive)
success_rate: calculate_success_rate(company.successful_bounties, company.total_bounties),
status: if(company.successful_bounties > 0, do: :active, else: :inactive)
})
end)
}}
Expand Down
8 changes: 8 additions & 0 deletions lib/algora_web/components/core_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,14 @@ defmodule AlgoraWeb.CoreComponents do
</div>
</div>
</:link>
<:link :if={@current_user.is_admin} href={~p"/admin"}>
<div class="flex items-center whitespace-nowrap">
<div class="mr-3 flex h-8 w-8 items-center justify-center">
<.icon name="tabler-adjustments-alt" class="h-5 w-5" />
</div>
<div class="font-semibold">Admin</div>
</div>
</:link>
<:link href={~p"/auth/logout"}>
<div class="flex items-center whitespace-nowrap">
<div class="mr-3 flex h-8 w-8 items-center justify-center">
Expand Down
113 changes: 65 additions & 48 deletions lib/algora_web/components/layouts/user.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -82,62 +82,66 @@
<.logo class="h-8 w-auto text-white" />
</div>
<nav class="mt-4">
<ul role="list" class="flex flex-col items-center space-y-1">
<%= for item <- @nav |> List.first() |> Map.get(:items) do %>
<li>
<.link
navigate={item.href}
target={Map.get(item, :target)}
class={[
"group flex gap-x-3 rounded-md p-3 text-sm/6 font-semibold text-gray-400 hover:bg-gray-800 hover:text-white",
if(@active_tab == item.tab,
do: "bg-gray-800 text-white",
else: "text-gray-400 hover:bg-gray-800 hover:text-white"
)
]}
>
<.icon name={item.icon} class="h-6 w-6 shrink-0" />
<span class="sr-only">{item.label}</span>
</.link>
</li>
<% end %>
</ul>

<.separator class="mx-auto my-4 w-2/3" />
<%= for {section, index} <- Enum.with_index(@nav) do %>
<ul role="list" class="flex flex-col items-center space-y-1">
<%= for item <- section.items do %>
<li>
<.link
navigate={item.href}
target={Map.get(item, :target)}
class={[
"group flex gap-x-3 rounded-md p-3 text-sm/6 font-semibold text-gray-400 hover:bg-gray-800 hover:text-white",
if(@active_tab == item.tab,
do: "bg-gray-800 text-white",
else: "text-gray-400 hover:bg-gray-800 hover:text-white"
)
]}
>
<.icon name={item.icon} class="h-6 w-6 shrink-0" />
<span class="sr-only">{item.label}</span>
</.link>
</li>
<% end %>
</ul>
<.separator :if={index != length(@nav) - 1} class="mx-auto my-4 w-2/3" />
<% end %>

<ul role="list" class="space-y-1">
<%= for contact <- @contacts do %>
<li>
<.link
class="flex justify-center p-2"
navigate={Algora.Accounts.User.url(contact)}
title={Algora.Accounts.User.handle(contact)}
>
<div class="relative inline-block">
<div class="relative h-8 w-8 flex-shrink-0 overflow-hidden rounded-full">
<img
alt={Algora.Accounts.User.handle(contact)}
loading="lazy"
decoding="async"
src={contact.avatar_url}
class="h-full w-full object-cover"
/>
<%= if @contacts != [] do %>
<.separator class="mx-auto my-4 w-2/3" />
<ul role="list" class="space-y-1">
<%= for contact <- @contacts do %>
<li>
<.link
class="flex justify-center p-2"
navigate={Algora.Accounts.User.url(contact)}
title={Algora.Accounts.User.handle(contact)}
>
<div class="relative inline-block">
<div class="relative h-8 w-8 flex-shrink-0 overflow-hidden rounded-full">
<img
alt={Algora.Accounts.User.handle(contact)}
loading="lazy"
decoding="async"
src={contact.avatar_url}
class="h-full w-full object-cover"
/>
</div>
<span class="absolute right-0 bottom-0 block h-2 w-2 rounded-full bg-green-400 ring-2 ring-white dark:ring-gray-950">
</span>
</div>
<span class="absolute right-0 bottom-0 block h-2 w-2 rounded-full bg-green-400 ring-2 ring-white dark:ring-gray-950">
</span>
</div>
</.link>
</li>
<% end %>
</ul>
</.link>
</li>
<% end %>
</ul>
<% end %>
</nav>
</div>

<div class="lg:pl-16">
<div
id="navbar"
phx-hook="NavBar"
class="sticky top-0 z-40 flex h-16 shrink-0 items-center justify-between lg:justify-end gap-x-6 border-b border-border bg-background px-4 shadow-sm sm:px-6 lg:px-8"
class="sticky top-0 z-40 flex h-16 shrink-0 items-center justify-between gap-x-6 border-b border-border bg-background px-4 shadow-sm sm:px-6 lg:px-8"
>
<!-- Mobile menu button -->
<div class="flex lg:hidden">
Expand Down Expand Up @@ -172,7 +176,20 @@
<.icon name="tabler-menu" class="size-6 text-white" />
</button>
</div>
<div class="flex items-center gap-x-6">
<%= if Map.get(assigns, :admin_page?) && Map.get(assigns, :selected_period) do %>
<ul role="list">
<.button
:for={period <- ["7d", "30d", "90d"]}
variant={if @selected_period == period, do: "default", else: "outline"}
phx-click="select_period"
phx-value-period={period}
class="w-[5rem] mx-auto text-base font-semibold"
>
{period}
</.button>
</ul>
<% end %>
<div class="ml-auto flex items-center gap-x-6">
<.link
class="group w-fit outline-none"
target="_blank"
Expand Down
2 changes: 1 addition & 1 deletion lib/algora_web/controllers/webhooks/stripe_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ defmodule AlgoraWeb.Webhooks.StripeController do
%{
color: 0xEF4444,
title: event.type,
# description: inspect(error),
description: inspect(error),
footer: %{
text: "Stripe",
icon_url: "https://github.com/stripe.png"
Expand Down
Loading