feat: implement nested routes for loaner form
We're using this as our testing ground before attempting to refactor all other pages as well.
This commit is contained in:
1 parent
8147ec3e00
commit
c693ed9190
5 files changed
+80
-26
No files matched your search
@@ -6,3 +6,6 @@ rustflags = [
|
|||||||
|
|
||||||
[target.wasm32-unknown-unknown]
|
[target.wasm32-unknown-unknown]
|
||||||
rustflags = ["--cfg=web_sys_unstable_apis"]
|
rustflags = ["--cfg=web_sys_unstable_apis"]
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "windows")']
|
||||||
|
rustflags = ["--cfg=web_sys_unstable_apis"]
|
||||||
+5
-4
@@ -1,4 +1,4 @@
|
|||||||
use crate::pages::{AboutPage, HomePage, LoanerPage, ProviderPortal, ComparisonTestPage, ScholarshipInfoPage, TestPage, ProviderContactPage};
|
use crate::pages::{AboutPage, HomePage, ProviderPortal, ComparisonTestPage, ScholarshipInfoPage, TestPage, ProviderContactPage, LoanerShell, LoanerFallback, LoanerBorrowForm, LoanerReturnForm};
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context};
|
use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context};
|
||||||
use leptos_oidc::{Auth, AuthParameters, AuthSignal, Challenge};
|
use leptos_oidc::{Auth, AuthParameters, AuthSignal, Challenge};
|
||||||
@@ -108,9 +108,10 @@ pub fn AppWithRoutes() -> impl IntoView {
|
|||||||
<Route path=path!(":id") view=ScholarshipInfoPage/>
|
<Route path=path!(":id") view=ScholarshipInfoPage/>
|
||||||
<Route path=path!("") view=ScholarshipInfoPage/>
|
<Route path=path!("") view=ScholarshipInfoPage/>
|
||||||
</ParentRoute>
|
</ParentRoute>
|
||||||
<ParentRoute path=path!("loaners") view=LoanerPage>
|
<ParentRoute path=path!("loaners") view=LoanerShell>
|
||||||
<Route path=path!("") view=LoanerPage />
|
<Route path=path!("") view=LoanerFallback />
|
||||||
<Route path=path!(":form_name") view=LoanerPage />
|
<Route path=path!("borrowing") view=LoanerBorrowForm />
|
||||||
|
<Route path=path!("returning") view=LoanerReturnForm />
|
||||||
</ParentRoute>
|
</ParentRoute>
|
||||||
</Routes>
|
</Routes>
|
||||||
</ToastList>
|
</ToastList>
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
use leptos_animate::animations::classes::{In, Out};
|
||||||
|
|
||||||
|
pub fn pop_in_out() -> (In, Out) {
|
||||||
|
(
|
||||||
|
In::default()
|
||||||
|
.source("opacity-0 -translate-y-2 scale-90")
|
||||||
|
.active("transition-all duration-150 transform-gpu")
|
||||||
|
.target("opacity-100 translate-y-0 scale-100"),
|
||||||
|
Out::default()
|
||||||
|
.source("opacity-100 translate-y-0 scale-100")
|
||||||
|
.active("transition-all duration-150 transform-gpu")
|
||||||
|
.target("opacity-0 -translate-y-2 scale-90"),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,5 +5,6 @@ mod form_schema;
|
|||||||
mod user;
|
mod user;
|
||||||
mod value_type;
|
mod value_type;
|
||||||
mod submit_status;
|
mod submit_status;
|
||||||
|
pub mod animations;
|
||||||
|
|
||||||
pub use self::{comparison::*, expandable_info::*, form_schema::*, user::*, value_type::*, form_params::*, submit_status::*};
|
pub use self::{comparison::*, expandable_info::*, form_schema::*, user::*, value_type::*, form_params::*, submit_status::*};
|
||||||
+57
-22
@@ -19,6 +19,13 @@ use leptos_router::hooks::{use_navigate, use_params};
|
|||||||
use leptos_router::params::Params;
|
use leptos_router::params::Params;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use leptos_router::components::Outlet;
|
||||||
|
use leptos_animate::animate;
|
||||||
|
use crate::common::animations::pop_in_out;
|
||||||
|
// Loaner page creates a single page that contains the borrowing/returning buttons
|
||||||
|
// and a panel for a form. At first, it will show a fallback view. At the borrowing
|
||||||
|
// path it will show the borrow form, and at the returning path it will show the
|
||||||
|
// return form.
|
||||||
|
|
||||||
#[derive(Params, PartialEq)]
|
#[derive(Params, PartialEq)]
|
||||||
struct LoanerParams {
|
struct LoanerParams {
|
||||||
@@ -191,7 +198,7 @@ async fn create_borrow_entry(input: ExpandableInfo) -> Result<(), ServerFnError>
|
|||||||
/// create a true admin page for this, simply to be able to survey and override/remove information
|
/// create a true admin page for this, simply to be able to survey and override/remove information
|
||||||
/// from the lists.
|
/// from the lists.
|
||||||
#[component]
|
#[component]
|
||||||
pub fn LoanerPage() -> impl IntoView {
|
pub fn LoanerShell() -> impl IntoView {
|
||||||
// Check URL params. Depending on what string is visible here, we'll display a different form.
|
// Check URL params. Depending on what string is visible here, we'll display a different form.
|
||||||
let params = use_params::<LoanerParams>();
|
let params = use_params::<LoanerParams>();
|
||||||
let form_passed = move || {
|
let form_passed = move || {
|
||||||
@@ -203,16 +210,9 @@ pub fn LoanerPage() -> impl IntoView {
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let form_view = move || match form_passed().as_str() {
|
|
||||||
"borrowing" => EitherOf3::A(LoanerBorrowForm),
|
|
||||||
"returning" => EitherOf3::B(LoanerReturnForm),
|
|
||||||
_ => EitherOf3::C("Choose something from the left.".into_view()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// We'll create the page here - the sidebar contains all the buttons, while the form
|
// We'll create the page here - the sidebar contains all the buttons, while the form
|
||||||
// container either shows forms or shows placeholder text.
|
// container either shows forms or shows placeholder text.
|
||||||
view! {
|
view! {
|
||||||
<ToastList>
|
|
||||||
<Banner
|
<Banner
|
||||||
title="Chromebook Loaners"
|
title="Chromebook Loaners"
|
||||||
logo="/PHS_Stacked_Acronym.png"
|
logo="/PHS_Stacked_Acronym.png"
|
||||||
@@ -235,16 +235,36 @@ pub fn LoanerPage() -> impl IntoView {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-2">
|
<div class="flex flex-2">
|
||||||
<Panel>{form_view}</Panel>
|
<Panel>
|
||||||
|
<Outlet />
|
||||||
|
</Panel>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ToastList>
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn LoanerFallback() -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<div
|
||||||
|
class="flex flex-col items-center justify-center"
|
||||||
|
use:animate=pop_in_out()
|
||||||
|
>
|
||||||
|
<div class="text-3xl font-bold mb-2">
|
||||||
|
"Chromebook Loaner Form"
|
||||||
|
</div>
|
||||||
|
<div class="text-lg">
|
||||||
|
"Select an option from the left to begin."
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn LoanerBorrowForm() -> impl IntoView {
|
pub fn LoanerBorrowForm() -> impl IntoView {
|
||||||
|
let navigate = use_navigate();
|
||||||
|
|
||||||
// Register server actions.
|
// Register server actions.
|
||||||
let create_entry_action = ServerAction::<CreateBorrowEntry>::new();
|
let create_entry_action = ServerAction::<CreateBorrowEntry>::new();
|
||||||
|
|
||||||
@@ -259,7 +279,7 @@ pub fn LoanerBorrowForm() -> impl IntoView {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//#region Toast Logic
|
//#region Toast Logic
|
||||||
let mut toast_context = expect_context::<ToastContext>();
|
let mut toast_context = expect_context::<ToastContext>();
|
||||||
Effect::new(move || {
|
Effect::new(move || {
|
||||||
@@ -268,14 +288,17 @@ pub fn LoanerBorrowForm() -> impl IntoView {
|
|||||||
toast_context.toast(
|
toast_context.toast(
|
||||||
Toast::new()
|
Toast::new()
|
||||||
.id(uuid::Uuid::new_v4().to_string())
|
.id(uuid::Uuid::new_v4().to_string())
|
||||||
.msg("From the form!")
|
.header("Borrower Added!")
|
||||||
|
.msg("You can take your loaner now.")
|
||||||
);
|
);
|
||||||
|
navigate("/loaners", Default::default());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<ValidatedForm
|
<ValidatedForm
|
||||||
|
use:animate=pop_in_out()
|
||||||
on_submit=Callback::new(on_submit)
|
on_submit=Callback::new(on_submit)
|
||||||
title="Borrower Information"
|
title="Borrower Information"
|
||||||
description="Please fill out the form below."
|
description="Please fill out the form below."
|
||||||
@@ -346,7 +369,7 @@ pub fn LoanerBorrowForm() -> impl IntoView {
|
|||||||
#[component]
|
#[component]
|
||||||
pub fn LoanerReturnForm() -> impl IntoView {
|
pub fn LoanerReturnForm() -> impl IntoView {
|
||||||
let navigate = use_navigate();
|
let navigate = use_navigate();
|
||||||
|
|
||||||
// Register server actions
|
// Register server actions
|
||||||
let check_in_action = ServerAction::<CheckInLoaner>::new();
|
let check_in_action = ServerAction::<CheckInLoaner>::new();
|
||||||
|
|
||||||
@@ -368,12 +391,19 @@ pub fn LoanerReturnForm() -> impl IntoView {
|
|||||||
|
|
||||||
// Create an effect to run after check-in - refreshes the list with another scan request.
|
// Create an effect to run after check-in - refreshes the list with another scan request.
|
||||||
// This could be beneficial if we ever decided to make multiple loaner kiosks (think SAT days)
|
// This could be beneficial if we ever decided to make multiple loaner kiosks (think SAT days)
|
||||||
|
let mut toasts = expect_context::<ToastContext>();
|
||||||
Effect::new(move || {
|
Effect::new(move || {
|
||||||
if let Some(Ok(_)) = check_in_action.value().get() {
|
if let Some(Ok(_)) = check_in_action.value().get() {
|
||||||
// Return to the main page.
|
// Return to the main page.
|
||||||
if let Some(dialog) = dialog_ref.get() {
|
if let Some(dialog) = dialog_ref.get() {
|
||||||
dialog.close();
|
dialog.close();
|
||||||
}
|
}
|
||||||
|
toasts.toast(
|
||||||
|
Toast::new()
|
||||||
|
.id(uuid::Uuid::new_v4())
|
||||||
|
.header("Check in successful!")
|
||||||
|
.msg("Don't forget to take your collateral.")
|
||||||
|
);
|
||||||
navigate("/loaners", Default::default());
|
navigate("/loaners", Default::default());
|
||||||
check_in_action.clear();
|
check_in_action.clear();
|
||||||
}
|
}
|
||||||
@@ -399,6 +429,7 @@ pub fn LoanerReturnForm() -> impl IntoView {
|
|||||||
|
|
||||||
view! {
|
view! {
|
||||||
<dialog
|
<dialog
|
||||||
|
use:animate=pop_in_out()
|
||||||
class="p-3 m-auto rounded-md shadow-lg/33 backdrop:backdrop-blur-xs backdrop:transition-backdrop-filter"
|
class="p-3 m-auto rounded-md shadow-lg/33 backdrop:backdrop-blur-xs backdrop:transition-backdrop-filter"
|
||||||
node_ref=dialog_ref>
|
node_ref=dialog_ref>
|
||||||
<h2 class="text-2xl font-bold">"Confirmation"</h2>
|
<h2 class="text-2xl font-bold">"Confirmation"</h2>
|
||||||
@@ -414,12 +445,16 @@ pub fn LoanerReturnForm() -> impl IntoView {
|
|||||||
<ActionButton on:click=close_dialog disabled=dialog_disabled>"Close"</ActionButton>
|
<ActionButton on:click=close_dialog disabled=dialog_disabled>"Close"</ActionButton>
|
||||||
<ActionButton on:click=dialog_check_in disabled=dialog_disabled>"Check In"</ActionButton>
|
<ActionButton on:click=dialog_check_in disabled=dialog_disabled>"Check In"</ActionButton>
|
||||||
</dialog>
|
</dialog>
|
||||||
<div class="flex flex-col justify-center gap-2 mb-3 py-3 px-2">
|
|
||||||
<h2 class="text-2xl font-bold">"Student List"</h2>
|
<div
|
||||||
<p class="text-lg">"Please select your name from the list."</p>
|
class="flex flex-col gap-2 m-2"
|
||||||
</div>
|
use:animate=pop_in_out()
|
||||||
<Suspense fallback=move || "Loading...".into_view()>
|
>
|
||||||
<div class="flex flex-col gap-2 m-2">
|
<div class="flex flex-col justify-center gap-2 mb-3 py-3 px-2">
|
||||||
|
<h2 class="text-2xl font-bold">"Student List"</h2>
|
||||||
|
<p class="text-lg">"Please select your name from the list."</p>
|
||||||
|
</div>
|
||||||
|
<Suspense fallback=move || "Loading...".into_view()>
|
||||||
{move || {
|
{move || {
|
||||||
match return_list_resource.get() {
|
match return_list_resource.get() {
|
||||||
Some(loaner_list) => {
|
Some(loaner_list) => {
|
||||||
@@ -461,7 +496,7 @@ pub fn LoanerReturnForm() -> impl IntoView {
|
|||||||
None => Either::Right("No loaners found.".into_view())
|
None => Either::Right("No loaners found.".into_view())
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
</div>
|
</Suspense>
|
||||||
</Suspense>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user