this is a really good first commit

This commit is contained in:
2023-01-18 16:13:51 +01:00
parent 6bc40e339a
commit be71f04838
117 changed files with 2972 additions and 3100 deletions

View File

@ -1,31 +0,0 @@
defmodule SomethingErlangWeb.BookmarksLive.Show do
use SomethingErlangWeb, :live_view
on_mount SomethingErlangWeb.UserLiveAuth
alias SomethingErlang.Grover
require Logger
@impl true
def mount(_params, _session, socket) do
Grover.mount(socket.assigns.current_user)
{:ok, socket}
end
@impl true
def handle_params(%{"page" => page}, _, socket) do
bookmarks = Grover.get_bookmarks!(page |> String.to_integer())
{:noreply,
socket
|> assign(:page_title, "bookmarks")
|> assign(:bookmarks, bookmarks)}
end
@impl true
def handle_params(_, _, socket) do
{:noreply,
push_redirect(socket,
to: Routes.bookmarks_show_path(socket, :show, page: 1)
)}
end
end

View File

@ -1,16 +0,0 @@
<table class="table w-full">
<thead>
<tr>
<th></th>
<th>Title</th>
</tr>
</thead>
<tbody>
<%= for thread <- @bookmarks do %>
<tr>
<th><%= raw thread.icon %></th>
<td><%= raw thread.title %></td>
</tr>
<% end %>
</tbody>
</table>

View File

@ -1,60 +0,0 @@
defmodule SomethingErlangWeb.LiveHelpers do
import Phoenix.LiveView
import Phoenix.LiveView.Helpers
alias Phoenix.LiveView.JS
@doc """
Renders a live component inside a modal.
The rendered modal receives a `:return_to` option to properly update
the URL when the modal is closed.
## Examples
<.modal return_to={Routes.thread_index_path(@socket, :index)}>
<.live_component
module={SomethingErlangWeb.ThreadLive.FormComponent}
id={@thread.id || :new}
title={@page_title}
action={@live_action}
return_to={Routes.thread_index_path(@socket, :index)}
thread: @thread
/>
</.modal>
"""
def modal(assigns) do
assigns = assign_new(assigns, :return_to, fn -> nil end)
~H"""
<div id="modal" class="phx-modal fade-in" phx-remove={hide_modal()}>
<div
id="modal-content"
class="phx-modal-content fade-in-scale"
phx-click-away={JS.dispatch("click", to: "#close")}
phx-window-keydown={JS.dispatch("click", to: "#close")}
phx-key="escape"
>
<%= if @return_to do %>
<%= live_patch "✖",
to: @return_to,
id: "close",
class: "phx-modal-close",
phx_click: hide_modal()
%>
<% else %>
<a id="close" href="#" class="phx-modal-close" phx-click={hide_modal()}>✖</a>
<% end %>
<%= render_slot(@inner_block) %>
</div>
</div>
"""
end
defp hide_modal(js \\ %JS{}) do
js
|> JS.hide(to: "#modal", transition: "fade-out")
|> JS.hide(to: "#modal-content", transition: "fade-out-scale")
end
end

View File

@ -1,43 +1,25 @@
defmodule SomethingErlangWeb.ThreadLive.Show do
defmodule SomethingErlangWeb.ThreadLive do
use SomethingErlangWeb, :live_view
on_mount SomethingErlangWeb.UserLiveAuth
alias SomethingErlang.Grover
require Logger
@impl true
def mount(_params, _session, socket) do
Grover.mount(socket.assigns.current_user)
{:ok, socket}
end
@impl true
def handle_params(%{"id" => id, "page" => page}, _, socket) do
thread = Grover.get_thread!(id, page |> String.to_integer())
{:noreply,
socket
|> assign(:page_title, thread.title)
|> assign(:thread, thread)}
end
@impl true
def handle_params(%{"id" => id}, _, socket) do
{:noreply,
push_redirect(socket,
to: Routes.thread_show_path(socket, :show, id, page: 1)
)}
def render(assigns) do
~H"""
<h1>Threads!</h1>
<pre class="whitespace-pre-wrap break-all">
<%= inspect(@current_user) %>
</pre>
"""
end
def post(assigns) do
~H"""
<div class="post">
<.user info={@author} />
<article class="postbody">
<%= raw @article %>
</article>
<.toolbar date={@date} />
<.user info={@author} />
<article class="postbody">
<%= raw(@article) %>
</article>
<.toolbar date={@date} />
</div>
"""
end
@ -45,10 +27,10 @@ defmodule SomethingErlangWeb.ThreadLive.Show do
def user(assigns) do
~H"""
<aside class="userinfo bg-base-100">
<h3 class="mb-4"><%= @info.name %></h3>
<div class="title hidden sm:flex flex-col text-sm pr-4">
<%= raw @info.title %>
</div>
<h3 class="mb-4"><%= @info.name %></h3>
<div class="title hidden sm:flex flex-col text-sm pr-4">
<%= raw(@info.title) %>
</div>
</aside>
"""
end
@ -56,7 +38,8 @@ defmodule SomethingErlangWeb.ThreadLive.Show do
def toolbar(assigns) do
~H"""
<div class="sm:col-span-2 text-sm p-2 px-4">
<%= @date |> Calendar.strftime("%A, %b %d %Y @ %H:%M") %></div>
<%= @date |> Calendar.strftime("%A, %b %d %Y @ %H:%M") %>
</div>
"""
end
@ -80,22 +63,49 @@ defmodule SomethingErlangWeb.ThreadLive.Show do
~H"""
<div class="navbar my-4 bg-base-200">
<div class="flex-1"></div>
<div class="pagination flex-none btn-group grid grid-cols-5">
<%= for btn <- buttons do %>
<%= live_redirect class: "btn btn-sm btn-ghost" <> btn.special,
to: Routes.thread_show_path(@socket, :show, @thread.id, page: btn.page) do %>
<%= case btn.label do %>
<% "«" -> %><Icons.chevron_left_double /><%= btn.page %>
<% "" -> %><Icons.chevron_left /><%= btn.page %>
<% "" -> %><%= btn.page %><Icons.chevron_right />
<% "»" -> %><%= btn.page %><Icons.chevron_right_double />
<% _ -> %><%= btn.page %>
<% end %>
<% end %>
<div class="flex-1"></div>
<div class="pagination flex-none btn-group grid grid-cols-5">
<%= for btn <- buttons do %>
<%= live_redirect class: "btn btn-sm btn-ghost" <> btn.special,
to: ~p"/thread/#{@thread.id}?page=#{btn.page}" do %>
<%= case btn.label do %>
<% "«" -> %>
<Icons.chevron_left_double /><%= btn.page %>
<% "" -> %>
<Icons.chevron_left /><%= btn.page %>
<% "" -> %>
<%= btn.page %><Icons.chevron_right />
<% "»" -> %>
<%= btn.page %><Icons.chevron_right_double />
<% _ -> %>
<%= btn.page %>
<% end %>
</div>
<% end %>
<% end %>
</div>
</div>
"""
end
def mount(_params, _session, socket) do
{:ok, socket}
end
def handle_params(%{"id" => id, "page" => page}, _, socket) do
thread = Grover.get_thread!(id, page |> String.to_integer())
{:noreply,
socket
|> assign(:page_title, thread.title)
|> assign(:thread, thread)}
end
def handle_params(%{"id" => id}, _, socket) do
params = %{page: 1}
{:noreply, push_redirect(socket, to: ~p"/thread/#{id}?#{params}")}
end
def handle_params(%{}, _, socket) do
{:noreply, socket}
end
end

View File

@ -1,55 +0,0 @@
defmodule SomethingErlangWeb.ThreadLive.FormComponent do
use SomethingErlangWeb, :live_component
alias SomethingErlang.Forums
@impl true
def update(%{thread: thread} = assigns, socket) do
changeset = Forums.change_thread(thread)
{:ok,
socket
|> assign(assigns)
|> assign(:changeset, changeset)}
end
@impl true
def handle_event("validate", %{"thread" => thread_params}, socket) do
changeset =
socket.assigns.thread
|> Forums.change_thread(thread_params)
|> Map.put(:action, :validate)
{:noreply, assign(socket, :changeset, changeset)}
end
def handle_event("save", %{"thread" => thread_params}, socket) do
save_thread(socket, socket.assigns.action, thread_params)
end
defp save_thread(socket, :edit, thread_params) do
case Forums.update_thread(socket.assigns.thread, thread_params) do
{:ok, _thread} ->
{:noreply,
socket
|> put_flash(:info, "Thread updated successfully")
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :changeset, changeset)}
end
end
defp save_thread(socket, :new, thread_params) do
case Forums.create_thread(thread_params) do
{:ok, _thread} ->
{:noreply,
socket
|> put_flash(:info, "Thread created successfully")
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, changeset: changeset)}
end
end
end

View File

@ -1,24 +0,0 @@
<div>
<h2><%= @title %></h2>
<.form
let={f}
for={@changeset}
id="thread-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save">
<%= label f, :title %>
<%= text_input f, :title %>
<%= error_tag f, :title %>
<%= label f, :thread_id %>
<%= number_input f, :thread_id %>
<%= error_tag f, :thread_id %>
<div>
<%= submit "Save", phx_disable_with: "Saving..." %>
</div>
</.form>
</div>

View File

@ -1,46 +0,0 @@
defmodule SomethingErlangWeb.ThreadLive.Index do
use SomethingErlangWeb, :live_view
alias SomethingErlang.Forums
alias SomethingErlang.Forums.Thread
@impl true
def mount(_params, _session, socket) do
{:ok, assign(socket, :threads, list_threads())}
end
@impl true
def handle_params(params, _url, socket) do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
defp apply_action(socket, :edit, %{"id" => id}) do
socket
|> assign(:page_title, "Edit Thread")
|> assign(:thread, Forums.get_thread!(id))
end
defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, "New Thread")
|> assign(:thread, %Thread{})
end
defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, "Listing Threads")
|> assign(:thread, nil)
end
@impl true
def handle_event("delete", %{"id" => id}, socket) do
thread = Forums.get_thread!(id)
{:ok, _} = Forums.delete_thread(thread)
{:noreply, assign(socket, :threads, list_threads())}
end
defp list_threads do
Forums.list_threads()
end
end

View File

@ -1,41 +0,0 @@
<h1>Listing Threads</h1>
<%= if @live_action in [:new, :edit] do %>
<.modal return_to={Routes.thread_index_path(@socket, :index)}>
<.live_component
module={SomethingErlangWeb.ThreadLive.FormComponent}
id={@thread.id || :new}
title={@page_title}
action={@live_action}
thread={@thread}
return_to={Routes.thread_index_path(@socket, :index)}
/>
</.modal>
<% end %>
<table>
<thead>
<tr>
<th>Title</th>
<th>Thread</th>
<th></th>
</tr>
</thead>
<tbody id="threads">
<%= for thread <- @threads do %>
<tr id={"thread-#{thread.id}"}>
<td><%= thread.title %></td>
<td><%= thread.thread_id %></td>
<td>
<span><%= live_redirect "Show", to: Routes.thread_show_path(@socket, :show, thread) %></span>
<span><%= live_patch "Edit", to: Routes.thread_index_path(@socket, :edit, thread) %></span>
<span><%= link "Delete", to: "#", phx_click: "delete", phx_value_id: thread.id, data: [confirm: "Are you sure?"] %></span>
</td>
</tr>
<% end %>
</tbody>
</table>
<span><%= live_patch "New Thread", to: Routes.thread_index_path(@socket, :new) %></span>

View File

@ -1,26 +0,0 @@
<%= if @live_action in [:edit] do %>
<.modal return_to={Routes.thread_show_path(@socket, :show, @thread)}>
<.live_component
module={SomethingErlangWeb.ThreadLive.FormComponent}
id={@thread.id}
title={@page_title}
action={@live_action}
thread={@thread}
return_to={Routes.thread_show_path(@socket, :show, @thread)}
/>
</.modal>
<% end %>
<h2>
<%= raw @thread.title %>
</h2>
<div class="thread my-8">
<.pagination socket={@socket} thread={@thread} />
<%= for post <- @thread.posts do %>
<.post author={post.userinfo} article={post.postbody} date={post.postdate} />
<% end %>
<.pagination socket={@socket} thread={@thread} />
</div>

View File

@ -0,0 +1,45 @@
defmodule SomethingErlangWeb.UserConfirmationInstructionsLive do
use SomethingErlangWeb, :live_view
alias SomethingErlang.Accounts
def render(assigns) do
~H"""
<.header>Resend confirmation instructions</.header>
<.simple_form :let={f} for={:user} id="resend_confirmation_form" phx-submit="send_instructions">
<.input field={{f, :email}} type="email" label="Email" required />
<:actions>
<.button phx-disable-with="Sending...">Resend confirmation instructions</.button>
</:actions>
</.simple_form>
<p>
<.link href={~p"/users/register"}>Register</.link>
|
<.link href={~p"/users/log_in"}>Log in</.link>
</p>
"""
end
def mount(_params, _session, socket) do
{:ok, socket}
end
def handle_event("send_instructions", %{"user" => %{"email" => email}}, socket) do
if user = Accounts.get_user_by_email(email) do
Accounts.deliver_user_confirmation_instructions(
user,
&url(~p"/users/confirm/#{&1}")
)
end
info =
"If your email is in our system and it has not been confirmed yet, you will receive an email with instructions shortly."
{:noreply,
socket
|> put_flash(:info, info)
|> redirect(to: ~p"/")}
end
end

View File

@ -0,0 +1,58 @@
defmodule SomethingErlangWeb.UserConfirmationLive do
use SomethingErlangWeb, :live_view
alias SomethingErlang.Accounts
def render(%{live_action: :edit} = assigns) do
~H"""
<div class="mx-auto max-w-sm">
<.header class="text-center">Confirm Account</.header>
<.simple_form :let={f} for={:user} id="confirmation_form" phx-submit="confirm_account">
<.input field={{f, :token}} type="hidden" value={@token} />
<:actions>
<.button phx-disable-with="Confirming..." class="w-full">Confirm my account</.button>
</:actions>
</.simple_form>
<p class="text-center mt-4">
<.link href={~p"/users/register"}>Register</.link>
|
<.link href={~p"/users/log_in"}>Log in</.link>
</p>
</div>
"""
end
def mount(params, _session, socket) do
{:ok, assign(socket, token: params["token"]), temporary_assigns: [token: nil]}
end
# Do not log in the user after confirmation to avoid a
# leaked token giving the user access to the account.
def handle_event("confirm_account", %{"user" => %{"token" => token}}, socket) do
case Accounts.confirm_user(token) do
{:ok, _} ->
{:noreply,
socket
|> put_flash(:info, "User confirmed successfully.")
|> redirect(to: ~p"/")}
:error ->
# If there is a current user and the account was already confirmed,
# then odds are that the confirmation link was already visited, either
# by some automation or by the user themselves, so we redirect without
# a warning message.
case socket.assigns do
%{current_user: %{confirmed_at: confirmed_at}} when not is_nil(confirmed_at) ->
{:noreply, redirect(socket, to: ~p"/")}
%{} ->
{:noreply,
socket
|> put_flash(:error, "User confirmation link is invalid or it has expired.")
|> redirect(to: ~p"/")}
end
end
end
end

View File

@ -0,0 +1,51 @@
defmodule SomethingErlangWeb.UserForgotPasswordLive do
use SomethingErlangWeb, :live_view
alias SomethingErlang.Accounts
def render(assigns) do
~H"""
<div class="mx-auto max-w-sm">
<.header class="text-center">
Forgot your password?
<:subtitle>We'll send a password reset link to your inbox</:subtitle>
</.header>
<.simple_form :let={f} id="reset_password_form" for={:user} phx-submit="send_email">
<.input field={{f, :email}} type="email" placeholder="Email" required />
<:actions>
<.button phx-disable-with="Sending..." class="w-full">
Send password reset instructions
</.button>
</:actions>
</.simple_form>
<p class="text-center mt-4">
<.link href={~p"/users/register"}>Register</.link>
|
<.link href={~p"/users/log_in"}>Log in</.link>
</p>
</div>
"""
end
def mount(_params, _session, socket) do
{:ok, socket}
end
def handle_event("send_email", %{"user" => %{"email" => email}}, socket) do
if user = Accounts.get_user_by_email(email) do
Accounts.deliver_user_reset_password_instructions(
user,
&url(~p"/users/reset_password/#{&1}")
)
end
info =
"If your email is in our system, you will receive instructions to reset your password shortly."
{:noreply,
socket
|> put_flash(:info, info)
|> redirect(to: ~p"/")}
end
end

View File

@ -1,16 +0,0 @@
defmodule SomethingErlangWeb.UserLiveAuth do
import Phoenix.LiveView
alias SomethingErlang.Accounts
def on_mount(:default, _params, %{"user_token" => user_token} = _session, socket) do
user = Accounts.get_user_by_session_token(user_token)
socket = assign_new(socket, :current_user, fn -> user end)
if socket.assigns.current_user.confirmed_at do
{:cont, socket}
else
{:halt, redirect(socket, to: "/login")}
end
end
end

View File

@ -0,0 +1,49 @@
defmodule SomethingErlangWeb.UserLoginLive do
use SomethingErlangWeb, :live_view
def render(assigns) do
~H"""
<div class="mx-auto max-w-sm">
<.header class="text-center">
Sign in to account
<:subtitle>
Don't have an account?
<.link navigate={~p"/users/register"} class="font-semibold text-brand hover:underline">
Sign up
</.link>
for an account now.
</:subtitle>
</.header>
<.simple_form
:let={f}
id="login_form"
for={:user}
action={~p"/users/log_in"}
as={:user}
phx-update="ignore"
>
<.input field={{f, :email}} type="email" label="Email" required />
<.input field={{f, :password}} type="password" label="Password" required />
<:actions :let={f}>
<.input field={{f, :remember_me}} type="checkbox" label="Keep me logged in" />
<.link href={~p"/users/reset_password"} class="text-sm font-semibold">
Forgot your password?
</.link>
</:actions>
<:actions>
<.button phx-disable-with="Signing in..." class="w-full">
Sign in <span aria-hidden="true">→</span>
</.button>
</:actions>
</.simple_form>
</div>
"""
end
def mount(_params, _session, socket) do
email = live_flash(socket.assigns.flash, :email)
{:ok, assign(socket, email: email), temporary_assigns: [email: nil]}
end
end

View File

@ -0,0 +1,74 @@
defmodule SomethingErlangWeb.UserRegistrationLive do
use SomethingErlangWeb, :live_view
alias SomethingErlang.Accounts
alias SomethingErlang.Accounts.User
def render(assigns) do
~H"""
<div class="mx-auto max-w-sm">
<.header class="text-center">
Register for an account
<:subtitle>
Already registered?
<.link navigate={~p"/users/log_in"} class="font-semibold text-brand hover:underline">
Sign in
</.link>
to your account now.
</:subtitle>
</.header>
<.simple_form
:let={f}
id="registration_form"
for={@changeset}
phx-submit="save"
phx-change="validate"
phx-trigger-action={@trigger_submit}
action={~p"/users/log_in?_action=registered"}
method="post"
as={:user}
>
<.error :if={@changeset.action == :insert}>
Oops, something went wrong! Please check the errors below.
</.error>
<.input field={{f, :email}} type="email" label="Email" required />
<.input field={{f, :password}} type="password" label="Password" required />
<:actions>
<.button phx-disable-with="Creating account..." class="w-full">Create an account</.button>
</:actions>
</.simple_form>
</div>
"""
end
def mount(_params, _session, socket) do
changeset = Accounts.change_user_registration(%User{})
socket = assign(socket, changeset: changeset, trigger_submit: false)
{:ok, socket, temporary_assigns: [changeset: nil]}
end
def handle_event("save", %{"user" => user_params}, socket) do
case Accounts.register_user(user_params) do
{:ok, user} ->
{:ok, _} =
Accounts.deliver_user_confirmation_instructions(
user,
&url(~p"/users/confirm/#{&1}")
)
changeset = Accounts.change_user_registration(user)
{:noreply, assign(socket, trigger_submit: true, changeset: changeset)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :changeset, changeset)}
end
end
def handle_event("validate", %{"user" => user_params}, socket) do
changeset = Accounts.change_user_registration(%User{}, user_params)
{:noreply, assign(socket, changeset: Map.put(changeset, :action, :validate))}
end
end

View File

@ -0,0 +1,87 @@
defmodule SomethingErlangWeb.UserResetPasswordLive do
use SomethingErlangWeb, :live_view
alias SomethingErlang.Accounts
def render(assigns) do
~H"""
<div class="mx-auto max-w-sm">
<.header class="text-center">Reset Password</.header>
<.simple_form
:let={f}
for={@changeset}
id="reset_password_form"
phx-submit="reset_password"
phx-change="validate"
>
<.error :if={@changeset.action == :insert}>
Oops, something went wrong! Please check the errors below.
</.error>
<.input field={{f, :password}} type="password" label="New password" required />
<.input
field={{f, :password_confirmation}}
type="password"
label="Confirm new password"
required
/>
<:actions>
<.button phx-disable-with="Resetting..." class="w-full">Reset Password</.button>
</:actions>
</.simple_form>
<p class="text-center mt-4">
<.link href={~p"/users/register"}>Register</.link>
|
<.link href={~p"/users/log_in"}>Log in</.link>
</p>
</div>
"""
end
def mount(params, _session, socket) do
socket = assign_user_and_token(socket, params)
socket =
case socket.assigns do
%{user: user} ->
assign(socket, :changeset, Accounts.change_user_password(user))
_ ->
socket
end
{:ok, socket, temporary_assigns: [changeset: nil]}
end
# Do not log in the user after reset password to avoid a
# leaked token giving the user access to the account.
def handle_event("reset_password", %{"user" => user_params}, socket) do
case Accounts.reset_user_password(socket.assigns.user, user_params) do
{:ok, _} ->
{:noreply,
socket
|> put_flash(:info, "Password reset successfully.")
|> redirect(to: ~p"/users/log_in")}
{:error, changeset} ->
{:noreply, assign(socket, :changeset, Map.put(changeset, :action, :insert))}
end
end
def handle_event("validate", %{"user" => user_params}, socket) do
changeset = Accounts.change_user_password(socket.assigns.user, user_params)
{:noreply, assign(socket, changeset: Map.put(changeset, :action, :validate))}
end
defp assign_user_and_token(socket, %{"token" => token}) do
if user = Accounts.get_user_by_reset_password_token(token) do
assign(socket, user: user, token: token)
else
socket
|> put_flash(:error, "Reset password link is invalid or it has expired.")
|> redirect(to: ~p"/")
end
end
end

View File

@ -0,0 +1,161 @@
defmodule SomethingErlangWeb.UserSettingsLive do
use SomethingErlangWeb, :live_view
alias SomethingErlang.Accounts
def render(assigns) do
~H"""
<.header>Change Email</.header>
<.simple_form
:let={f}
id="email_form"
for={@email_changeset}
phx-submit="update_email"
phx-change="validate_email"
>
<.error :if={@email_changeset.action == :insert}>
Oops, something went wrong! Please check the errors below.
</.error>
<.input field={{f, :email}} type="email" label="Email" required />
<.input
field={{f, :current_password}}
name="current_password"
id="current_password_for_email"
type="password"
label="Current password"
value={@email_form_current_password}
required
/>
<:actions>
<.button phx-disable-with="Changing...">Change Email</.button>
</:actions>
</.simple_form>
<.header>Change Password</.header>
<.simple_form
:let={f}
id="password_form"
for={@password_changeset}
action={~p"/users/log_in?_action=password_updated"}
method="post"
phx-change="validate_password"
phx-submit="update_password"
phx-trigger-action={@trigger_submit}
>
<.error :if={@password_changeset.action == :insert}>
Oops, something went wrong! Please check the errors below.
</.error>
<.input field={{f, :email}} type="hidden" value={@current_email} />
<.input field={{f, :password}} type="password" label="New password" required />
<.input field={{f, :password_confirmation}} type="password" label="Confirm new password" />
<.input
field={{f, :current_password}}
name="current_password"
type="password"
label="Current password"
id="current_password_for_password"
value={@current_password}
required
/>
<:actions>
<.button phx-disable-with="Changing...">Change Password</.button>
</:actions>
</.simple_form>
"""
end
def mount(%{"token" => token}, _session, socket) do
socket =
case Accounts.update_user_email(socket.assigns.current_user, token) do
:ok ->
put_flash(socket, :info, "Email changed successfully.")
:error ->
put_flash(socket, :error, "Email change link is invalid or it has expired.")
end
{:ok, push_navigate(socket, to: ~p"/users/settings")}
end
def mount(_params, _session, socket) do
user = socket.assigns.current_user
socket =
socket
|> assign(:current_password, nil)
|> assign(:email_form_current_password, nil)
|> assign(:current_email, user.email)
|> assign(:email_changeset, Accounts.change_user_email(user))
|> assign(:password_changeset, Accounts.change_user_password(user))
|> assign(:trigger_submit, false)
{:ok, socket}
end
def handle_event("validate_email", params, socket) do
%{"current_password" => password, "user" => user_params} = params
email_changeset = Accounts.change_user_email(socket.assigns.current_user, user_params)
socket =
assign(socket,
email_changeset: Map.put(email_changeset, :action, :validate),
email_form_current_password: password
)
{:noreply, socket}
end
def handle_event("update_email", params, socket) do
%{"current_password" => password, "user" => user_params} = params
user = socket.assigns.current_user
case Accounts.apply_user_email(user, password, user_params) do
{:ok, applied_user} ->
Accounts.deliver_user_update_email_instructions(
applied_user,
user.email,
&url(~p"/users/settings/confirm_email/#{&1}")
)
info = "A link to confirm your email change has been sent to the new address."
{:noreply, put_flash(socket, :info, info)}
{:error, changeset} ->
{:noreply, assign(socket, :email_changeset, Map.put(changeset, :action, :insert))}
end
end
def handle_event("validate_password", params, socket) do
%{"current_password" => password, "user" => user_params} = params
password_changeset = Accounts.change_user_password(socket.assigns.current_user, user_params)
{:noreply,
socket
|> assign(:password_changeset, Map.put(password_changeset, :action, :validate))
|> assign(:current_password, password)}
end
def handle_event("update_password", params, socket) do
%{"current_password" => password, "user" => user_params} = params
user = socket.assigns.current_user
case Accounts.update_user_password(user, password, user_params) do
{:ok, user} ->
socket =
socket
|> assign(:trigger_submit, true)
|> assign(:password_changeset, Accounts.change_user_password(user, user_params))
{:noreply, socket}
{:error, changeset} ->
{:noreply, assign(socket, :password_changeset, changeset)}
end
end
end