PR with too many features #58
No files matched your search
+14
-1
@@ -1,4 +1,4 @@
|
|||||||
use crate::pages::{ProviderPortal, ScholarshipInfoPage, ProviderContactPage, LoanerShell, LoanerFallback, LoanerBorrowForm, LoanerReturnForm, AuthCallbackPage, ApplicantsPageFallback, TestPage};
|
use crate::pages::{ProviderPortal, ScholarshipInfoPage, ProviderContactPage, LoanerShell, LoanerFallback, LoanerBorrowForm, LoanerReturnForm, AuthCallbackPage, ApplicantsPageFallback, AdminShell, AdminTesting, AdminFallback};
|
||||||
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::AuthSignal;
|
use leptos_oidc::AuthSignal;
|
||||||
@@ -64,6 +64,7 @@ pub fn AppWithRoutes() -> impl IntoView {
|
|||||||
// <Route path=path!("/testing") view=TestPage />
|
// <Route path=path!("/testing") view=TestPage />
|
||||||
<ProviderRoutes />
|
<ProviderRoutes />
|
||||||
<LoanerRoutes />
|
<LoanerRoutes />
|
||||||
|
<AdminRoutes />
|
||||||
</Routes>
|
</Routes>
|
||||||
</ToastList>
|
</ToastList>
|
||||||
</main>
|
</main>
|
||||||
@@ -101,6 +102,18 @@ fn LoanerRoutes() -> impl MatchNestedRoutes + Clone {
|
|||||||
.into_any_nested_route()
|
.into_any_nested_route()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[component(transparent)]
|
||||||
|
fn AdminRoutes() -> impl MatchNestedRoutes + Clone {
|
||||||
|
view! {
|
||||||
|
<ParentRoute path=path!("admin") view=AdminShell>
|
||||||
|
<Route path=path!("home") view=AdminFallback />
|
||||||
|
<Route path=path!("testing") view=AdminTesting />
|
||||||
|
</ParentRoute>
|
||||||
|
}
|
||||||
|
.into_inner()
|
||||||
|
.into_any_nested_route()
|
||||||
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn AuthErrorView() -> impl IntoView {
|
pub fn AuthErrorView() -> impl IntoView {
|
||||||
let auth = use_context::<AuthSignal>().expect("AuthError: RwSignal<AuthStore> was not found");
|
let auth = use_context::<AuthSignal>().expect("AuthError: RwSignal<AuthStore> was not found");
|
||||||
|
|||||||
+2
-1
@@ -7,8 +7,9 @@ mod submit_status;
|
|||||||
mod user;
|
mod user;
|
||||||
mod value_type;
|
mod value_type;
|
||||||
pub mod animations;
|
pub mod animations;
|
||||||
|
mod tab_info;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
comparison::*, date_info::*, expandable_info::*, form_params::*, form_schema::*,
|
comparison::*, date_info::*, expandable_info::*, form_params::*, form_schema::*,
|
||||||
submit_status::*, user::*, value_type::*,
|
submit_status::*, user::*, value_type::*, tab_info::*,
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TabInfo {
|
||||||
|
pub name: String,
|
||||||
|
pub path: String,
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ pub fn Banner(
|
|||||||
title: String,
|
title: String,
|
||||||
/// The file path or URL of a logo displayed at the top left of the banner.
|
/// The file path or URL of a logo displayed at the top left of the banner.
|
||||||
#[prop(into)]
|
#[prop(into)]
|
||||||
logo: String,
|
logo: Signal<String>,
|
||||||
/// The route that the navigates user to a page (home page).
|
/// The route that the navigates user to a page (home page).
|
||||||
#[prop(into, optional)]
|
#[prop(into, optional)]
|
||||||
path: Signal<String>,
|
path: Signal<String>,
|
||||||
@@ -44,7 +44,7 @@ pub fn Banner(
|
|||||||
<div class="flex flex-row items-center gap-4 p-6 pb-2">
|
<div class="flex flex-row items-center gap-4 p-6 pb-2">
|
||||||
<div class="flex-shrink-0">
|
<div class="flex-shrink-0">
|
||||||
<img
|
<img
|
||||||
src=logo.clone()
|
src=logo
|
||||||
class="h-10 w-10 cursor-pointer"
|
class="h-10 w-10 cursor-pointer"
|
||||||
alt="icon"
|
alt="icon"
|
||||||
on:click=on_click
|
on:click=on_click
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
use leptos::prelude::*;
|
||||||
|
use crate::components::login::setup::provide_auth_context;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn AdminLoginContext(
|
||||||
|
children: Children
|
||||||
|
) -> impl IntoView {
|
||||||
|
provide_auth_context(
|
||||||
|
crate::utils::use_origin(),
|
||||||
|
"https://cognito-idp.us-east-1.amazonaws.com/us-east-1_Lfjuy5zaM",
|
||||||
|
"56c2bqvl021rv8d5mq36blt7jv",
|
||||||
|
"/providers/callback"
|
||||||
|
);
|
||||||
|
|
||||||
|
view! {
|
||||||
|
{children()}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
pub(crate) mod setup;
|
||||||
mod provider;
|
mod provider;
|
||||||
pub use provider::*;
|
pub use provider::*;
|
||||||
mod student;
|
mod student;
|
||||||
pub use student::*;
|
pub use student::*;
|
||||||
pub(crate) mod setup;
|
mod admin;
|
||||||
|
pub use admin::*;
|
||||||
@@ -13,9 +13,10 @@ mod lists;
|
|||||||
mod toasts;
|
mod toasts;
|
||||||
mod header;
|
mod header;
|
||||||
pub mod login;
|
pub mod login;
|
||||||
|
mod tabs;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
action_button::*, banner::*, dashboard_button::*, lists::*,
|
action_button::*, banner::*, dashboard_button::*, lists::*,
|
||||||
loading::*, multi_entry::*, panel::*, row::*, text_field::*,
|
loading::*, multi_entry::*, panel::*, row::*, text_field::*,
|
||||||
validated_form::*, toasts::*, header::*, date::*
|
validated_form::*, toasts::*, header::*, date::*, tabs::*
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod sidebar;
|
||||||
|
pub use sidebar::*;
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
use leptos::prelude::*;
|
||||||
|
use leptos_router::components::{Outlet, A};
|
||||||
|
use leptos_router::hooks::use_location;
|
||||||
|
use crate::common::TabInfo;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn SidebarTab(
|
||||||
|
#[prop(into)] name: 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())>
|
||||||
|
{name}
|
||||||
|
</div>
|
||||||
|
</A>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn TabSidebarList(
|
||||||
|
#[prop(into)] tabs: Signal<Vec<TabInfo>>,
|
||||||
|
) -> impl IntoView {
|
||||||
|
// Create a series of tabs based on a given list of names and paths.
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<div class="flex flex-row h-full w-full fixed">
|
||||||
|
<nav class="flex flex-col bg-red-900 w-64 h-full overflow-scroll">
|
||||||
|
<For
|
||||||
|
each=move || tabs.get()
|
||||||
|
key=|info| info.name.clone()
|
||||||
|
let(TabInfo {name, path})
|
||||||
|
>
|
||||||
|
<SidebarTab
|
||||||
|
name=name
|
||||||
|
path=path
|
||||||
|
/>
|
||||||
|
</For>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="flex flex-1">
|
||||||
|
<Outlet />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod shell;
|
||||||
|
pub use shell::*;
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
use leptos::prelude::*;
|
||||||
|
use crate::common::TabInfo;
|
||||||
|
use crate::components::{Banner, TabSidebarList};
|
||||||
|
use crate::components::login::AdminLoginContext;
|
||||||
|
|
||||||
|
/// # Admin Shell Component
|
||||||
|
///
|
||||||
|
/// This shell should keep track of pretty much everything that changes across the admin page. It
|
||||||
|
/// will provide the login context, the banner, and the tabs.
|
||||||
|
#[component]
|
||||||
|
pub fn AdminShell() -> impl IntoView {
|
||||||
|
// Create login context
|
||||||
|
view! {
|
||||||
|
<AdminLoginContext>
|
||||||
|
<Banner title="R15 Scholarships Admin" logo="/PHS_Stacked_Acronym.png" />
|
||||||
|
// We'll put the tabs here.
|
||||||
|
<TabSidebarList
|
||||||
|
tabs=vec![
|
||||||
|
TabInfo {
|
||||||
|
name: "Home".to_string(),
|
||||||
|
path: "/admin/home".to_string(),
|
||||||
|
},
|
||||||
|
TabInfo {
|
||||||
|
name: "Test".to_string(),
|
||||||
|
path: "/admin/testing".to_string(),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
/>
|
||||||
|
</AdminLoginContext>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn AdminFallback() -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<div>
|
||||||
|
<p class="mx-auto">"This is a fallback page"</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn AdminTesting() -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<div>
|
||||||
|
<p class="mx-auto">"This is a testing page"</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -10,9 +10,10 @@ mod unauthenticated_page;
|
|||||||
mod provider_contact;
|
mod provider_contact;
|
||||||
mod auth_callback;
|
mod auth_callback;
|
||||||
mod provider_applicants;
|
mod provider_applicants;
|
||||||
|
mod admin;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
about_page::*, comparison_test::*, home_page::*, loaner_page::*, provider_portal::*,
|
about_page::*, comparison_test::*, home_page::*, loaner_page::*, provider_portal::*,
|
||||||
test_page::*, unauthenticated_page::*, scholarship_info::*, provider_contact::*,
|
test_page::*, unauthenticated_page::*, scholarship_info::*, provider_contact::*,
|
||||||
auth_callback::*, provider_applicants::*
|
auth_callback::*, provider_applicants::*, admin::*
|
||||||
};
|
};
|
||||||
Reference in new issue
Block a user