Progressively enhanced register form
Thanks copilot for all the shit I didn't have to write.
This commit is contained in:
parent
5881412b59
commit
7abffb2729
@ -1,6 +1,7 @@
|
|||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use axum::TypedHeader;
|
use axum::TypedHeader;
|
||||||
use axum::{extract::State, Form};
|
use axum::{extract::State, Form};
|
||||||
|
use http::HeaderValue;
|
||||||
use lettre::SmtpTransport;
|
use lettre::SmtpTransport;
|
||||||
use maud::html;
|
use maud::html;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -25,8 +26,17 @@ pub struct Register {
|
|||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get(hx_target: Option<TypedHeader<HXTarget>>, layout: Layout) -> Result<Response> {
|
pub fn register_page(
|
||||||
Ok(layout
|
hx_target: Option<TypedHeader<HXTarget>>,
|
||||||
|
layout: Layout,
|
||||||
|
form_props: RegisterFormProps,
|
||||||
|
) -> Response {
|
||||||
|
if let Some(hx_target) = &hx_target {
|
||||||
|
if hx_target.target == HeaderValue::from_static("register-form") {
|
||||||
|
return register_form(form_props).into_response();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layout
|
||||||
.with_subtitle("register")
|
.with_subtitle("register")
|
||||||
.targeted(hx_target)
|
.targeted(hx_target)
|
||||||
.render(html! {
|
.render(html! {
|
||||||
@ -34,9 +44,18 @@ pub async fn get(hx_target: Option<TypedHeader<HXTarget>>, layout: Layout) -> Re
|
|||||||
header class="center-text" {
|
header class="center-text" {
|
||||||
h2 { "Register" }
|
h2 { "Register" }
|
||||||
}
|
}
|
||||||
(register_form(RegisterFormProps::default()))
|
(register_form(form_props))
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
|
.into_response()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get(hx_target: Option<TypedHeader<HXTarget>>, layout: Layout) -> Result<Response> {
|
||||||
|
Ok(register_page(
|
||||||
|
hx_target,
|
||||||
|
layout,
|
||||||
|
RegisterFormProps::default(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn post(
|
pub async fn post(
|
||||||
@ -49,22 +68,16 @@ pub async fn post(
|
|||||||
Form(register): Form<Register>,
|
Form(register): Form<Register>,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
if register.password != register.password_confirmation {
|
if register.password != register.password_confirmation {
|
||||||
return Ok(layout
|
return Ok(register_page(
|
||||||
.with_subtitle("register")
|
hx_target,
|
||||||
.targeted(hx_target)
|
layout,
|
||||||
.render(html! {
|
RegisterFormProps {
|
||||||
div class="center-horizontal" {
|
email: Some(register.email),
|
||||||
header class="center-text" {
|
name: register.name,
|
||||||
h2 { "Register" }
|
password_error: Some("passwords do not match".to_string()),
|
||||||
}
|
..Default::default()
|
||||||
(register_form(RegisterFormProps {
|
},
|
||||||
email: Some(register.email),
|
));
|
||||||
name: register.name,
|
|
||||||
password_error: Some("passwords do not match".to_string()),
|
|
||||||
..Default::default()
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
let user = match User::create(
|
let user = match User::create(
|
||||||
&pool,
|
&pool,
|
||||||
@ -80,62 +93,50 @@ pub async fn post(
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
if let Error::InvalidEntity(validation_errors) = err {
|
if let Error::InvalidEntity(validation_errors) = err {
|
||||||
let field_errors = validation_errors.field_errors();
|
let field_errors = validation_errors.field_errors();
|
||||||
return Ok(layout
|
return Ok(register_page(
|
||||||
.with_subtitle("register")
|
hx_target,
|
||||||
.targeted(hx_target)
|
layout,
|
||||||
.render(html! {
|
RegisterFormProps {
|
||||||
div class="center-horizontal" {
|
email: Some(register.email),
|
||||||
header class="center-text" {
|
name: register.name,
|
||||||
h2 { "Register" }
|
email_error: field_errors.get("email").map(|&errors| {
|
||||||
}
|
errors
|
||||||
(register_form(RegisterFormProps {
|
.iter()
|
||||||
email: Some(register.email),
|
.filter_map(|error| error.message.clone().map(|m| m.to_string()))
|
||||||
name: register.name,
|
.collect::<Vec<String>>()
|
||||||
email_error: field_errors.get("email").map(|&errors| {
|
.join(", ")
|
||||||
errors
|
}),
|
||||||
.iter()
|
name_error: field_errors.get("name").map(|&errors| {
|
||||||
.filter_map(|error| error.message.clone().map(|m| m.to_string()))
|
errors
|
||||||
.collect::<Vec<String>>()
|
.iter()
|
||||||
.join(", ")
|
.filter_map(|error| error.message.clone().map(|m| m.to_string()))
|
||||||
}),
|
.collect::<Vec<String>>()
|
||||||
name_error: field_errors.get("name").map(|&errors| {
|
.join(", ")
|
||||||
errors
|
}),
|
||||||
.iter()
|
password_error: field_errors.get("password").map(|&errors| {
|
||||||
.filter_map(|error| error.message.clone().map(|m| m.to_string()))
|
errors
|
||||||
.collect::<Vec<String>>()
|
.iter()
|
||||||
.join(", ")
|
.filter_map(|error| error.message.clone().map(|m| m.to_string()))
|
||||||
}),
|
.collect::<Vec<String>>()
|
||||||
password_error: field_errors.get("password").map(|&errors| {
|
.join(", ")
|
||||||
errors
|
}),
|
||||||
.iter()
|
..Default::default()
|
||||||
.filter_map(|error| error.message.clone().map(|m| m.to_string()))
|
},
|
||||||
.collect::<Vec<String>>()
|
));
|
||||||
.join(", ")
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
if let Error::Sqlx(sqlx::error::Error::Database(db_error)) = &err {
|
if let Error::Sqlx(sqlx::error::Error::Database(db_error)) = &err {
|
||||||
if let Some(constraint) = db_error.constraint() {
|
if let Some(constraint) = db_error.constraint() {
|
||||||
if constraint == "users_email_idx" {
|
if constraint == "users_email_idx" {
|
||||||
return Ok(layout
|
return Ok(register_page(
|
||||||
.with_subtitle("register")
|
hx_target,
|
||||||
.targeted(hx_target)
|
layout,
|
||||||
.render(html! {
|
RegisterFormProps {
|
||||||
div class="center-horizontal" {
|
email: Some(register.email),
|
||||||
header class="center-text" {
|
name: register.name,
|
||||||
h2 { "Register" }
|
email_error: Some("email already exists".to_string()),
|
||||||
}
|
..Default::default()
|
||||||
(register_form(RegisterFormProps {
|
},
|
||||||
email: Some(register.email),
|
));
|
||||||
name: register.name,
|
|
||||||
email_error: Some("email already exists".to_string()),
|
|
||||||
..Default::default()
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,24 +20,56 @@ pub fn register_form(props: RegisterFormProps) -> Markup {
|
|||||||
general_error,
|
general_error,
|
||||||
} = props;
|
} = props;
|
||||||
html! {
|
html! {
|
||||||
form action="/register" method="post" class="auth-form-grid" {
|
form
|
||||||
|
action="/register"
|
||||||
|
method="post"
|
||||||
|
hx-post="/register"
|
||||||
|
hx-target="#register-form"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
id="register-form"
|
||||||
|
class="auth-form-grid"
|
||||||
|
{
|
||||||
label for="email" { "Email *" }
|
label for="email" { "Email *" }
|
||||||
input type="email" name="email" id="email" placeholder="Email" value=(email.unwrap_or_default()) required;
|
input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
id="email"
|
||||||
|
placeholder="Email"
|
||||||
|
value=(email.unwrap_or_default())
|
||||||
|
required;
|
||||||
@if let Some(email_error) = email_error {
|
@if let Some(email_error) = email_error {
|
||||||
span class="error" { (email_error) }
|
span class="error" { (email_error) }
|
||||||
}
|
}
|
||||||
label for="name" { (PreEscaped("Name ")) }
|
label for="name" { (PreEscaped("Name ")) }
|
||||||
input type="text" name="name" id="name" value=(name.unwrap_or_default()) placeholder="Name" maxlength="255";
|
input
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
id="name"
|
||||||
|
value=(name.unwrap_or_default())
|
||||||
|
placeholder="Name"
|
||||||
|
maxlength="255";
|
||||||
@if let Some(name_error) = name_error {
|
@if let Some(name_error) = name_error {
|
||||||
span class="error" { (name_error) }
|
span class="error" { (name_error) }
|
||||||
}
|
}
|
||||||
label for="email" { "Password *" }
|
label for="email" { "Password *" }
|
||||||
input type="password" name="password" id="password" placeholder="Password" minlength="8" maxlength="255" required;
|
input
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
id="password"
|
||||||
|
placeholder="Password"
|
||||||
|
minlength="8"
|
||||||
|
maxlength="255"
|
||||||
|
required;
|
||||||
@if let Some(password_error) = password_error {
|
@if let Some(password_error) = password_error {
|
||||||
span class="error" { (password_error) }
|
span class="error" { (password_error) }
|
||||||
}
|
}
|
||||||
label for="password_confirmation" { "Confirm Password *" }
|
label for="password_confirmation" { "Confirm Password *" }
|
||||||
input type="password" name="password_confirmation" id="password_confirmation" placeholder="Confirm Password" required;
|
input
|
||||||
|
type="password"
|
||||||
|
name="password_confirmation"
|
||||||
|
id="password_confirmation"
|
||||||
|
placeholder="Confirm Password"
|
||||||
|
required;
|
||||||
button type="submit" { "Submit" }
|
button type="submit" { "Submit" }
|
||||||
@if let Some(general_error) = general_error {
|
@if let Some(general_error) = general_error {
|
||||||
span class="error" { (general_error) }
|
span class="error" { (general_error) }
|
||||||
|
Loading…
Reference in New Issue
Block a user