Skip to content

Commit

Permalink
PrivateSet
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobbe committed Oct 15, 2023
1 parent 8931199 commit 20ff2d5
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 66 deletions.
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
65 changes: 54 additions & 11 deletions packages/router/src/__tests__/analyzeRoutes.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { isValidElement } from 'react'

import { Route, Router } from '../router'
import { Private, Set } from '../Set'
import { Private, PrivateSet, Set } from '../Set'
import { analyzeRoutes } from '../util'

const FakePage = () => <h1>Fake Page</h1>
Expand Down Expand Up @@ -106,14 +106,26 @@ describe('AnalyzeRoutes: with homePage and Children', () => {
})

test('Creates setWrapper map', () => {
const WrapperX = ({ children }) => (
interface WrapperXProps {
children: React.ReactNode
id: string
passThruProp: string
}

const WrapperX = ({ children }: WrapperXProps) => (
<>
<h1>WrapperA</h1>
{children}
</>
)

const WrapperY = ({ children }) => (
interface WrapperYProps {
children: React.ReactNode
id: string
theme: string
}

const WrapperY = ({ children }: WrapperYProps) => (
<>
<h1>WrapperY</h1>
{children}
Expand Down Expand Up @@ -196,7 +208,7 @@ describe('AnalyzeRoutes: with homePage and Children', () => {

test('Creates setWrapper map with nested sets', () => {
const KrismasTree = (
<Private unauthenticated="signIn">
<PrivateSet unauthenticated="signIn">
<Route path="/dashboard" page={FakePage} name="dashboard" />
<Set wrap={[FakeLayout1, FakeLayout2]}>
<Route
Expand Down Expand Up @@ -254,7 +266,7 @@ describe('AnalyzeRoutes: with homePage and Children', () => {
/>
</Set>
</Set>
</Private>
</PrivateSet>
)

const { pathRouteMap } = analyzeRoutes(KrismasTree.props.children, {
Expand Down Expand Up @@ -297,6 +309,37 @@ describe('AnalyzeRoutes: with homePage and Children', () => {
})
})

test('Handles PrivateSet', () => {
const Routes = (
<Router>
<Route path="/" name="home" page={FakePage} />
<PrivateSet unauthenticated="home">
<Route path="/private" name="privateRoute" page={FakePage} />
</PrivateSet>
</Router>
)

const { pathRouteMap } = analyzeRoutes(Routes.props.children, {
currentPathName: '/',
})

expect(pathRouteMap['/private']).toStrictEqual({
redirect: null,
name: 'privateRoute',
path: '/private',
whileLoadingPage: undefined,
page: FakePage,
wrappers: [],
setId: 1,
setProps: [
{
private: true,
unauthenticated: 'home',
},
],
})
})

test('Redirect routes analysis', () => {
const RedirectedRoutes = (
<Router>
Expand Down Expand Up @@ -334,7 +377,7 @@ describe('AnalyzeRoutes: with homePage and Children', () => {
const RedirectedRoutes = (
<Router>
<Route path="/" page={HomePage} name="home" />
<Private unauthenticated="home">
<PrivateSet unauthenticated="home">
<Route
path="/no-roles-assigned"
page={PrivateNoRolesAssigned}
Expand All @@ -346,23 +389,23 @@ describe('AnalyzeRoutes: with homePage and Children', () => {
roles={['ADMIN', 'EMPLOYEE']}
someProp="propFromNoRolesSet"
>
<Private unauthenticated="admin" roles={'EMPLOYEE'}>
<PrivateSet unauthenticated="admin" roles={'EMPLOYEE'}>
<Route
path="/employee"
page={PrivateEmployeePage}
name="privateEmployee"
/>
</Private>
</PrivateSet>

<Private unauthenticated="employee" roles={'ADMIN'}>
<PrivateSet unauthenticated="employee" roles={'ADMIN'}>
<Route
path="/admin"
page={PrivateAdminPage}
name="privateAdmin"
/>
</Private>
</PrivateSet>
</Set>
</Private>
</PrivateSet>
</Router>
)

Expand Down
Loading

0 comments on commit 20ff2d5

Please sign in to comment.