Skip to content

Commit d572bfc

Browse files
gxncanunom27
andauthored
feat: confirmation modal (#90)
--------- Co-authored-by: Nuno Miguel <nmpf.2005@gmail.com>
1 parent e5ff157 commit d572bfc

File tree

11 files changed

+365
-182
lines changed

11 files changed

+365
-182
lines changed

lib/ares_web/components/core_components.ex

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,77 @@ defmodule AresWeb.CoreComponents do
3232
alias Phoenix.HTML.Form
3333
alias Phoenix.LiveView.JS
3434

35+
@doc """
36+
Renders a modal.
37+
38+
## Examples
39+
40+
<.modal id="confirm-modal">
41+
This is a modal.
42+
</.modal>
43+
44+
JS commands may be passed to the `:on_cancel` to configure
45+
the closing/cancel event, for example:
46+
47+
<.modal id="confirm" on_cancel={JS.navigate(~p"/posts")}>
48+
This is another modal.
49+
</.modal>
50+
51+
"""
52+
attr :id, :string, required: true
53+
attr :show, :boolean, default: false
54+
attr :wrapper_class, :string, default: ""
55+
attr :on_cancel, JS, default: %JS{}
56+
slot :inner_block, required: true
57+
58+
def modal(assigns) do
59+
~H"""
60+
<div
61+
id={@id}
62+
phx-mounted={@show && show_modal(@id)}
63+
phx-remove={hide_modal(@id)}
64+
data-cancel={JS.exec(@on_cancel, "phx-remove")}
65+
class="relative z-50 hidden"
66+
>
67+
<div id={"#{@id}-bg"} class="bg-black/90 fixed inset-0 transition-opacity" aria-hidden="true" />
68+
<div
69+
class={"fixed inset-0 overflow-y-auto #{@wrapper_class}"}
70+
aria-labelledby={"#{@id}-title"}
71+
aria-describedby={"#{@id}-description"}
72+
role="dialog"
73+
aria-modal="true"
74+
tabindex="0"
75+
>
76+
<div class="flex min-h-full items-center justify-center m-4">
77+
<div class="w-full max-w-xl">
78+
<.focus_wrap
79+
id={"#{@id}-container"}
80+
phx-window-keydown={JS.exec("data-cancel", to: "##{@id}")}
81+
phx-key="escape"
82+
phx-click-away={JS.exec("data-cancel", to: "##{@id}")}
83+
class="p-6 bg-[#0A0A0A] border border-zinc-800 text-white shadow-2xl shadow-primary/10 relative rounded-2xl transition"
84+
>
85+
<div class="absolute top-6 right-5">
86+
<button
87+
phx-click={JS.exec("data-cancel", to: "##{@id}")}
88+
type="button"
89+
class="-m-3 flex-none p-3 opacity-20 text-white black:text-black cursor-pointer hover:opacity-40"
90+
aria-label={gettext("close")}
91+
>
92+
<.icon name="hero-x-mark-solid" class="h-5 w-5" />
93+
</button>
94+
</div>
95+
<div id={"#{@id}-content"}>
96+
{render_slot(@inner_block)}
97+
</div>
98+
</.focus_wrap>
99+
</div>
100+
</div>
101+
</div>
102+
</div>
103+
"""
104+
end
105+
35106
@doc """
36107
Renders flash notices.
37108
@@ -443,6 +514,30 @@ defmodule AresWeb.CoreComponents do
443514
)
444515
end
445516

517+
def show_modal(js \\ %JS{}, id) when is_binary(id) do
518+
js
519+
|> JS.show(to: "##{id}")
520+
|> JS.show(
521+
to: "##{id}-bg",
522+
transition: {"transition-all transform ease-out duration-300", "opacity-0", "opacity-100"}
523+
)
524+
|> show("##{id}-container")
525+
|> JS.add_class("overflow-hidden", to: "body")
526+
|> JS.focus_first(to: "##{id}-content")
527+
end
528+
529+
def hide_modal(js \\ %JS{}, id) do
530+
js
531+
|> JS.hide(
532+
to: "##{id}-bg",
533+
transition: {"transition-all transform ease-in duration-200", "opacity-100", "opacity-0"}
534+
)
535+
|> hide("##{id}-container")
536+
|> JS.hide(to: "##{id}", transition: {"block", "block", "hidden"})
537+
|> JS.remove_class("overflow-hidden", to: "body")
538+
|> JS.pop_focus()
539+
end
540+
446541
@doc """
447542
Translates an error message using gettext.
448543
"""

lib/ares_web/components/layouts/root.html.heex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="utf-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1" />
66
<meta name="csrf-token" content={get_csrf_token()} />
7-
<.live_title default="Ares" suffix="">
7+
<.live_title default="BugsByte" suffix="">
88
{assigns[:page_title]}
99
</.live_title>
1010
<link phx-track-static rel="stylesheet" href={~p"/assets/css/app.css"} />

lib/ares_web/components/navbar.ex

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,14 @@ defmodule AresWeb.Components.Navbar do
5555
Previous edition
5656
</.link>
5757
</li>
58-
<li>
58+
<%!-- <li>
5959
<.link
6060
class="hover:text-primary transition-colors"
6161
navigate="/app/team-formation"
6262
>
6363
Teams
6464
</.link>
65-
</li>
65+
</li> --%>
6666
<%= if @user && @user.is_admin do %>
6767
<li>
6868
<.link
@@ -94,19 +94,25 @@ defmodule AresWeb.Components.Navbar do
9494
>
9595
View Profile
9696
</.link>
97+
<.link
98+
navigate="/users/settings"
99+
class="block px-4 py-2 text-black hover:bg-gray-300 rounded-t-lg transition-colors"
100+
>
101+
Settings
102+
</.link>
97103
<.link href="/users/log-out" method="delete" class="border-t border-gray-700">
98104
<p class="w-full text-left px-4 py-2 text-black hover:bg-gray-300 rounded-b-lg transition-colors cursor-pointer">
99105
Log out
100106
</p>
101107
</.link>
102108
</div>
103109
<% else %>
104-
<.link
110+
<%!-- <.link
105111
navigate="/register"
106112
class="rounded-full px-3 py-2 text-sm font-semibold text-white shadow-sm ring-1 ring-inset ring-white hover:ring-primary hover:text-primary transition-all"
107113
>
108114
Register
109-
</.link>
115+
</.link> --%>
110116
<% end %>
111117
</li>
112118
</ul>
@@ -177,12 +183,12 @@ defmodule AresWeb.Components.Navbar do
177183
Profile
178184
</.link>
179185
<% else %>
180-
<a
186+
<%!-- <.link
181187
class="block py-3 sm:py-4 text-center text-lg sm:text-xl hover:text-primary transition-colors"
182188
href="/register"
183189
>
184190
Register
185-
</a>
191+
</.link> --%>
186192
<% end %>
187193
</li>
188194
<%= if @user do %>
@@ -196,6 +202,14 @@ defmodule AresWeb.Components.Navbar do
196202
</.link>
197203
</li>
198204
<% end %>
205+
<li>
206+
<.link
207+
navigate="/users/settings"
208+
class="block w-full py-3 sm:py-4 text-center text-lg sm:text-xl hover:text-primary transition-colors"
209+
>
210+
Settings
211+
</.link>
212+
</li>
199213
<li>
200214
<.link
201215
href="/users/log-out"
@@ -238,14 +252,14 @@ defmodule AresWeb.Components.Navbar do
238252
Previous edition
239253
</.link>
240254
</li>
241-
<li>
255+
<%!-- <li>
242256
<.link
243257
class="block py-3 sm:py-4 text-center text-lg sm:text-xl hover:text-primary transition-colors"
244258
navigate="/app/team-formation"
245259
>
246260
Team formation
247261
</.link>
248-
</li>
262+
</li> --%>
249263
</ul>
250264
</nav>
251265
</div>

lib/ares_web/live/app/team-formation.ex

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,9 @@ defmodule AresWeb.AppLive.TeamFormation do
186186
187187
<div class="flex items-center font-inter">
188188
<.button
189-
phx-click="join-team"
189+
phx-click="open-join-modal"
190190
class="btn btn-primary flex items-center"
191191
phx-value-team_code={team.code}
192-
data-confirm={"Are you sure you want to join #{team.name}?"}
193192
>
194193
<.icon name="hero-user-plus" class="w-5 h-5 mr-2" /> Join
195194
</.button>
@@ -276,6 +275,42 @@ defmodule AresWeb.AppLive.TeamFormation do
276275
</div>
277276
</div>
278277
</div>
278+
279+
<.modal
280+
:if={@live_action == :join}
281+
id="join-team-modal"
282+
show
283+
on_cancel={JS.patch(~p"/app/team-formation?#{[tab: @tab]}")}
284+
>
285+
<div class="space-y-8 flex flex-col items-center">
286+
<div class="p-4 rounded-full border-2 border-primary">
287+
<span class="hero-users text-primary size-6" />
288+
</div>
289+
<div class="space-y-2 text-center">
290+
<h2 class="text-2xl font-resegrg">Join Team?</h2>
291+
<p class="text-xl">
292+
You are about to join <span class="text-primary font-bold">{@selected_team.name}</span>. Confirm that this is the team you want to participate with.
293+
</p>
294+
</div>
295+
<div class="flex flex-col gap-4 sm:flex-row w-full">
296+
<button
297+
type="button"
298+
phx-click="join-team"
299+
phx-value-team_code={@selected_team.code}
300+
class="cursor-pointer bg-primary w-full sm:w-1/2 text-white py-2 px-6 rounded-lg hover:bg-primary/50 transition-colors"
301+
>
302+
Join Team
303+
</button>
304+
<button
305+
type="button"
306+
phx-click={JS.patch(~p"/app/team-formation?#{[tab: @tab]}")}
307+
class="cursor-pointer bg-gray-600 w-full sm:w-1/2 text-white py-2 px-6 rounded-lg hover:bg-gray-500 transition-colors"
308+
>
309+
Cancel
310+
</button>
311+
</div>
312+
</div>
313+
</.modal>
279314
</Layouts.app>
280315
"""
281316
end
@@ -314,6 +349,25 @@ defmodule AresWeb.AppLive.TeamFormation do
314349
|> assign_form(Teams.change_team(%Teams.Team{}, %{}))}
315350
end
316351

352+
@impl true
353+
def handle_params(params, _url, socket) do
354+
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
355+
end
356+
357+
defp apply_action(socket, :index, params) do
358+
tab = Map.get(params, "tab", "create")
359+
360+
socket
361+
|> assign(:tab, tab)
362+
end
363+
364+
defp apply_action(socket, :join, params) do
365+
tab = Map.get(params, "tab", "join")
366+
367+
socket
368+
|> assign(:tab, tab)
369+
end
370+
317371
@impl true
318372
def handle_event("save", %{"team" => team_params}, socket) do
319373
case Teams.create_and_join_team(socket.assigns.user, team_params) do
@@ -353,6 +407,16 @@ defmodule AresWeb.AppLive.TeamFormation do
353407
end
354408
end
355409

410+
@impl true
411+
def handle_event("open-join-modal", %{"team_code" => team_code}, socket) do
412+
selected_team = Enum.find(socket.assigns.available_teams, &(&1.code == team_code))
413+
414+
{:noreply,
415+
socket
416+
|> assign(:selected_team, selected_team)
417+
|> push_patch(to: ~p"/app/team-formation/join?#{[tab: socket.assigns.tab]}")}
418+
end
419+
356420
@impl true
357421
def handle_event("join-team", %{"team_code" => team_code}, socket) do
358422
case Teams.add_user_to_team_by_code(socket.assigns.user, team_code) do

lib/ares_web/live/auth/login.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ defmodule AresWeb.UserLive.Login do
1717
<% else %>
1818
<p class="text-2xl">
1919
Don't have an account? <.link
20-
navigate={~p"/register"}
20+
navigate="/register"
2121
class="font-semibold text-primary hover:underline"
2222
phx-no-format
2323
>Register</.link> to participate now.

0 commit comments

Comments
 (0)