Skip to content

Commit

Permalink
routes: refactor private and public route elements
Browse files Browse the repository at this point in the history
The routes are now components that wrap a route to make sure
required permissions are granted. These components can use the auth
state directly to know if the person is authenticated or get the current
user. This avoids having to pass them as props and simplifies the
components.
  • Loading branch information
tahini committed Feb 6, 2025
1 parent d175049 commit 8dae1e2
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,39 @@
* This file is licensed under the MIT License.
* License text available at https://opensource.org/licenses/MIT
*/
import React, { PropsWithChildren } from 'react';
import React from 'react';
import { Navigate, RouteProps } from 'react-router';

import config from 'chaire-lib-common/lib/config/shared/project.config';
import { Header } from '../pageParts';
import { CliUser } from 'chaire-lib-common/lib/services/user/userType';
import { useSelector } from 'react-redux';
import { AuthState } from '../../store/auth';

export type PrivateRouteProps = RouteProps & {
isAuthenticated: boolean;
component: any;
componentProps: { [prop: string]: unknown };
user: CliUser;
componentProps?: { [prop: string]: unknown };
permissions?: { [subject: string]: string | string[] };
config?: { [key: string]: unknown };
} & PropsWithChildren;
};

const PrivateRoute = ({ permissions, component: Component, ...rest }: PrivateRouteProps) => {
const auth = useSelector((state: { auth: AuthState }) => ({
isAuthenticated: !!state.auth.isAuthenticated,
user: state.auth.user
}));

const PrivateRoute = ({ permissions, component: Component, children: _children, ...rest }: PrivateRouteProps) => {
return rest.isAuthenticated ? (
return auth.isAuthenticated && auth.user ? (
permissions ? (
rest.user.isAuthorized(permissions) ? (
auth.user.isAuthorized(permissions) ? (
<React.Fragment>
<Header path={rest.path as string} appName={rest.config?.appName as string} />
<Header path={rest.path as string} appName={config?.appName as string} />
<Component {...rest.componentProps} />
</React.Fragment>
) : (
<Navigate to="/unauthorized" />
)
) : (
<React.Fragment>
<Header path={rest.path as string} appName={rest.config?.appName as string} />
<Header path={rest.path as string} appName={config?.appName as string} />
<Component {...rest.componentProps} />
</React.Fragment>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,22 @@
* This file is licensed under the MIT License.
* License text available at https://opensource.org/licenses/MIT
*/
import React, { PropsWithChildren } from 'react';
import React from 'react';
import { RouteProps } from 'react-router';
import { CliUser } from 'chaire-lib-common/lib/services/user/userType';

import config from 'chaire-lib-common/lib/config/shared/project.config';
import { Header } from '../pageParts';

/*const mapStateToProps = (state) => ({
isAuthenticated: !!state.auth.uuid
});*/
type PublicRouteProps = RouteProps & {
isAuthenticated: boolean;
component: any;
componentProps?: { [prop: string]: unknown };
user?: CliUser;
config?: { [key: string]: unknown };
} & PropsWithChildren;

const PublicRoute = ({ component: Component, children: _children, ...rest }: PublicRouteProps) => {
return (
<React.Fragment>
<Header path={rest.path as string} appName={rest.config?.appName as string} />
<Component {...rest.componentProps} config={rest.config} />
</React.Fragment>
);
};

const PublicRoute = ({ component: Component, children: _children, ...rest }: PublicRouteProps) => (
<React.Fragment>
<Header path={rest.path as string} appName={config?.appName as string} />
<Component {...rest.componentProps} config={config} />
</React.Fragment>
);

export default PublicRoute;
2 changes: 1 addition & 1 deletion packages/transition-frontend/src/app-transition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const jsx = (
<Provider store={store}>
<I18nextProvider i18n={i18n}>
<BrowserRouter>
<TransitionRouter contributions={contributions} config={config} mainMap={MainMap as any} />
<TransitionRouter contributions={contributions} mainMap={MainMap as any} />
</BrowserRouter>
</I18nextProvider>
</Provider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/
import React from 'react';
import { Route, Routes } from 'react-router';
import { useSelector } from 'react-redux';

import DashboardTransition from '../dashboard/TransitionDashboard';
import { MainMapProps } from '../map/TransitionMainMap';
Expand All @@ -25,130 +24,51 @@ import { DashboardContribution } from 'chaire-lib-frontend/lib/services/dashboar
type TransitionRouterProps = {
contributions: DashboardContribution[];
mainMap: React.ComponentType<MainMapProps>;
config: any;
};

const TransitionRouter: React.FunctionComponent<TransitionRouterProps> = (props: TransitionRouterProps) => {
//const navigate = useNavigate();
//const location = useLocation();
const auth = useSelector((state: any) => ({
isAuthenticated: state.auth.isAuthenticated,
user: state.auth.user
}));

return (
<Routes>
<Route
path="/register"
element={
<PublicRoute
isAuthenticated={auth.isAuthenticated}
component={RegisterPage}
config={{ ...props.config, queryString: location.search }}
/>
}
/>
<Route
path="/forgot"
element={
<PublicRoute
isAuthenticated={auth.isAuthenticated}
component={ForgotPage}
config={{ ...props.config, queryString: location.search }}
/>
}
/>
<Route
path="/unconfirmed"
element={
<PublicRoute
isAuthenticated={auth.isAuthenticated}
component={UnconfirmedPage}
config={{ ...props.config, queryString: location.search }}
/>
}
/>
<Route
path="/verify/:token"
element={
<PublicRoute
isAuthenticated={auth.isAuthenticated}
component={VerifyPage}
config={{ ...props.config, queryString: location.search }}
/>
}
/>
<Route
path="/reset/:token"
element={
<PublicRoute
isAuthenticated={auth.isAuthenticated}
component={ResetPasswordPage}
config={{ ...props.config, queryString: location.search }}
/>
}
/>
<Route
path="/unauthorized"
element={
<PublicRoute
isAuthenticated={auth.isAuthenticated}
component={UnauthorizedPage}
config={{ ...props.config, queryString: location.search }}
/>
}
/>
<Route
path="/login"
element={
<PublicRoute isAuthenticated={auth.isAuthenticated} component={LoginPage} config={props.config} />
}
/>
<Route path="/register" element={<PublicRoute component={RegisterPage} />} />
<Route path="/forgot" element={<PublicRoute component={ForgotPage} />} />
<Route path="/unconfirmed" element={<PublicRoute component={UnconfirmedPage} />} />
<Route path="/verify/:token" element={<PublicRoute component={VerifyPage} />} />
<Route path="/reset/:token" element={<PublicRoute component={ResetPasswordPage} />} />
<Route path="/unauthorized" element={<PublicRoute component={UnauthorizedPage} />} />
<Route path="/login" element={<PublicRoute component={LoginPage} />} />
<Route
path="/"
element={
<PrivateRoute
isAuthenticated={auth.isAuthenticated}
user={auth.user}
component={DashboardTransition}
componentProps={{ contributions: props.contributions, mainMap: props.mainMap }}
config={props.config}
/>
}
/>
<Route
path="/"
element={
<PrivateRoute
isAuthenticated={auth.isAuthenticated}
user={auth.user}
component={DashboardTransition}
componentProps={{ contributions: props.contributions, mainMap: props.mainMap }}
config={props.config}
/>
}
/>
<Route
path="/dashboard"
element={
<PrivateRoute
isAuthenticated={auth.isAuthenticated}
user={auth.user}
component={DashboardTransition}
componentProps={{ contributions: props.contributions, mainMap: props.mainMap }}
config={props.config}
/>
}
/>
<Route
path="/home"
element={
<PrivateRoute
isAuthenticated={auth.isAuthenticated}
user={auth.user}
component={DashboardTransition}
componentProps={{ contributions: props.contributions, mainMap: props.mainMap }}
config={props.config}
/>
}
/>
Expand Down

0 comments on commit 8dae1e2

Please sign in to comment.