From 7aa4d9e6db30066a46b050d9a6326352f86bf413 Mon Sep 17 00:00:00 2001 From: Kaszanas <34846245+Kaszanas@users.noreply.github.com> Date: Fri, 31 Mar 2023 20:50:46 +0200 Subject: [PATCH] feat: Added ` component to route file (#741) --- router/src/components/route.rs | 124 +++++++++++++++++++++++---------- 1 file changed, 86 insertions(+), 38 deletions(-) diff --git a/router/src/components/route.rs b/router/src/components/route.rs index d36936639..7a4a62143 100644 --- a/router/src/components/route.rs +++ b/router/src/components/route.rs @@ -34,44 +34,7 @@ where F: Fn(Scope) -> E + 'static, P: std::fmt::Display, { - fn inner( - cx: Scope, - children: Option, - path: String, - view: Rc View>, - ssr_mode: SsrMode, - ) -> RouteDefinition { - let children = children - .map(|children| { - children(cx) - .as_children() - .iter() - .filter_map(|child| { - child - .as_transparent() - .and_then(|t| t.downcast_ref::()) - }) - .cloned() - .collect::>() - }) - .unwrap_or_default(); - - let id = ROUTE_ID.with(|id| { - let next = id.get() + 1; - id.set(next); - next - }); - - RouteDefinition { - id, - path, - children, - view, - ssr_mode, - } - } - - inner( + define_route( cx, children, path.to_string(), @@ -80,6 +43,91 @@ where ) } +/// Describes a route that is guarded by a certain condition. This works the same way as +/// [``](Route), except that if the `condition` function evaluates to `false`, it +/// redirects to `redirect_path` instead of displaying its `view`. +#[component(transparent)] +pub fn ProtectedRoute( + cx: Scope, + /// The path fragment that this route should match. This can be static (`users`), + /// include a parameter (`:id`) or an optional parameter (`:id?`), or match a + /// wildcard (`user/*any`). + path: P, + /// The path that will be redirected to if the condition is `false`. + redirect_path: P, + /// Condition function that returns a boolean. + condition: C, + /// View that will be exposed if the condition is `true`. + view: F, + /// The mode that this route prefers during server-side rendering. Defaults to out-of-order streaming. + #[prop(optional)] + ssr: SsrMode, + /// `children` may be empty or include nested routes. + #[prop(optional)] + children: Option, +) -> impl IntoView +where + E: IntoView, + F: Fn(Scope) -> E + 'static, + P: std::fmt::Display + 'static, + C: Fn(Scope) -> bool + 'static, +{ + use crate::{Redirect, RedirectProps}; + let redirect_path = redirect_path.to_string(); + + define_route( + cx, + children, + path.to_string(), + Rc::new(move |cx| { + if condition(cx) { + view(cx).into_view(cx) + } else { + view! { cx, } + .into_view(cx) + } + }), + ssr, + ) +} + +pub(crate) fn define_route( + cx: Scope, + children: Option, + path: String, + view: Rc View>, + ssr_mode: SsrMode, +) -> RouteDefinition { + let children = children + .map(|children| { + children(cx) + .as_children() + .iter() + .filter_map(|child| { + child + .as_transparent() + .and_then(|t| t.downcast_ref::()) + }) + .cloned() + .collect::>() + }) + .unwrap_or_default(); + + let id = ROUTE_ID.with(|id| { + let next = id.get() + 1; + id.set(next); + next + }); + + RouteDefinition { + id, + path, + children, + view, + ssr_mode, + } +} + impl IntoView for RouteDefinition { fn into_view(self, cx: Scope) -> View { Transparent::new(self).into_view(cx)