PR with too many features #58

Merged
BobdaFett merged 56 commits from feat/admin-page into main 2026-02-10 14:31:49 +00:00
8 changed files with 135 additions and 42 deletions
Showing only changes of commit 3f1745a589 - Show all commits

No files matched your search

+2 -1
View File
@@ -1,4 +1,4 @@
use crate::pages::{ProviderPortal, ScholarshipInfoPage, ProviderContactPage, LoanerShell, LoanerFallback, LoanerBorrowForm, LoanerReturnForm, AuthCallbackPage, ApplicantsPageFallback, AdminShell, AdminHomePage, AdminProviderPage, AdminScholarshipPage, StudentShell, StudentHomePage, StudentDemographicsPage};
use crate::pages::{ProviderPortal, ScholarshipInfoPage, ProviderContactPage, LoanerShell, LoanerFallback, LoanerBorrowForm, LoanerReturnForm, AuthCallbackPage, ApplicantsPageFallback, AdminShell, AdminHomePage, AdminProviderPage, AdminScholarshipPage, StudentShell, StudentHomePage, StudentDemographicsPage, AdditionalPage};
use leptos::prelude::*;
use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context};
use leptos_oidc::AuthSignal;
@@ -123,6 +123,7 @@ fn StudentRoutes() -> impl MatchNestedRoutes + Clone {
<Route path=path!("callback") view=AuthCallbackPage />
<Route path=path!("home") view=StudentHomePage />
<Route path=path!("demographics") view=StudentDemographicsPage />
<Route path=path!("additional") view=AdditionalPage />
</ParentRoute>
}
.into_inner()
+23 -2
View File
@@ -2,13 +2,34 @@
pub struct TabInfo {
pub text: String,
pub path: String,
pub sub_paths: Vec<SubTabInfo>,
}
impl TabInfo {
pub fn new(text: impl Into<String>, path: impl Into<String>) -> Self {
pub fn new(
text: impl Into<String>,
path: impl Into<String>,
sub_paths: Option<Vec<SubTabInfo>>
) -> Self {
Self {
text: text.into(),
path: path.into(),
sub_paths: sub_paths.unwrap_or_default()
}
}
}
}
#[derive(Debug, Clone)]
pub struct SubTabInfo {
pub text: String,
pub path: String,
}
impl SubTabInfo {
pub fn new(text: impl Into<String>, path: impl Into<String>) -> Self {
Self {
text: text.into(),
path: path.into()
}
}
}
+76 -30
View File
@@ -1,34 +1,9 @@
use leptos::prelude::*;
use leptos_animate::animate;
use leptos_animate::animations::classes::{In, Out};
use leptos_router::components::{Outlet, A};
use leptos_router::hooks::use_location;
use crate::common::TabInfo;
#[component]
fn SidebarTab(
#[prop(into)] text: Signal<String>,
#[prop(into)] path: Signal<String>
) -> impl IntoView {
let location = use_location();
let selected = Memo::new(move |_| {
let current_path = location.pathname.get();
// There's extra logic here as well, but for now this works.
current_path.starts_with(&path.get())
});
view! {
<A href=move || path.get()>
<div
class="p-3 transition-all font-bold"
class=(["bg-transparent", "text-white"], move || !selected.get())
class=(["bg-white", "text-black"], move || selected.get())
>
{text}
</div>
</A>
}
}
use crate::common::{SubTabInfo, TabInfo};
/// # Tab Sidebar Component
///
@@ -85,9 +60,9 @@ pub fn TabSidebarList(
<For
each=move || tabs.get()
key=|info| info.text.clone()
let(TabInfo { text, path })
let(TabInfo { text, path, sub_paths })
>
<SidebarTab text=text path=path />
<SidebarTab text=text path=path sub_paths=sub_paths />
</For>
</nav>
@@ -97,3 +72,74 @@ pub fn TabSidebarList(
</div>
}
}
#[component]
fn SidebarTab(
#[prop(into)] text: Signal<String>,
#[prop(into)] path: Signal<String>,
#[prop(into)] sub_paths: Signal<Vec<SubTabInfo>>,
) -> impl IntoView {
let location = use_location();
let selected = Memo::new(move |_| {
let current_path = location.pathname.get();
// There's extra logic here as well, but for now this works.
current_path.starts_with(&path.get())
});
view! {
<A href=move || path.get()>
<div
class="p-3 transition-all font-bold"
class=(["bg-transparent", "text-white"], move || !selected.get())
class=(["bg-white", "text-black"], move || selected.get())
>
{text}
</div>
</A>
<For
each=move || sub_paths.get()
key=|info| info.text.clone()
let(SubTabInfo { text, path })
>
<SidebarSubTab
use:animate=(
In::default()
.source("h-0")
.target("h-auto")
.active("transition-all"),
Out::default()
.source("h-auto")
.target("h-0")
.active("transition-all")
)
text=text path=path visible=selected />
</For>
}
}
#[component]
fn SidebarSubTab(
#[prop(into)] text: Signal<String>,
#[prop(into)] path: Signal<String>,
#[prop(into)] visible: Signal<bool>,
) -> impl IntoView {
let selected = Memo::new(move |_| {
visible.get()
});
view! {
<div class="grid transition-all ease-in-out"
style:grid-template-rows=move || if visible.get() { "1fr" } else { "0fr" }
style:opacity=move || if visible.get() { "1" } else { "0" }
>
<div
class="overflow-hidden p-3 pl-10 transition-all bg-white"
class=(["font-bold"], move || selected.get())
>
{text}
</div>
</div>
}
}
+3 -3
View File
@@ -15,9 +15,9 @@ pub fn AdminShell() -> impl IntoView {
<Banner title="R15 Scholarships Admin" logo="/PHS_Stacked_Acronym.png" />
// We'll put the tabs here.
<TabSidebarList tabs=vec![
TabInfo::new("Home", "/admin/home"),
TabInfo::new("Providers", "/admin/providers"),
TabInfo::new("Scholarships", "/admin/scholarships"),
TabInfo::new("Home", "/admin/home", None),
TabInfo::new("Providers", "/admin/providers", None),
TabInfo::new("Scholarships", "/admin/scholarships", None),
] />
</AdminLoginContext>
}
+13
View File
@@ -0,0 +1,13 @@
use leptos::prelude::*;
#[component]
pub fn AdditionalPage() -> impl IntoView {
view! {
<div class="flex flex-1 flex-col gap-4 items-center m-4">
<div class="font-bold text-3xl">"Student Additional Forms"</div>
<div class="text-lg">
"This is just a placeholder for now. We'll show redirect buttons to each form."
</div>
</div>
}
}
+3 -1
View File
@@ -5,7 +5,9 @@ pub fn StudentHomePage() -> impl IntoView {
view! {
<div class="flex flex-1 flex-col gap-4 items-center m-4">
<div class="font-bold text-3xl">"Student Home Page"</div>
<div class="text-lg">"This is just a placeholder for now. We'll show some redirect buttons."</div>
<div class="text-lg">
"This is just a placeholder for now. We'll show some redirect buttons."
</div>
</div>
}
}
+3 -1
View File
@@ -1,7 +1,9 @@
mod shell;
mod home_page;
mod demographics_page;
mod additional_page;
pub use shell::*;
pub use home_page::*;
pub use demographics_page::*;
pub use demographics_page::*;
pub use additional_page::*;
+12 -4
View File
@@ -1,6 +1,6 @@
use leptos::prelude::*;
use leptos_oidc::{AuthLoaded, Authenticated};
use crate::common::TabInfo;
use crate::common::{SubTabInfo, TabInfo};
use crate::components::{Banner, Loading, TabSidebarList};
use crate::components::login::StudentLoginContext;
use crate::pages::UnauthenticatedPage;
@@ -14,9 +14,17 @@ pub fn StudentShell() -> impl IntoView {
<AuthLoaded fallback=Loading>
<Authenticated unauthenticated=UnauthenticatedPage>
<TabSidebarList tabs=vec![
TabInfo::new("Home", "/students/home"),
TabInfo::new("Demographics", "/students/demographics"),
TabInfo::new("Additional Info", "/students/additional"),
TabInfo::new("Home", "/students/home", None),
TabInfo::new("Demographics", "/students/demographics",
Some(vec![
SubTabInfo::new("Testing", "/students/testing"),
SubTabInfo::new("Testing Again!", "/students/testing/again")
])),
TabInfo::new("Additional Info", "/students/additional",
Some(vec![
SubTabInfo::new("Testing", "/students/testing"),
SubTabInfo::new("Testing Again!", "/students/testing/again")
])),
] />
</Authenticated>
</AuthLoaded>