Skip to content

Commit 1d19562

Browse files
committed
feat: add repository navigation and enhance BountyLive functionality
- Introduced a new route for repository-specific live sessions in the router. - Added a RepoNav component for improved navigation within repository contexts. - Enhanced BountyLive to support dynamic loading of bounties based on repository owner and name. - Updated ticket reference handling to streamline data assignment in BountyLive. - Refactored the mount function in BountyLive to incorporate repository parameters for better context management.
1 parent 3f7ea04 commit 1d19562

File tree

3 files changed

+183
-46
lines changed

3 files changed

+183
-46
lines changed

lib/algora_web/live/bounty_live.ex

Lines changed: 66 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ defmodule AlgoraWeb.BountyLive do
33
use AlgoraWeb, :live_view
44

55
import Ecto.Changeset
6+
import Ecto.Query
67

78
alias Algora.Accounts
89
alias Algora.Admin
@@ -65,13 +66,49 @@ defmodule AlgoraWeb.BountyLive do
6566
bounty =
6667
Bounty
6768
|> Repo.get!(bounty_id)
68-
|> Repo.preload([
69-
:owner,
70-
:creator,
71-
:transactions,
72-
ticket: [repository: [:user]]
73-
])
69+
|> Repo.preload([:owner, :creator, :transactions, ticket: [repository: [:user]]])
7470

71+
ticket_ref = %{
72+
owner: bounty.ticket.repository.user.provider_login,
73+
repo: bounty.ticket.repository.name,
74+
number: bounty.ticket.number
75+
}
76+
77+
socket
78+
|> assign(:bounty, bounty)
79+
|> assign(:ticket_ref, ticket_ref)
80+
|> on_mount(bounty)
81+
end
82+
83+
@impl true
84+
def mount(%{"repo_owner" => repo_owner, "repo_name" => repo_name, "number" => number}, _session, socket) do
85+
number = String.to_integer(number)
86+
87+
ticket_ref = %{owner: repo_owner, repo: repo_name, number: number}
88+
89+
bounty =
90+
from(b in Bounty,
91+
join: t in assoc(b, :ticket),
92+
join: r in assoc(t, :repository),
93+
join: u in assoc(r, :user),
94+
where: u.provider == "github",
95+
where: u.provider_login == ^repo_owner,
96+
where: r.name == ^repo_name,
97+
where: t.number == ^number,
98+
# TODO: pool bounties
99+
limit: 1,
100+
order_by: [asc: b.inserted_at]
101+
)
102+
|> Repo.one()
103+
|> Repo.preload([:owner, :creator, :transactions, ticket: [repository: [:user]]])
104+
105+
socket
106+
|> assign(:bounty, bounty)
107+
|> assign(:ticket_ref, ticket_ref)
108+
|> on_mount(bounty)
109+
end
110+
111+
defp on_mount(socket, bounty) do
75112
debits = Enum.filter(bounty.transactions, &(&1.type == :debit and &1.status == :succeeded))
76113

77114
total_paid =
@@ -81,8 +118,6 @@ defmodule AlgoraWeb.BountyLive do
81118

82119
ticket_body_html = Algora.Markdown.render(bounty.ticket.description)
83120

84-
contexts = contexts(bounty)
85-
86121
reward_changeset =
87122
RewardBountyForm.changeset(%RewardBountyForm{}, %{
88123
tip_percentage: 0,
@@ -102,11 +137,9 @@ defmodule AlgoraWeb.BountyLive do
102137
{:ok,
103138
socket
104139
|> assign(:page_title, bounty.ticket.title)
105-
|> assign(:bounty, bounty)
106140
|> assign(:ticket, bounty.ticket)
107141
|> assign(:total_paid, total_paid)
108142
|> assign(:ticket_body_html, ticket_body_html)
109-
|> assign(:contexts, contexts)
110143
|> assign(:show_reward_modal, false)
111144
|> assign(:show_exclusive_modal, false)
112145
|> assign(:selected_context, nil)
@@ -126,11 +159,6 @@ defmodule AlgoraWeb.BountyLive do
126159
{:noreply, socket}
127160
end
128161

129-
# @impl true
130-
# def handle_params(%{"context" => context_id}, _url, socket) do
131-
# {:noreply, socket |> assign_selected_context(context_id) |> assign_line_items(nil)}
132-
# end
133-
134162
@impl true
135163
def handle_params(_params, _url, socket) do
136164
{:noreply, socket}
@@ -164,7 +192,7 @@ defmodule AlgoraWeb.BountyLive do
164192

165193
{:noreply,
166194
socket
167-
|> update(:messages, &(&1 ++ [message]))
195+
|> Phoenix.Component.update(:messages, &(&1 ++ [message]))
168196
|> push_event("clear-input", %{selector: "#message-input"})}
169197
end
170198

@@ -367,22 +395,38 @@ defmodule AlgoraWeb.BountyLive do
367395
<.social_share_button
368396
id="twitter-share-url"
369397
icon="tabler-brand-x"
370-
value={url(~p"/org/#{@bounty.owner.handle}/bounties/#{@bounty.id}")}
398+
value={
399+
url(
400+
~p"/#{@ticket_ref.owner}/#{@ticket_ref.repo}/issues/#{@ticket_ref.number}"
401+
)
402+
}
371403
/>
372404
<.social_share_button
373405
id="reddit-share-url"
374406
icon="tabler-brand-reddit"
375-
value={url(~p"/org/#{@bounty.owner.handle}/bounties/#{@bounty.id}")}
407+
value={
408+
url(
409+
~p"/#{@ticket_ref.owner}/#{@ticket_ref.repo}/issues/#{@ticket_ref.number}"
410+
)
411+
}
376412
/>
377413
<.social_share_button
378414
id="linkedin-share-url"
379415
icon="tabler-brand-linkedin"
380-
value={url(~p"/org/#{@bounty.owner.handle}/bounties/#{@bounty.id}")}
416+
value={
417+
url(
418+
~p"/#{@ticket_ref.owner}/#{@ticket_ref.repo}/issues/#{@ticket_ref.number}"
419+
)
420+
}
381421
/>
382422
<.social_share_button
383423
id="hackernews-share-url"
384424
icon="tabler-brand-ycombinator"
385-
value={url(~p"/org/#{@bounty.owner.handle}/bounties/#{@bounty.id}")}
425+
value={
426+
url(
427+
~p"/#{@ticket_ref.owner}/#{@ticket_ref.repo}/issues/#{@ticket_ref.number}"
428+
)
429+
}
386430
/>
387431
</div>
388432
</div>
@@ -635,16 +679,6 @@ defmodule AlgoraWeb.BountyLive do
635679
"""
636680
end
637681

638-
# defp assign_selected_context(socket, context_id) do
639-
# case Enum.find(socket.assigns.contexts, &(&1.id == context_id)) do
640-
# nil ->
641-
# socket
642-
643-
# context ->
644-
# assign(socket, :selected_context, context)
645-
# end
646-
# end
647-
648682
defp assign_recipient(socket, github_handle) do
649683
case Workspace.ensure_user(Admin.token!(), github_handle) do
650684
{:ok, recipient} ->
@@ -658,7 +692,7 @@ defmodule AlgoraWeb.BountyLive do
658692
defp assign_line_items(socket) do
659693
amount = calculate_final_amount(socket.assigns.reward_form.source)
660694
recipient = socket.assigns.recipient
661-
ticket_ref = ticket_ref(socket)
695+
ticket_ref = socket.assigns.ticket_ref
662696

663697
line_items =
664698
if recipient do
@@ -685,20 +719,12 @@ defmodule AlgoraWeb.BountyLive do
685719
assign(socket, :line_items, line_items)
686720
end
687721

688-
defp ticket_ref(socket) do
689-
%{
690-
owner: socket.assigns.ticket.repository.user.provider_login,
691-
repo: socket.assigns.ticket.repository.name,
692-
number: socket.assigns.ticket.number
693-
}
694-
end
695-
696722
defp reward_bounty(socket, bounty, changeset) do
697723
final_amount = calculate_final_amount(changeset)
698724

699725
Bounties.reward_bounty(
700726
%{owner: bounty.owner, amount: final_amount, bounty_id: bounty.id, claims: []},
701-
ticket_ref: ticket_ref(socket),
727+
ticket_ref: socket.assigns.ticket_ref,
702728
recipient: socket.assigns.recipient
703729
)
704730
end
@@ -745,10 +771,6 @@ defmodule AlgoraWeb.BountyLive do
745771
"""
746772
end
747773

748-
defp contexts(_bounty) do
749-
Accounts.list_featured_developers()
750-
end
751-
752774
defp close_drawers(socket) do
753775
socket
754776
|> assign(:show_reward_modal, false)
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
defmodule AlgoraWeb.Org.RepoNav do
2+
@moduledoc false
3+
use Phoenix.Component
4+
5+
import Phoenix.LiveView
6+
7+
alias Algora.Organizations
8+
alias AlgoraWeb.OrgAuth
9+
10+
def on_mount(:default, %{"repo_owner" => repo_owner} = params, _session, socket) do
11+
current_user = socket.assigns[:current_user]
12+
current_org = Organizations.get_org_by(provider_login: repo_owner, provider: "github")
13+
current_user_role = OrgAuth.get_user_role(current_user, current_org)
14+
15+
{:cont,
16+
socket
17+
|> assign(:screenshot?, not is_nil(params["screenshot"]))
18+
|> assign(:new_bounty_form, to_form(%{"github_issue_url" => "", "amount" => ""}))
19+
|> assign(:current_org, current_org)
20+
|> assign(:current_user_role, current_user_role)
21+
|> assign(:nav, nav_items(current_org.handle, current_user_role))
22+
|> assign(:contacts, [])
23+
|> attach_hook(:active_tab, :handle_params, &handle_active_tab_params/3)}
24+
end
25+
26+
defp handle_active_tab_params(_params, _url, socket) do
27+
active_tab =
28+
case {socket.view, socket.assigns.live_action} do
29+
{AlgoraWeb.Org.DashboardLive, _} -> :dashboard
30+
{AlgoraWeb.Org.HomeLive, _} -> :home
31+
{AlgoraWeb.Org.BountiesLive, _} -> :bounties
32+
{AlgoraWeb.Org.ProjectsLive, _} -> :projects
33+
{AlgoraWeb.Project.ViewLive, _} -> :projects
34+
{AlgoraWeb.Org.SettingsLive, _} -> :settings
35+
{AlgoraWeb.Org.MembersLive, _} -> :members
36+
{_, _} -> nil
37+
end
38+
39+
{:cont, assign(socket, :active_tab, active_tab)}
40+
end
41+
42+
def nav_items(org_handle, current_user_role) do
43+
[
44+
%{
45+
title: "Overview",
46+
items: build_nav_items(org_handle, current_user_role)
47+
}
48+
]
49+
end
50+
51+
defp build_nav_items(org_handle, current_user_role) do
52+
Enum.filter(
53+
[
54+
%{
55+
href: "/org/#{org_handle}",
56+
tab: :dashboard,
57+
icon: "tabler-sparkles",
58+
label: "Dashboard",
59+
roles: [:admin, :mod]
60+
},
61+
%{
62+
href: "/org/#{org_handle}/home",
63+
tab: :home,
64+
icon: "tabler-home",
65+
label: "Home",
66+
roles: [:admin, :mod, :expert, :none]
67+
},
68+
%{
69+
href: "/org/#{org_handle}/bounties",
70+
tab: :bounties,
71+
icon: "tabler-diamond",
72+
label: "Bounties",
73+
roles: [:admin, :mod, :expert, :none]
74+
},
75+
%{
76+
href: "/org/#{org_handle}/leaderboard",
77+
tab: :leaderboard,
78+
icon: "tabler-trophy",
79+
label: "Leaderboard",
80+
roles: [:admin, :mod, :expert, :none]
81+
},
82+
%{
83+
href: "/org/#{org_handle}/team",
84+
tab: :team,
85+
icon: "tabler-users",
86+
label: "Team",
87+
roles: [:admin, :mod, :expert, :none]
88+
},
89+
%{
90+
href: "/org/#{org_handle}/transactions",
91+
tab: :transactions,
92+
icon: "tabler-credit-card",
93+
label: "Transactions",
94+
roles: [:admin]
95+
},
96+
%{
97+
href: "/org/#{org_handle}/settings",
98+
tab: :settings,
99+
icon: "tabler-settings",
100+
label: "Settings",
101+
roles: [:admin]
102+
}
103+
],
104+
fn item -> current_user_role in item[:roles] end
105+
)
106+
end
107+
end

lib/algora_web/router.ex

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,26 @@ defmodule AlgoraWeb.Router do
8888
end
8989
end
9090

91+
scope "/:repo_owner/:repo_name" do
92+
live_session :repo,
93+
layout: {AlgoraWeb.Layouts, :user},
94+
on_mount: [{AlgoraWeb.UserAuth, :current_user}, AlgoraWeb.Org.RepoNav] do
95+
live "/issues/:number", BountyLive
96+
live "/pull/:number", BountyLive
97+
end
98+
end
99+
91100
scope "/org/:org_handle" do
92101
live_session :org,
93102
layout: {AlgoraWeb.Layouts, :user},
94103
on_mount: [{AlgoraWeb.UserAuth, :current_user}, AlgoraWeb.Org.Nav] do
95104
live "/", Org.DashboardLive, :index
96105
live "/home", Org.HomeLive, :index
97106
live "/bounties", Org.BountiesLive, :index
107+
live "/bounties/:id", BountyLive, :index
98108
live "/contracts/:id", Contract.ViewLive
99109
live "/team", Org.TeamLive, :index
100110
live "/leaderboard", Org.LeaderboardLive, :index
101-
# TODO: allow access to invited users
102-
live "/bounties/:id", BountyLive
103111
end
104112

105113
live_session :org_admin,

0 commit comments

Comments
 (0)