profile of a new registered users

This commit is contained in:
Priec
2026-06-18 21:11:48 +02:00
parent b9c1277876
commit c6624e1b3d
20 changed files with 501 additions and 17 deletions

112
src/controllers/account.rs Normal file
View File

@@ -0,0 +1,112 @@
//! Customer account area. Currently just the shipping/contact profile, whose
//! fields prefill the checkout form. Gated to authenticated non-admin users:
//! anonymous visitors are bounced to `/login`. Admins have their own area and
//! are sent to the dashboard.
use axum_extra::extract::cookie::CookieJar;
use loco_rs::prelude::*;
use serde::Deserialize;
use serde_json::json;
use crate::{
controllers::i18n::current_lang,
models::customer_profiles::{self, ProfileFields},
shared::guard,
};
#[derive(Debug, Deserialize)]
struct ProfileForm {
phone_prefix: Option<String>,
phone: Option<String>,
address: Option<String>,
city: Option<String>,
zip: Option<String>,
country: Option<String>,
}
fn trimmed(value: Option<&str>) -> Option<String> {
value.map(str::trim).filter(|v| !v.is_empty()).map(String::from)
}
impl From<ProfileForm> for ProfileFields {
fn from(form: ProfileForm) -> Self {
Self {
phone_prefix: trimmed(form.phone_prefix.as_deref()),
phone: trimmed(form.phone.as_deref()),
address: trimmed(form.address.as_deref()),
city: trimmed(form.city.as_deref()),
zip: trimmed(form.zip.as_deref()),
country: trimmed(form.country.as_deref()),
}
}
}
/// Render the profile form for `profile` (which may be `None` for a customer
/// who hasn't saved anything yet). `saved` shows the success banner after a
/// POST.
fn profile_view(
v: &TeraView,
jar: &CookieJar,
name: &str,
email: &str,
profile: Option<&customer_profiles::Model>,
saved: bool,
) -> Result<Response> {
format::view(
v,
"account/profile.html",
json!({
"logged_in_admin": false,
"logged_in_customer": true,
"saved": saved,
"name": name,
"email": email,
"phone_prefix": profile.and_then(|p| p.phone_prefix.clone()),
"phone": profile.and_then(|p| p.phone.clone()),
"address": profile.and_then(|p| p.address.clone()),
"city": profile.and_then(|p| p.city.clone()),
"zip": profile.and_then(|p| p.zip.clone()),
"country": profile.and_then(|p| p.country.clone()),
"lang": current_lang(jar),
}),
)
}
#[debug_handler]
async fn profile_page(
jar: CookieJar,
ViewEngine(v): ViewEngine<TeraView>,
State(ctx): State<AppContext>,
) -> Result<Response> {
let Some(user) = guard::current_user(&ctx, &jar).await else {
return format::redirect("/login");
};
if guard::is_admin(&ctx, &user) {
return format::redirect("/admin/dashboard");
}
let profile = customer_profiles::Model::find_for_user(&ctx.db, user.id).await?;
profile_view(&v, &jar, &user.name, &user.email, profile.as_ref(), false)
}
#[debug_handler]
async fn save_profile(
jar: CookieJar,
ViewEngine(v): ViewEngine<TeraView>,
State(ctx): State<AppContext>,
Form(form): Form<ProfileForm>,
) -> Result<Response> {
let Some(user) = guard::current_user(&ctx, &jar).await else {
return format::redirect("/login");
};
if guard::is_admin(&ctx, &user) {
return format::redirect("/admin/dashboard");
}
let profile = customer_profiles::Model::upsert(&ctx.db, user.id, form.into()).await?;
profile_view(&v, &jar, &user.name, &user.email, Some(&profile), true)
}
pub fn routes() -> Routes {
Routes::new()
.add("/account/profile", get(profile_page))
.add("/account/profile", post(save_profile))
}