From 05b865c608fb2c0fa6297dd28f8345f7aa0fd100 Mon Sep 17 00:00:00 2001 From: Lucas Vas Date: Wed, 18 Mar 2026 13:48:26 -0400 Subject: [PATCH] feat: implement applicant page shell --- src/app.rs | 6 +- src/pages/provider_applicants.rs | 108 ++++++++++++++++++++++--------- 2 files changed, 83 insertions(+), 31 deletions(-) diff --git a/src/app.rs b/src/app.rs index 3439ed1..b8d691a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,11 +1,11 @@ use crate::components::ToastList; use crate::components::login::ProviderLoginContext; -use crate::pages::student; use crate::pages::{ AdminHomePage, AdminProviderPage, AdminScholarshipPage, AdminShell, AdminUtilsPage, ApplicantsPageFallback, AuthCallbackPage, LoanerBorrowForm, LoanerFallback, LoanerReturnForm, LoanerShell, ProviderContactPage, ProviderPortal, ScholarshipInfoPage, }; +use crate::pages::{ApplicantsPageShell, student}; use leptos::prelude::*; use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context}; use leptos_oidc::AuthSignal; @@ -86,7 +86,9 @@ fn ProviderRoutes() -> impl MatchNestedRoutes + Clone { view! { - + + + // diff --git a/src/pages/provider_applicants.rs b/src/pages/provider_applicants.rs index 84fe9a7..c1ae3f3 100644 --- a/src/pages/provider_applicants.rs +++ b/src/pages/provider_applicants.rs @@ -1,20 +1,18 @@ -use crate::common::ValueType; +use crate::common::{ExpandableInfo, ValueType}; use crate::components::{Banner, Loading}; -use leptos::either::Either; use leptos::prelude::*; use leptos_oidc::AuthSignal; +use leptos_router::components::Outlet; +use leptos_router::hooks::use_navigate; #[component] pub fn ApplicantsPageFallback() -> impl IntoView { view! { - -
-

"Applicants Page"

- -

- "This page is under construction! It will show all the students that are eligible for your scholarship(s)." +

+

"Scholarship Applicants"

+

+ "Please select a scholarship from the left to view the eligible applicants."

-

"Come back soon!"

} } @@ -29,7 +27,19 @@ pub fn ApplicantsPageShell() -> impl IntoView { // The content will be shown within the right side, but only as a result of some subroutes, // each of which is still considered a single page. - view! {
} + view! { + +
+
+
+ +
+ +
+
+
+
+ } } #[component] @@ -82,8 +92,17 @@ fn ApplicantsScholarshipList() -> impl IntoView { }, ); + let navigate = use_navigate(); + + // This closure returns another closure that's using the correct scholarship ID. + // It avoids having to define it within the Transition component. It's wrapped in a Callback + // because this makes it Send + Sync. + let on_view_click = Callback::new(move |scholarship_id: String| { + navigate(&*scholarship_id, Default::default()); + }); + view! { -
+

"Scholarships"

{move || { @@ -93,26 +112,28 @@ fn ApplicantsScholarshipList() -> impl IntoView { let items = match items_res { Ok(items) => items, Err(e) => { - return Either::Left( - view! { -
- {format!("Couldn't get scholarships: {}", e.to_string())} -
- } - .into_any(), - ); + return view! { +
+ {format!("Couldn't get scholarships: {}", e.to_string())} +
+ } + .into_any(); } }; - Either::Right( - items - .into_iter() - .map(|item| { - view! { } - .into_any() - }) - .collect_view(), - ) + view! { + + + + } + .into_any() }) .collect_view() }} @@ -122,7 +143,36 @@ fn ApplicantsScholarshipList() -> impl IntoView { } #[component] -fn ApplicantsScholarshipEntry() -> impl IntoView {} +fn ApplicantsScholarshipEntry( + #[prop()] item: ExpandableInfo, + #[prop(into)] on_view_click: Callback, +) -> impl IntoView { + // Store the item's subject. + let subject = StoredValue::new(item.subject); + let scholarship_name = Memo::new(move |_| { + item.data + .get("name") + .map(|name| name.as_string().ok().flatten()) + .flatten() + .unwrap_or("".to_string()) + }); + + let on_click = move |_| { + on_view_click.run(subject.get_value()); + }; + + view! { +
+
{scholarship_name}
+
+ "View Applicants" +
+
+ } +} #[component] fn ApplicantsStudentList() -> impl IntoView {}