소스 검색

createPrivateRoute HOC

asmer 3 달 전
부모
커밋
f5978d4d6e
3개의 변경된 파일50개의 추가작업 그리고 2개의 파일을 삭제
  1. 6 1
      src/App.tsx
  2. 1 1
      src/lib/index.ts
  3. 43 0
      src/lib/router/index.tsx

+ 6 - 1
src/App.tsx

@@ -4,7 +4,7 @@ import viteLogo from '/vite.svg'
 import './App.css'
 import {createBrowserHistory} from 'history';
 import {Router} from 'react-router-dom'
-import {NamedRoute, NamedLink, HashRoute} from './lib';
+import {NamedRoute, NamedLink, HashRoute, createPrivateRoute} from './lib';
 
 const history = createBrowserHistory()
 
@@ -40,6 +40,10 @@ const queries = {
 const Pending = () => <h1>Loading</h1>
 const Error   = ({error}) => <h1>Error: {error.message}</h1>
 
+const UserNamedRoute = createPrivateRoute(() => ['user'], history => history.goBack())(NamedRoute)
+
+const Dashboard = () => <h1>dashboard</h1>
+
 
 function App() {
   return (
@@ -56,6 +60,7 @@ function App() {
                     errorQueryComponent={Error}
                     path="/planet/:id" 
                     component={SwapiPlanet}/>
+        <UserNamedRoute routeName="dashboard" path="/dashboard" component={Dashboard} roles={['admin']} />
       </div>
       <p className="read-the-docs">
         <NamedLink routeName="people" params={{id: 1}}>Luke</NamedLink>

+ 1 - 1
src/lib/index.ts

@@ -4,4 +4,4 @@ export {createPub};
 
 export type { Pub } from  './pub'
 export { usePub } from  './pub'
-export {NamedRoute, NamedLink, HashRoute} from './router'
+export {NamedRoute, NamedLink, HashRoute, createPrivateRoute} from './router'

+ 43 - 0
src/lib/router/index.tsx

@@ -77,6 +77,49 @@ export const HashRoute = ({component, render, ...props}) => {
     return <Render match={match} history={history} location={location} />
 }
 
+type GetUserRolesFunc = () => Array<string>
+
+export const createPrivateRoute = (getUserRoles:GetUserRolesFunc, defaultFallback:string|Function, defaultRouteRoles:string[]):Function => 
+    (RouteComponent:ComponentType):ComponentType => 
+        ({fallback, roles=[], render, component, ...props}) => {
+            const Render:ComponentType = component || render 
+
+            const intersectArrays = (first:Array<any>, second:Array<any>) => 
+                first.find(firstItem => second.find(secondItem => firstItem === secondItem))
+
+            const ComponentWrapper:ComponentType = (props) => {
+                fallback               ||= defaultFallback
+                roles:Array<string>    ||= defaultRouteRoles
+
+                const userRoles:Array<string> = getUserRoles()
+
+                if (!fallback){
+                    throw new ReferenceError('fallback or defaultFallback are mandatory for Private Route')
+                }
+
+                if (!intersectArrays(roles, userRoles)){
+                    if (typeof fallback === 'string')
+                        props.history.push(fallback)
+                    if (typeof fallback === 'function')
+                        fallback(props.history, props)
+                    return null;
+                }
+
+
+                return <Render {...props} />
+            }
+
+            if (!getUserRoles || typeof getUserRoles !== 'function'){
+                throw new ReferenceError('getUserRoles are mandatory for Private Routing and it should be a function')
+            }
+
+            return <RouteComponent {...props} component={ComponentWrapper}/>
+        }
+
+console.log(createPrivateRoute)
+
+    
+
 //export const HashNamedRoute = ({name, routeName, query, pendingQueryComponent:P, errorQueryComponent:E, errorQueryComponentErrorProp="error", componentQueryResultProp='data', path, component, render, ...props}) => {