Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add fallback prop to ProtectedRoute and ProtectedParentRoute #3264

Merged
merged 1 commit into from
Nov 20, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 23 additions & 10 deletions router/src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use crate::{
resolve_path::resolve_path,
ChooseView, MatchNestedRoutes, NestedRoute, RouteDefs, SsrMode,
};
use either_of::Either;
use leptos::prelude::*;
use either_of::EitherOf3;
use leptos::{children, prelude::*};
use reactive_graph::{
owner::{provide_context, use_context, Owner},
signal::ArcRwSignal,
Expand Down Expand Up @@ -386,6 +386,9 @@ pub fn ProtectedRoute<Segments, ViewFn, View, C, PathFn, P>(
condition: C,
/// The path that will be redirected to if the condition is `Some(false)`.
redirect_path: PathFn,
/// Will be displayed while the condition is pending. By default this is the empty view.
#[prop(optional, into)]
fallback: children::ViewFn,
/// The mode that this route prefers during server-side rendering.
/// Defaults to out-of-order streaming.
#[prop(optional)]
Expand All @@ -398,23 +401,26 @@ where
PathFn: Fn() -> P + Send + Clone + 'static,
P: Display + 'static,
{
let fallback = move || fallback.run();
let view = move || {
let condition = condition.clone();
let redirect_path = redirect_path.clone();
let view = view.clone();
let fallback = fallback.clone();
(view! {
<Transition>
<Transition fallback=fallback.clone()>
{move || {
let condition = condition();
let view = view.clone();
let redirect_path = redirect_path.clone();
let fallback = fallback.clone();
Unsuspend::new(move || match condition {
Some(true) => Either::Left(view()),
Some(true) => EitherOf3::A(view()),
#[allow(clippy::unit_arg)]
Some(false) => {
Either::Right(view! { <Redirect path=redirect_path()/> }.into_inner())
EitherOf3::B(view! { <Redirect path=redirect_path()/> }.into_inner())
}
None => Either::Right(()),
None => EitherOf3::C(fallback()),
})
}}

Expand All @@ -437,6 +443,9 @@ pub fn ProtectedParentRoute<Segments, ViewFn, View, C, PathFn, P, Children>(
/// the page, `Some(false)` means the user cannot access the page, and `None` means this
/// information is still loading.
condition: C,
/// Will be displayed while the condition is pending. By default this is the empty view.
#[prop(optional, into)]
fallback: children::ViewFn,
/// The path that will be redirected to if the condition is `Some(false)`.
redirect_path: PathFn,
/// Nested child routes.
Expand All @@ -453,17 +462,21 @@ where
PathFn: Fn() -> P + Send + Clone + 'static,
P: Display + 'static,
{
let fallback = move || fallback.run();
let children = children.into_inner();
let view = move || {
let condition = condition.clone();
let redirect_path = redirect_path.clone();
let fallback = fallback.clone();
let view = view.clone();
let owner = Owner::current().unwrap();
let view = {
let fallback = fallback.clone();
move || {
let condition = condition();
let view = view.clone();
let redirect_path = redirect_path.clone();
let fallback = fallback.clone();
let owner = owner.clone();
Unsuspend::new(move || match condition {
// reset the owner so that things like providing context work
Expand All @@ -472,16 +485,16 @@ where
//
// clippy: not redundant, a FnOnce vs FnMut issue
#[allow(clippy::redundant_closure)]
Some(true) => Either::Left(owner.with(|| view())),
Some(true) => EitherOf3::A(owner.with(|| view())),
#[allow(clippy::unit_arg)]
Some(false) => Either::Right(
Some(false) => EitherOf3::B(
view! { <Redirect path=redirect_path()/> }.into_inner(),
),
None => Either::Right(()),
None => EitherOf3::C(fallback()),
})
}
};
(view! { <Transition>{view}</Transition> }).into_any()
(view! { <Transition fallback>{view}</Transition> }).into_any()
};
NestedRoute::new(path, view).ssr_mode(ssr).child(children)
}
Expand Down
Loading