Skip to content

Commit

Permalink
<PrivateSet> (#9303)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobbe authored and jtoar committed Oct 28, 2023
1 parent e5f5ddd commit c83a1f5
Show file tree
Hide file tree
Showing 8 changed files with 579 additions and 261 deletions.
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/unsupported-route-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ESLintUtils } from '@typescript-eslint/utils'
const createRule = ESLintUtils.RuleCreator.withoutDocs

function isAllowedElement(name: string) {
const allowedElements = ['Router', 'Route', 'Set', 'Private']
const allowedElements = ['Router', 'Route', 'Set', 'PrivateSet', 'Private']
return allowedElements.includes(name)
}

Expand All @@ -16,7 +16,7 @@ export const unsupportedRouteComponents = createRule({
},
messages: {
unexpected:
'Unexpected JSX element <{{name}}>. Only <Router>, <Route>, <Set> and <Private> are allowed in the Routes file.',
'Unexpected JSX element <{{name}}>. Only <Router>, <Route>, <Set>, <PrivateSet> and <Private> are allowed in the Routes file.',
},
schema: [], // No additional configuration needed
},
Expand Down
29 changes: 9 additions & 20 deletions packages/router/src/AuthenticatedRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,16 @@ import type { GeneratedRoutesMap } from './util'
interface AuthenticatedRouteProps {
children: React.ReactNode
roles?: string | string[]
unauthenticated?: keyof GeneratedRoutesMap
unauthenticated: keyof GeneratedRoutesMap
whileLoadingAuth?: () => React.ReactElement | null
private?: boolean
}
export const AuthenticatedRoute: React.FC<AuthenticatedRouteProps> = (
props
) => {
const {
private: isPrivate,
unauthenticated,
roles,
whileLoadingAuth,
children,
} = props

export const AuthenticatedRoute: React.FC<AuthenticatedRouteProps> = ({
unauthenticated,
roles,
whileLoadingAuth,
children,
}) => {
const routerState = useRouterState()
const {
loading: authLoading,
Expand All @@ -34,14 +30,7 @@ export const AuthenticatedRoute: React.FC<AuthenticatedRouteProps> = (
}, [isAuthenticated, roles, hasRole])

// Make sure `wrappers` is always an array with at least one wrapper component
if (isPrivate && unauthorized()) {
if (!unauthenticated) {
throw new Error(
'Private Sets need to specify what route to redirect unauthorized ' +
'users to by setting the `unauthenticated` prop'
)
}

if (unauthorized()) {
if (authLoading) {
return whileLoadingAuth?.() || null
} else {
Expand Down
28 changes: 23 additions & 5 deletions packages/router/src/Set.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ReactElement, ReactNode } from 'react'
import React from 'react'
import * as React from 'react'

export type WrapperType<WTProps> = (
props: WTProps & { children: ReactNode }
Expand All @@ -12,9 +12,11 @@ type SetProps<P> = P & {
// <Set<{theme: string}> wrap={ThemeableLayout} theme="dark">
wrap?: WrapperType<P> | WrapperType<P>[]
/**
* `Routes` nested in a `<Set>` with `private` specified require
*`Routes` nested in a `<Set>` with `private` specified require
* authentication. When a user is not authenticated and attempts to visit
* the wrapped route they will be redirected to `unauthenticated` route.
*
* @deprecated Please use `<PrivateSet>` instead
*/
private?: boolean
/** The page name where a user will be redirected when not authenticated */
Expand Down Expand Up @@ -45,7 +47,7 @@ export function Set<WrapperProps>(_props: SetProps<WrapperProps>) {
return null
}

type PrivateProps<P> = Omit<
type PrivateSetProps<P> = Omit<
SetProps<P>,
'private' | 'unauthenticated' | 'wrap'
> & {
Expand All @@ -54,7 +56,16 @@ type PrivateProps<P> = Omit<
wrap?: WrapperType<P> | WrapperType<P>[]
}

export function Private<WrapperProps>(_props: PrivateProps<WrapperProps>) {
/** @deprecated Please use `<PrivateSet>` instead */
export function Private<WrapperProps>(_props: PrivateSetProps<WrapperProps>) {
// @MARK Virtual Component, this is actually never rendered
// See analyzeRoutes in utils.tsx, inside the isSetNode block
return null
}

export function PrivateSet<WrapperProps>(
_props: PrivateSetProps<WrapperProps>
) {
// @MARK Virtual Component, this is actually never rendered
// See analyzeRoutes in utils.tsx, inside the isSetNode block
return null
Expand All @@ -64,10 +75,17 @@ export const isSetNode = (
node: ReactNode
): node is ReactElement<SetProps<any>> => {
return (
React.isValidElement(node) && (node.type === Set || node.type === Private)
React.isValidElement(node) &&
(node.type === Set || node.type === PrivateSet || node.type === Private)
)
}

export const isPrivateSetNode = (
node: ReactNode
): node is ReactElement<PrivateSetProps<unknown>> => {
return React.isValidElement(node) && node.type === PrivateSet
}

// Only identifies <Private> nodes, not <Set private> nodes
export const isPrivateNode = (
node: ReactNode
Expand Down
Loading

0 comments on commit c83a1f5

Please sign in to comment.