fixup edit wall page

This commit is contained in:
2025-02-09 18:22:56 +01:00
parent 2b9533534a
commit fe33cc9c12
4 changed files with 56 additions and 60 deletions

View File

@@ -23,9 +23,7 @@ pub fn Problem(#[prop(into)] dim: Signal<models::WallDimensions>, #[prop(into)]
view! { view! {
<div class="grid grid-cols-[auto,1fr] gap-8"> <div class="grid grid-cols-[auto,1fr] gap-8">
<div class=move || { grid_classes.clone() }> <div class=move || { grid_classes.clone() }>{holds}</div>
{holds}
</div>
</div> </div>
} }
} }

View File

@@ -1,13 +1,13 @@
use crate::codec::ron::Ron; use crate::components::StyledHeader;
use crate::codec::ron::RonEncoded;
use crate::components::header::HeaderItem; use crate::components::header::HeaderItem;
use crate::components::header::HeaderItems; use crate::components::header::HeaderItems;
use crate::models; use crate::models;
use crate::models::HoldPosition; use crate::models::HoldPosition;
use crate::models::Wall; use leptos::Params;
use leptos::ev::Event; use leptos::ev::Event;
use leptos::html::Input; use leptos::html::Input;
use leptos::prelude::*; use leptos::prelude::*;
use leptos_router::params::Params;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use server_fn::codec::Cbor; use server_fn::codec::Cbor;
@@ -15,17 +15,28 @@ use wasm_bindgen::JsCast;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use web_sys::FileList; use web_sys::FileList;
#[derive(Params, PartialEq, Clone)]
struct RouteParams {
wall_uid: Option<models::WallUid>,
}
#[component] #[component]
pub fn EditWall() -> impl leptos::IntoView { pub fn EditWall() -> impl leptos::IntoView {
let load = async move { let params = leptos_router::hooks::use_params::<RouteParams>();
// TODO: What to do about this unwrap? let wall_uid = Signal::derive(move || {
load_initial_data().await.unwrap() params
}; .get()
.expect("gets wall_uid from URL")
.wall_uid
.expect("wall_uid param is never None")
});
let header_items = HeaderItems { let wall = crate::resources::wall_by_uid(wall_uid);
let header_items = move || HeaderItems {
left: vec![HeaderItem { left: vec![HeaderItem {
text: "← Ascend".to_string(), text: "← Ascend".to_string(),
link: Some("/".to_string()), link: Some(format!("/wall/{}", wall_uid.get())),
}], }],
middle: vec![HeaderItem { middle: vec![HeaderItem {
text: "HOLDS".to_string(), text: "HOLDS".to_string(),
@@ -34,29 +45,43 @@ pub fn EditWall() -> impl leptos::IntoView {
right: vec![], right: vec![],
}; };
// leptos::view! { leptos::view! {
// <div class="min-w-screen min-h-screen bg-slate-900"> <div class="min-w-screen min-h-screen bg-slate-900">
// <StyledHeader items=header_items /> <StyledHeader items=Signal::derive(header_items) />
// <div class="container mx-auto mt-2"> <div class="container mx-auto mt-2">
// <Await future=load let:data> <Suspense fallback=move || {
// <Ready data=data.deref().to_owned() /> view! { <p>"Loading..."</p> }
// </Await> }>
// </div> {move || Suspend::new(async move {
// </div> let wall = wall.await;
// } view! {
<ErrorBoundary fallback=|_errors| {
"error"
}>
{move || -> Result<_, ServerFnError> {
let wall = wall.clone()?;
Ok(view! { <Ready wall /> })
}}
</ErrorBoundary>
}
})}
</Suspense>
</div>
</div>
}
} }
#[component] #[component]
fn Ready(data: InitialData) -> impl leptos::IntoView { fn Ready(wall: models::Wall) -> impl leptos::IntoView {
tracing::debug!("ready"); tracing::debug!("ready");
let mut holds = vec![]; let mut holds = vec![];
for hold in data.wall.holds.values().cloned() { for hold in wall.holds.values().cloned() {
holds.push(view! { <Hold hold /> }); holds.push(view! { <Hold hold /> });
} }
let grid_classes = format!("grid grid-rows-{} grid-cols-{} gap-3", data.wall.rows, data.wall.cols); let grid_classes = format!("grid grid-rows-{} grid-cols-{} gap-3", wall.rows, wall.cols);
view! { view! {
<div> <div>
@@ -137,29 +162,12 @@ fn Hold(hold: models::Hold) -> impl leptos::IntoView {
} }
} }
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct InitialData {
wall: Wall,
}
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Image { pub struct Image {
file_name: String, file_name: String,
file_contents: Vec<u8>, file_contents: Vec<u8>,
} }
#[server(
input = Ron,
output = Ron,
custom = RonEncoded
)]
#[tracing::instrument(skip_all, err)]
async fn load_initial_data() -> Result<RonEncoded<InitialData>, ServerFnError> {
todo!()
// let wall = state.persistent.with(|s| s.wall.clone()).await;
// Ok(RonCodec::new(InitialData { wall }))
}
#[server(name = SetImage, input = Cbor)] #[server(name = SetImage, input = Cbor)]
#[tracing::instrument(skip(image), err)] #[tracing::instrument(skip(image), err)]
async fn set_image(hold_position: HoldPosition, image: Image) -> Result<models::Hold, ServerFnError> { async fn set_image(hold_position: HoldPosition, image: Image) -> Result<models::Hold, ServerFnError> {

View File

@@ -1,4 +1,3 @@
use crate::codec::ron::Ron;
use crate::components; use crate::components;
use crate::components::header::HeaderItem; use crate::components::header::HeaderItem;
use crate::components::header::HeaderItems; use crate::components::header::HeaderItems;
@@ -65,20 +64,14 @@ pub fn Routes() -> impl leptos::IntoView {
each=problems_sample each=problems_sample
key=|problem| problem.uid key=|problem| problem.uid
children=move |problem: models::Problem| { children=move |problem: models::Problem| {
view! { view! { <Problem dim=wall_dimensions problem /> }
<Problem dim=wall_dimensions problem/>
}
} }
/> />
</div> </div>
}) })
}; };
view! { view! { <ErrorBoundary fallback=|_errors| "error">{v}</ErrorBoundary> }
<ErrorBoundary fallback=|errors| "error">
{v}
</ErrorBoundary>
}
}) })
}; };
@@ -87,11 +80,8 @@ pub fn Routes() -> impl leptos::IntoView {
<StyledHeader items=header_items /> <StyledHeader items=header_items />
<div class="container mx-auto mt-2"> <div class="container mx-auto mt-2">
{move || view! { <Import wall_uid=wall_uid.get() /> }} {move || view! { <Import wall_uid=wall_uid.get() /> }}
<Suspense fallback=|| view! { <p>"loading"</p> }>{suspend}</Suspense>
<Suspense fallback=|| view! {<p>"loading"</p>}>
{suspend}
</Suspense>
</div> </div>
</div> </div>
} }
@@ -104,7 +94,7 @@ fn Problem(#[prop(into)] dim: Signal<models::WallDimensions>, #[prop(into)] prob
view! { view! {
<components::Problem dim problem /> <components::Problem dim problem />
<p>{ move || problem.get().name.clone() }</p> <p>{move || problem.get().name.clone()}</p>
} }
} }

View File

@@ -59,7 +59,7 @@ pub fn Wall() -> impl IntoView {
{move || Suspend::new(async move { {move || Suspend::new(async move {
let wall: Option<models::Wall> = wall.get().and_then(Result::ok); let wall: Option<models::Wall> = wall.get().and_then(Result::ok);
wall.map(|wall| { wall.map(|wall| {
view! { <Ready wall/> } view! { <Ready wall /> }
}) })
})} })}
</Suspense> </Suspense>
@@ -121,9 +121,9 @@ fn Ready(wall: models::Wall) -> impl leptos::IntoView {
</div> </div>
<div> <div>
<div>// TODO: // TODO:
// <p>{current_problem.read().as_ref().map(|p| p.name.clone())}</p> // <p>{current_problem.read().as_ref().map(|p| p.name.clone())}</p>
// <p>{current_problem.read().as_ref().map(|p| p.set_by.clone())}</p> <div>// <p>{current_problem.read().as_ref().map(|p| p.set_by.clone())}</p>
</div> </div>
<Button onclick=move |_| problem_fetcher.mark_dirty() text="➤ Next problem" /> <Button onclick=move |_| problem_fetcher.mark_dirty() text="➤ Next problem" />