add user auth
This commit is contained in:
parent
fd82d6e7bd
commit
41eaec5c8e
12 changed files with 627 additions and 221 deletions
|
|
@ -119,6 +119,8 @@
|
|||
color: oklch(58% 0.233 277.117) !important;
|
||||
}
|
||||
|
||||
/* Input field dark mode fixes */
|
||||
|
||||
/* Marker cluster styles */
|
||||
.marker-cluster-small {
|
||||
background-color: rgba(16, 185, 129, 0.8);
|
||||
|
|
@ -326,4 +328,60 @@
|
|||
|
||||
.historical-dot-marker {
|
||||
z-index: 15 !important;
|
||||
}
|
||||
|
||||
/* Input field dark mode fixes - Override DaisyUI CSS variables for dark theme */
|
||||
|
||||
[data-theme="dark"] {
|
||||
--color-base-100: #2d3748 !important;
|
||||
--color-base-200: #1a202c !important;
|
||||
--color-base-300: #171923 !important;
|
||||
--color-base-content: #f7fafc !important;
|
||||
--input-bg: #2d3748;
|
||||
--input-color: #f7fafc;
|
||||
--input-border: #4a5568;
|
||||
}
|
||||
|
||||
/* Ultra-specific selector to override DaisyUI */
|
||||
html[data-theme="dark"] .card .input,
|
||||
html[data-theme="dark"] .card .input-bordered,
|
||||
html[data-theme="dark"] .card input.input,
|
||||
html[data-theme="dark"] .card input.input-bordered,
|
||||
html[data-theme="dark"] .card input[type="email"],
|
||||
html[data-theme="dark"] .card input[type="password"],
|
||||
html[data-theme="dark"] .form-control input.input,
|
||||
html[data-theme="dark"] .form-control input.input-bordered,
|
||||
html[data-theme="dark"] .form-control input[type="email"],
|
||||
html[data-theme="dark"] .form-control input[type="password"] {
|
||||
background-color: #2d3748 !important;
|
||||
color: #f7fafc !important;
|
||||
border-color: #4a5568 !important;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .card .input:focus,
|
||||
html[data-theme="dark"] .card .input-bordered:focus,
|
||||
html[data-theme="dark"] .card input.input:focus,
|
||||
html[data-theme="dark"] .card input.input-bordered:focus,
|
||||
html[data-theme="dark"] .card input[type="email"]:focus,
|
||||
html[data-theme="dark"] .card input[type="password"]:focus,
|
||||
html[data-theme="dark"] .form-control input.input:focus,
|
||||
html[data-theme="dark"] .form-control input.input-bordered:focus,
|
||||
html[data-theme="dark"] .form-control input[type="email"]:focus,
|
||||
html[data-theme="dark"] .form-control input[type="password"]:focus {
|
||||
background-color: #2d3748 !important;
|
||||
color: #f7fafc !important;
|
||||
border-color: #6366f1 !important;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .input::placeholder,
|
||||
html[data-theme="dark"] input.input::placeholder,
|
||||
html[data-theme="dark"] input[type="email"]::placeholder,
|
||||
html[data-theme="dark"] input[type="password"]::placeholder {
|
||||
color: oklch(60% 0.029 256.847) !important;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .checkbox,
|
||||
html[data-theme="dark"] input.checkbox {
|
||||
background-color: var(--input-bg) !important;
|
||||
border-color: var(--input-border) !important;
|
||||
}
|
||||
|
|
@ -237,7 +237,7 @@ defmodule AprsmeWeb.CoreComponents do
|
|||
def simple_form(assigns) do
|
||||
~H"""
|
||||
<.form :let={f} for={@for} as={@as} {@rest}>
|
||||
<div class="space-y-8 bg-white mt-10">
|
||||
<div class="space-y-8 bg-base-100 mt-10">
|
||||
{render_slot(@inner_block, f)}
|
||||
<div :for={action <- @actions} class="mt-2 flex items-center justify-between gap-6">
|
||||
{render_slot(action, f)}
|
||||
|
|
@ -442,6 +442,7 @@ defmodule AprsmeWeb.CoreComponents do
|
|||
"""
|
||||
attr :class, :string, default: ""
|
||||
attr :dev_mode, :boolean, default: false
|
||||
attr :current_user, :any, default: nil
|
||||
|
||||
def header(assigns) do
|
||||
~H"""
|
||||
|
|
@ -455,7 +456,7 @@ defmodule AprsmeWeb.CoreComponents do
|
|||
</.link>
|
||||
</div>
|
||||
<div class="navbar-center hidden lg:flex">
|
||||
<.navigation variant={:horizontal} />
|
||||
<.navigation variant={:horizontal} current_user={@current_user} />
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
<.theme_selector />
|
||||
|
|
@ -474,7 +475,7 @@ defmodule AprsmeWeb.CoreComponents do
|
|||
tabindex="0"
|
||||
class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-base-100 rounded-box w-52"
|
||||
>
|
||||
<.navigation variant={:vertical} />
|
||||
<.navigation variant={:vertical} current_user={@current_user} />
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -750,6 +751,7 @@ defmodule AprsmeWeb.CoreComponents do
|
|||
"""
|
||||
attr :class, :string, default: ""
|
||||
attr :variant, :atom, values: [:horizontal, :vertical], default: :horizontal
|
||||
attr :current_user, :any, default: nil
|
||||
|
||||
def navigation(assigns) do
|
||||
~H"""
|
||||
|
|
@ -764,6 +766,29 @@ defmodule AprsmeWeb.CoreComponents do
|
|||
{gettext("About")}
|
||||
</.link>
|
||||
</li>
|
||||
<%= if @current_user do %>
|
||||
<li>
|
||||
<.link navigate="/users/settings" class="text-gray-900 hover:text-gray-700">
|
||||
{gettext("Settings")}
|
||||
</.link>
|
||||
</li>
|
||||
<li>
|
||||
<.link href="/users/log_out" method="delete" class="text-gray-900 hover:text-gray-700">
|
||||
{gettext("Log out")}
|
||||
</.link>
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<.link navigate="/users/register" class="text-gray-900 hover:text-gray-700">
|
||||
{gettext("Register")}
|
||||
</.link>
|
||||
</li>
|
||||
<li>
|
||||
<.link navigate="/users/log_in" class="text-gray-900 hover:text-gray-700">
|
||||
{gettext("Log in")}
|
||||
</.link>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% else %>
|
||||
<li><.link navigate="/" class="text-gray-900 hover:text-gray-700">{gettext("Home")}</.link></li>
|
||||
|
|
@ -771,6 +796,29 @@ defmodule AprsmeWeb.CoreComponents do
|
|||
<li>
|
||||
<.link navigate="/about" class="text-gray-900 hover:text-gray-700">{gettext("About")}</.link>
|
||||
</li>
|
||||
<%= if @current_user do %>
|
||||
<li>
|
||||
<.link navigate="/users/settings" class="text-gray-900 hover:text-gray-700">
|
||||
{gettext("Settings")}
|
||||
</.link>
|
||||
</li>
|
||||
<li>
|
||||
<.link href="/users/log_out" method="delete" class="text-gray-900 hover:text-gray-700">
|
||||
{gettext("Log out")}
|
||||
</.link>
|
||||
</li>
|
||||
<% else %>
|
||||
<li>
|
||||
<.link navigate="/users/register" class="text-gray-900 hover:text-gray-700">
|
||||
{gettext("Register")}
|
||||
</.link>
|
||||
</li>
|
||||
<li>
|
||||
<.link navigate="/users/log_in" class="text-gray-900 hover:text-gray-700">
|
||||
{gettext("Log in")}
|
||||
</.link>
|
||||
</li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
"""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@
|
|||
}
|
||||
</style>
|
||||
|
||||
<.header dev_mode={Application.get_env(:aprsme, :dev_routes, false)} />
|
||||
<.header dev_mode={Application.get_env(:aprsme, :dev_routes, false)} current_user={@current_user} />
|
||||
<main
|
||||
id="main-content"
|
||||
class={if assigns[:map_page], do: "min-h-screen bg-base-100", else: "bg-base-100"}
|
||||
|
|
|
|||
|
|
@ -906,7 +906,7 @@ defmodule AprsmeWeb.MapLive.Index do
|
|||
</svg>
|
||||
<span class="font-medium">{gettext("Navigation")}</span>
|
||||
</div>
|
||||
<.navigation variant={:vertical} class="text-sm" />
|
||||
<.navigation variant={:vertical} class="text-sm" current_user={@current_user} />
|
||||
</div>
|
||||
|
||||
<!-- Deployment Information -->
|
||||
|
|
|
|||
|
|
@ -6,25 +6,61 @@ defmodule AprsmeWeb.UserConfirmationInstructionsLive do
|
|||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<.header />
|
||||
<div class="hero min-h-screen bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title text-3xl mb-4 justify-center">
|
||||
Resend confirmation instructions
|
||||
</h1>
|
||||
<p class="text-base-content/70 mb-6">
|
||||
Enter your email address to receive a new confirmation link
|
||||
</p>
|
||||
|
||||
<.simple_form
|
||||
:let={f}
|
||||
for={%{}}
|
||||
as={: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>
|
||||
<.simple_form
|
||||
:let={_f}
|
||||
for={%{}}
|
||||
as={:user}
|
||||
id="resend_confirmation_form"
|
||||
phx-submit="send_instructions"
|
||||
>
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Email</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
name="user[email]"
|
||||
class="input input-bordered w-full bg-base-100 text-base-content"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<.link navigate={~p"/users/register"}>Register</.link>
|
||||
| <.link navigate={~p"/users/log_in"}>Log in</.link>
|
||||
</p>
|
||||
<div class="form-control mt-6">
|
||||
<button type="submit" class="btn btn-primary w-full" phx-disable-with="Sending...">
|
||||
Resend confirmation instructions
|
||||
</button>
|
||||
</div>
|
||||
</.simple_form>
|
||||
|
||||
<div class="divider">OR</div>
|
||||
|
||||
<div class="text-center text-sm">
|
||||
<.link navigate={~p"/users/register"} class="link link-primary">
|
||||
Register
|
||||
</.link>
|
||||
|
|
||||
<.link navigate={~p"/users/log_in"} class="link link-primary">
|
||||
Log in
|
||||
</.link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -6,20 +6,49 @@ defmodule AprsmeWeb.UserConfirmationLive do
|
|||
|
||||
def render(%{live_action: :edit} = assigns) do
|
||||
~H"""
|
||||
<div class="mx-auto max-w-sm">
|
||||
<.header class="text-center" />
|
||||
<div class="hero min-h-screen bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title text-3xl mb-4 justify-center">Confirm your account</h1>
|
||||
<p class="text-base-content/70 mb-6">Click the button below to confirm your account</p>
|
||||
|
||||
<.simple_form :let={f} for={%{}} as={: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>
|
||||
<.simple_form
|
||||
:let={_f}
|
||||
for={%{}}
|
||||
as={:user}
|
||||
id="confirmation_form"
|
||||
phx-submit="confirm_account"
|
||||
>
|
||||
<input type="hidden" name="user[token]" value={@token} />
|
||||
|
||||
<p class="text-center mt-4">
|
||||
<.link navigate={~p"/users/register"}>Register</.link>
|
||||
| <.link navigate={~p"/users/log_in"}>Log in</.link>
|
||||
</p>
|
||||
<div class="form-control mt-6">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary w-full"
|
||||
phx-disable-with="Confirming..."
|
||||
>
|
||||
Confirm my account
|
||||
</button>
|
||||
</div>
|
||||
</.simple_form>
|
||||
|
||||
<div class="divider">OR</div>
|
||||
|
||||
<div class="text-center text-sm">
|
||||
<.link navigate={~p"/users/register"} class="link link-primary">
|
||||
Register
|
||||
</.link>
|
||||
|
|
||||
<.link navigate={~p"/users/log_in"} class="link link-primary">
|
||||
Log in
|
||||
</.link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,24 +6,56 @@ defmodule AprsmeWeb.UserForgotPasswordLive do
|
|||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div class="mx-auto max-w-sm">
|
||||
<.header class="text-center" />
|
||||
<div class="hero min-h-screen bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title text-3xl mb-4 justify-center">Forgot your password?</h1>
|
||||
<p class="text-base-content/70 mb-6">We'll send a password reset link to your inbox</p>
|
||||
|
||||
<h2 class="text-center text-2xl font-bold mt-6 mb-2">Forgot your password?</h2>
|
||||
<p class="text-center text-gray-600 mb-6">We'll send a password reset link to your inbox</p>
|
||||
<.simple_form
|
||||
:let={_f}
|
||||
id="reset_password_form"
|
||||
for={%{}}
|
||||
as={:user}
|
||||
phx-submit="send_email"
|
||||
>
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Email</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
name="user[email]"
|
||||
class="input input-bordered w-full bg-base-100 text-base-content"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<.simple_form :let={f} id="reset_password_form" for={%{}} as={: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 navigate={~p"/users/register"}>Register</.link>
|
||||
| <.link navigate={~p"/users/log_in"}>Log in</.link>
|
||||
</p>
|
||||
<div class="form-control mt-6">
|
||||
<button type="submit" class="btn btn-primary w-full" phx-disable-with="Sending...">
|
||||
Send password reset instructions
|
||||
</button>
|
||||
</div>
|
||||
</.simple_form>
|
||||
|
||||
<div class="divider">OR</div>
|
||||
|
||||
<div class="text-center text-sm">
|
||||
<.link navigate={~p"/users/register"} class="link link-primary">
|
||||
Register
|
||||
</.link>
|
||||
|
|
||||
<.link navigate={~p"/users/log_in"} class="link link-primary">
|
||||
Log in
|
||||
</.link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,41 +7,88 @@ defmodule AprsmeWeb.UserLoginLive do
|
|||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div class="mx-auto max-w-sm">
|
||||
<.header class="text-center" />
|
||||
<div class="hero min-h-screen bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title text-3xl mb-4 justify-center">Sign in to account</h1>
|
||||
<p class="text-base-content/70 mb-6">
|
||||
Don't have an account?
|
||||
<.link navigate={~p"/users/register"} class="link link-primary">
|
||||
Sign up
|
||||
</.link>
|
||||
for an account now.
|
||||
</p>
|
||||
|
||||
<h2 class="text-center text-2xl font-bold mt-6 mb-2">Sign in to account</h2>
|
||||
<p class="text-center text-gray-600 mb-6">
|
||||
Don't have an account?
|
||||
<.link navigate={~p"/users/register"} class="font-semibold text-brand hover:underline">
|
||||
Sign up
|
||||
</.link>
|
||||
for an account now.
|
||||
</p>
|
||||
<.simple_form
|
||||
:let={f}
|
||||
id="login_form"
|
||||
for={@changeset}
|
||||
action={~p"/users/log_in"}
|
||||
as={:user}
|
||||
phx-update="ignore"
|
||||
>
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Email</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
name={Phoenix.HTML.Form.input_name(f, :email)}
|
||||
value={Phoenix.HTML.Form.input_value(f, :email) || ""}
|
||||
class="input input-bordered w-full"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<.simple_form
|
||||
:let={f}
|
||||
id="login_form"
|
||||
for={@changeset}
|
||||
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 />
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Password</span>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
name={Phoenix.HTML.Form.input_name(f, :password)}
|
||||
value={Phoenix.HTML.Form.input_value(f, :password) || ""}
|
||||
class="input input-bordered w-full"
|
||||
placeholder="Enter your password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<:actions :let={f}>
|
||||
<.input field={{f, :remember_me}} type="checkbox" label="Keep me logged in" />
|
||||
<.link navigate={~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 class="form-control">
|
||||
<label class="label cursor-pointer justify-start">
|
||||
<input
|
||||
type="checkbox"
|
||||
name={Phoenix.HTML.Form.input_name(f, :remember_me)}
|
||||
value="true"
|
||||
class="checkbox checkbox-primary mr-2"
|
||||
/>
|
||||
<span class="label-text">Keep me logged in</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="text-center mb-4">
|
||||
<.link navigate={~p"/users/reset_password"} class="link link-primary text-sm">
|
||||
Forgot your password?
|
||||
</.link>
|
||||
</div>
|
||||
|
||||
<div class="form-control mt-6">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary w-full"
|
||||
phx-disable-with="Signing in..."
|
||||
>
|
||||
Sign in →
|
||||
</button>
|
||||
</div>
|
||||
</.simple_form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,40 +7,77 @@ defmodule AprsmeWeb.UserRegistrationLive do
|
|||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div class="mx-auto max-w-sm">
|
||||
<.header class="text-center" />
|
||||
<div class="hero min-h-screen bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title text-3xl mb-4 justify-center">Register for an account</h1>
|
||||
<p class="text-base-content/70 mb-6">
|
||||
Already registered?
|
||||
<.link navigate={~p"/users/log_in"} class="link link-primary">
|
||||
Sign in
|
||||
</.link>
|
||||
to your account now.
|
||||
</p>
|
||||
|
||||
<h2 class="text-center text-2xl font-bold mt-6 mb-2">Register for an account</h2>
|
||||
<p class="text-center text-gray-600 mb-6">
|
||||
Already registered?
|
||||
<.link navigate={~p"/users/log_in"} class="font-semibold text-brand hover:underline">
|
||||
Sign in
|
||||
</.link>
|
||||
to your account now.
|
||||
</p>
|
||||
<.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}
|
||||
>
|
||||
<div :if={@changeset.action == :insert} class="alert alert-error mb-4">
|
||||
<span>Oops, something went wrong! Please check the errors below.</span>
|
||||
</div>
|
||||
|
||||
<.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>
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Email</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
name={Phoenix.HTML.Form.input_name(f, :email)}
|
||||
value={Phoenix.HTML.Form.input_value(f, :email) || ""}
|
||||
class="input input-bordered w-full bg-base-100 text-base-content"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<.input field={{f, :email}} type="email" label="Email" required />
|
||||
<.input field={{f, :password}} type="password" label="Password" required />
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Password</span>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
name={Phoenix.HTML.Form.input_name(f, :password)}
|
||||
value={Phoenix.HTML.Form.input_value(f, :password) || ""}
|
||||
class="input input-bordered w-full bg-base-100 text-base-content"
|
||||
placeholder="Enter your password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<:actions>
|
||||
<.button phx-disable-with="Creating account..." class="w-full">Create an account</.button>
|
||||
</:actions>
|
||||
</.simple_form>
|
||||
<div class="form-control mt-6">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary w-full"
|
||||
phx-disable-with="Creating account..."
|
||||
>
|
||||
Create an account
|
||||
</button>
|
||||
</div>
|
||||
</.simple_form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,36 +6,75 @@ defmodule AprsmeWeb.UserResetPasswordLive do
|
|||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div class="mx-auto max-w-sm">
|
||||
<.header class="text-center" />
|
||||
<div class="hero min-h-screen bg-base-200">
|
||||
<div class="hero-content text-center">
|
||||
<div class="max-w-md">
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h1 class="card-title text-3xl mb-4 justify-center">Reset Password</h1>
|
||||
<p class="text-base-content/70 mb-6">Enter your new password below</p>
|
||||
|
||||
<.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>
|
||||
<.simple_form
|
||||
:let={f}
|
||||
for={@changeset}
|
||||
id="reset_password_form"
|
||||
phx-submit="reset_password"
|
||||
phx-change="validate"
|
||||
>
|
||||
<div :if={@changeset.action == :insert} class="alert alert-error mb-4">
|
||||
<span>Oops, something went wrong! Please check the errors below.</span>
|
||||
</div>
|
||||
|
||||
<.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>
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">New password</span>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
name={Phoenix.HTML.Form.input_name(f, :password)}
|
||||
value={Phoenix.HTML.Form.input_value(f, :password) || ""}
|
||||
class="input input-bordered w-full bg-base-100 text-base-content"
|
||||
placeholder="Enter new password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p class="text-center mt-4">
|
||||
<.link navigate={~p"/users/register"}>Register</.link>
|
||||
| <.link navigate={~p"/users/log_in"}>Log in</.link>
|
||||
</p>
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Confirm new password</span>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
name={Phoenix.HTML.Form.input_name(f, :password_confirmation)}
|
||||
value={Phoenix.HTML.Form.input_value(f, :password_confirmation) || ""}
|
||||
class="input input-bordered w-full bg-base-100 text-base-content"
|
||||
placeholder="Confirm new password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control mt-6">
|
||||
<button type="submit" class="btn btn-primary w-full" phx-disable-with="Resetting...">
|
||||
Reset Password
|
||||
</button>
|
||||
</div>
|
||||
</.simple_form>
|
||||
|
||||
<div class="divider">OR</div>
|
||||
|
||||
<div class="text-center text-sm">
|
||||
<.link navigate={~p"/users/register"} class="link link-primary">
|
||||
Register
|
||||
</.link>
|
||||
|
|
||||
<.link navigate={~p"/users/log_in"} class="link link-primary">
|
||||
Log in
|
||||
</.link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,68 +6,147 @@ defmodule AprsmeWeb.UserSettingsLive do
|
|||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<.header />
|
||||
<div class="hero min-h-screen bg-base-200">
|
||||
<div class="hero-content flex-col w-full max-w-4xl">
|
||||
<div class="text-center mb-8">
|
||||
<h1 class="text-4xl font-bold">Account Settings</h1>
|
||||
<p class="text-base-content/70">Update your email address and password</p>
|
||||
</div>
|
||||
|
||||
<.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>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 w-full">
|
||||
<!-- Change Email Section -->
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-2xl mb-4">Change Email</h2>
|
||||
|
||||
<.input field={{f, :email}} type="email" label="Email" required />
|
||||
<.simple_form
|
||||
:let={f}
|
||||
id="email_form"
|
||||
for={@email_changeset}
|
||||
phx-submit="update_email"
|
||||
phx-change="validate_email"
|
||||
>
|
||||
<div :if={@email_changeset.action == :insert} class="alert alert-error mb-4">
|
||||
<span>Oops, something went wrong! Please check the errors below.</span>
|
||||
</div>
|
||||
|
||||
<.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>
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Email</span>
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
name={Phoenix.HTML.Form.input_name(f, :email)}
|
||||
value={Phoenix.HTML.Form.input_value(f, :email) || ""}
|
||||
class="input input-bordered w-full bg-base-100 text-base-content"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<.header />
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Current password</span>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
name="current_password"
|
||||
id="current_password_for_email"
|
||||
value={@email_form_current_password || ""}
|
||||
class="input input-bordered w-full bg-base-100 text-base-content"
|
||||
placeholder="Enter current password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<.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>
|
||||
<div class="form-control mt-6">
|
||||
<button type="submit" class="btn btn-primary w-full" phx-disable-with="Changing...">
|
||||
Change Email
|
||||
</button>
|
||||
</div>
|
||||
</.simple_form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Change Password Section -->
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-2xl mb-4">Change Password</h2>
|
||||
|
||||
<.input field={{f, :email}} type="hidden" value={@current_email} />
|
||||
<.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}
|
||||
>
|
||||
<div :if={@password_changeset.action == :insert} class="alert alert-error mb-4">
|
||||
<span>Oops, something went wrong! Please check the errors below.</span>
|
||||
</div>
|
||||
|
||||
<.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>
|
||||
<input
|
||||
type="hidden"
|
||||
name={Phoenix.HTML.Form.input_name(f, :email)}
|
||||
value={@current_email}
|
||||
/>
|
||||
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">New password</span>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
name={Phoenix.HTML.Form.input_name(f, :password)}
|
||||
value={Phoenix.HTML.Form.input_value(f, :password) || ""}
|
||||
class="input input-bordered w-full bg-base-100 text-base-content"
|
||||
placeholder="Enter new password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Confirm new password</span>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
name={Phoenix.HTML.Form.input_name(f, :password_confirmation)}
|
||||
value={Phoenix.HTML.Form.input_value(f, :password_confirmation) || ""}
|
||||
class="input input-bordered w-full bg-base-100 text-base-content"
|
||||
placeholder="Confirm new password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control w-full">
|
||||
<label class="label">
|
||||
<span class="label-text">Current password</span>
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
name="current_password"
|
||||
id="current_password_for_password"
|
||||
value={@current_password || ""}
|
||||
class="input input-bordered w-full bg-base-100 text-base-content"
|
||||
placeholder="Enter current password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control mt-6">
|
||||
<button type="submit" class="btn btn-primary w-full" phx-disable-with="Changing...">
|
||||
Change Password
|
||||
</button>
|
||||
</div>
|
||||
</.simple_form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -51,10 +51,37 @@ defmodule AprsmeWeb.Router do
|
|||
get "/status.json", PageController, :status_json
|
||||
end
|
||||
|
||||
## Authentication routes
|
||||
|
||||
scope "/", AprsmeWeb do
|
||||
pipe_through [:browser, :redirect_if_user_is_authenticated]
|
||||
|
||||
live_session :redirect_if_user_is_authenticated,
|
||||
on_mount: [{AprsmeWeb.UserAuth, :redirect_if_user_is_authenticated}, {AprsmeWeb.LocaleHook, :set_locale}] do
|
||||
live "/users/register", UserRegistrationLive, :new
|
||||
live "/users/log_in", UserLoginLive, :new
|
||||
live "/users/reset_password", UserForgotPasswordLive, :new
|
||||
live "/users/reset_password/:token", UserResetPasswordLive, :edit
|
||||
end
|
||||
|
||||
post "/users/log_in", UserSessionController, :create
|
||||
end
|
||||
|
||||
scope "/", AprsmeWeb do
|
||||
pipe_through [:browser, :require_authenticated_user]
|
||||
|
||||
live_session :require_authenticated_user,
|
||||
on_mount: [{AprsmeWeb.UserAuth, :ensure_authenticated}, {AprsmeWeb.LocaleHook, :set_locale}] do
|
||||
live "/users/settings", UserSettingsLive, :edit
|
||||
live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email
|
||||
end
|
||||
end
|
||||
|
||||
scope "/", AprsmeWeb do
|
||||
pipe_through :browser
|
||||
|
||||
live_session :regular_pages, on_mount: [{AprsmeWeb.LocaleHook, :set_locale}] do
|
||||
live_session :regular_pages,
|
||||
on_mount: [{AprsmeWeb.UserAuth, :mount_current_user}, {AprsmeWeb.LocaleHook, :set_locale}] do
|
||||
live "/status", StatusLive.Index, :index
|
||||
live "/packets", PacketsLive.Index, :index
|
||||
live "/packets/:callsign", PacketsLive.CallsignView, :index
|
||||
|
|
@ -89,30 +116,4 @@ defmodule AprsmeWeb.Router do
|
|||
forward "/mailbox", Plug.Swoosh.MailboxPreview
|
||||
end
|
||||
end
|
||||
|
||||
## Authentication routes
|
||||
|
||||
scope "/", AprsmeWeb do
|
||||
pipe_through [:browser, :redirect_if_user_is_authenticated]
|
||||
|
||||
live_session :redirect_if_user_is_authenticated,
|
||||
on_mount: [{AprsmeWeb.UserAuth, :redirect_if_user_is_authenticated}, {AprsmeWeb.LocaleHook, :set_locale}] do
|
||||
live "/users/register", UserRegistrationLive, :new
|
||||
live "/users/log_in", UserLoginLive, :new
|
||||
live "/users/reset_password", UserForgotPasswordLive, :new
|
||||
live "/users/reset_password/:token", UserResetPasswordLive, :edit
|
||||
end
|
||||
|
||||
post "/users/log_in", UserSessionController, :create
|
||||
end
|
||||
|
||||
scope "/", AprsmeWeb do
|
||||
pipe_through [:browser, :require_authenticated_user]
|
||||
|
||||
live_session :require_authenticated_user,
|
||||
on_mount: [{AprsmeWeb.UserAuth, :ensure_authenticated}, {AprsmeWeb.LocaleHook, :set_locale}] do
|
||||
live "/users/settings", UserSettingsLive, :edit
|
||||
live "/users/settings/confirm_email/:token", UserSettingsLive, :confirm_email
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue