Skip to content

Commit

Permalink
refactor router
Browse files Browse the repository at this point in the history
  • Loading branch information
Bender101 committed Nov 19, 2023
1 parent 6843803 commit 0d7cabc
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 91 deletions.
Original file line number Diff line number Diff line change
@@ -1,47 +1,15 @@
import { RouteProps } from "react-router-dom";
import { MainPage } from "@/pages/MainPage";
import { AboutPage } from "@/pages/AboutPage";
import { NotFoundPage } from "@/pages/NotFoundPage";
import { ProfilePage } from "@/pages/ProfilePage";
import { ArticlesPage } from "@/pages/ArticlesPage";
import { ArticleDetailsPage } from "@/pages/ArticleDetailsPage";
import { ArticleEditPage } from "@/pages/ArticleEditPage";
import { AdminPanelPage } from "@/pages/AdminPanelPage";
import { UserRole } from "@/entities/User";
import { ForbiddenPage } from "@/pages/ForbiddenPage";

export type AppRoutesProps = RouteProps & {
authOnly?: boolean;
roles?: UserRole[];
};

export enum AppRoutes {
MAIN = "main",
ABOUT = "about",
PROFILE = "profile",
ARTICLES = "articles",
ARTICLES_DETAILS = "article_details",
ARTICLE_CREATE = "article_create",
ARTICLE_EDIT = "article_edit",
ADMIN_PANEL = "admin_panel",
FORBIDDEN = "forbidden",
// last
NOT_FOUND = "not_found",
}

export const RoutePath: Record<AppRoutes, string> = {
[AppRoutes.MAIN]: "/",
[AppRoutes.ABOUT]: "/about",
[AppRoutes.PROFILE]: "/profile/",
[AppRoutes.ARTICLES]: "/articles",
[AppRoutes.ARTICLES_DETAILS]: "/articles/",
[AppRoutes.ARTICLE_CREATE]: "/articles/new",
[AppRoutes.ARTICLE_EDIT]: "/articles/:id/edit",
[AppRoutes.ADMIN_PANEL]: "/admin",
[AppRoutes.FORBIDDEN]: "/forbidden",

[AppRoutes.NOT_FOUND]: "*",
};
import { NotFoundPage } from "@/pages/NotFoundPage";
import { AppRoutes, RoutePath } from "@/shared/const/router";
import { AppRoutesProps } from "@/shared/types/router";

export const routeConfig: Record<AppRoutes, AppRoutesProps> = {
[AppRoutes.MAIN]: {
Expand Down
12 changes: 7 additions & 5 deletions src/app/providers/router/ui/AppRouter.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React, { memo, Suspense, useCallback } from "react";
import { Route, Routes } from "react-router-dom";
import {
AppRoutesProps,
routeConfig,
} from "@/shared/config/routeConfig/routeConfig";
import { PageLoader } from "@/widgets/PageLoader";
import { RequireAuth } from "./RequireAuth";
import { routeConfig } from "@/app/providers/router/config/routeConfig";
import { AppRoutesProps } from "@/shared/types/router";

const AppRouter = () => {
const renderWithWrapper = useCallback((route: AppRoutesProps) => {
Expand All @@ -17,7 +15,11 @@ const AppRouter = () => {
key={route.path}
path={route.path}
element={
route.authOnly ? <RequireAuth roles={route.roles}>{element}</RequireAuth> : element
route.authOnly ? (
<RequireAuth roles={route.roles}>{element}</RequireAuth>
) : (
element
)
}
/>
);
Expand Down
6 changes: 4 additions & 2 deletions src/app/providers/router/ui/RequireAuth.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useSelector } from "react-redux";
import { getUserAuthData, getUserRoles, UserRole } from "@/entities/User";
import { Navigate, useLocation } from "react-router-dom";
import { RoutePath } from "@/shared/config/routeConfig/routeConfig";
import { useMemo } from "react";
import { RoutePath } from "@/shared/const/router";

export interface RequireAuthProps {
roles?: UserRole[];
Expand All @@ -28,7 +28,9 @@ export function RequireAuth({ children, roles }: RequireAuthProps) {
}

if (!hasRequiredRoles) {
return <Navigate to={RoutePath.forbidden} state={{ from: location }} replace />;
return (
<Navigate to={RoutePath.forbidden} state={{ from: location }} replace />
);
}

return children;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import EyeIcon from "@/shared/assets/icons/eye-20-20.svg";
import { Card } from "@/shared/ui/Card/Card";
import { Avatar } from "@/shared/ui/Avatar/Avatar";
import { Button, ButtonTheme } from "@/shared/ui/Button/Button";
import { RoutePath } from "@/shared/config/routeConfig/routeConfig";
import cls from "./ArticleListItem.module.scss";
import { Article, ArticleTextBlock } from "../../model/types/article";
import { ArticleTextBlockComponent } from "../ArticleTextBlockComponent/ArticleTextBlockComponent";
import { AppLink } from "@/shared/ui/AppLink/AppLink";
import { ArticleBlockType, ArticleView } from "../../model/consts/consts";
import {RoutePath} from "@/shared/const/router";

interface ArticleListItemProps {
className?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/entities/Comment/ui/CommentCard/CommentCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { Skeleton } from "@/shared/ui/Skeleton/Skeleton";
import cls from "./CommentCard.module.scss";
import { Comment } from "../../model/types/comment";
import { AppLink } from "@/shared/ui/AppLink/AppLink";
import { RoutePath } from "@/shared/config/routeConfig/routeConfig";
import { VStack } from "@/shared/ui/Stack";
import {RoutePath} from "@/shared/const/router";

interface CommentCardProps {
className?: string;
Expand Down
95 changes: 51 additions & 44 deletions src/features/avatarDropdown/ui/AvatarDropdown/AvatarDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,62 @@
import { classNames } from '@/shared/lib/classNames/classNames';
import { useTranslation } from 'react-i18next';
import React, { memo, useCallback } from 'react';
import { RoutePath } from '@/shared/config/routeConfig/routeConfig';
import { Avatar } from '@/shared/ui/Avatar/Avatar';
import { Dropdown } from '@/shared/ui/Popups';
import { useDispatch, useSelector } from 'react-redux';
import { classNames } from "@/shared/lib/classNames/classNames";
import { useTranslation } from "react-i18next";
import React, { memo, useCallback } from "react";
import { Avatar } from "@/shared/ui/Avatar/Avatar";
import { Dropdown } from "@/shared/ui/Popups";
import { useDispatch, useSelector } from "react-redux";
import {
getUserAuthData, isUserAdmin, isUserManager, userActions,
} from '@/entities/User';
getUserAuthData,
isUserAdmin,
isUserManager,
userActions,
} from "@/entities/User";
import { RoutePath } from "@/shared/const/router";

interface AvatarDropdownProps {
className?: string;
className?: string;
}

export const AvatarDropdown = memo((props: AvatarDropdownProps) => {
const { className } = props;
const { t } = useTranslation();
const dispatch = useDispatch();
const isAdmin = useSelector(isUserAdmin);
const isManager = useSelector(isUserManager);
const authData = useSelector(getUserAuthData);
const { className } = props;
const { t } = useTranslation();
const dispatch = useDispatch();
const isAdmin = useSelector(isUserAdmin);
const isManager = useSelector(isUserManager);
const authData = useSelector(getUserAuthData);

const onLogout = useCallback(() => {
dispatch(userActions.logout());
}, [dispatch]);
const onLogout = useCallback(() => {
dispatch(userActions.logout());
}, [dispatch]);

const isAdminPanelAvailable = isAdmin || isManager;
const isAdminPanelAvailable = isAdmin || isManager;

if (!authData) {
return null;
}
if (!authData) {
return null;
}

return (
<Dropdown
direction="bottom left"
className={classNames('', {}, [className])}
items={[
...(isAdminPanelAvailable ? [{
content: t('Админка'),
href: RoutePath.admin_panel,
}] : []),
{
content: t('Профиль'),
href: RoutePath.profile + authData.id,
},
{
content: t('Выйти'),
onClick: onLogout,
},
]}
trigger={<Avatar size={30} src={authData.avatar} />}
/>
);
return (
<Dropdown
direction="bottom left"
className={classNames("", {}, [className])}
items={[
...(isAdminPanelAvailable
? [
{
content: t("Админка"),
href: RoutePath.admin_panel,
},
]
: []),
{
content: t("Профиль"),
href: RoutePath.profile + authData.id,
},
{
content: t("Выйти"),
onClick: onLogout,
},
]}
trigger={<Avatar size={30} src={authData.avatar} />}
/>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { classNames } from "@/shared/lib/classNames/classNames";
import { useTranslation } from "react-i18next";
import { memo, useCallback } from "react";
import { useNavigate } from "react-router-dom";
import { RoutePath } from "@/shared/config/routeConfig/routeConfig";
import { Button, ButtonTheme } from "@/shared/ui/Button/Button";
import { useSelector } from "react-redux";
import { getArticleDetailsData } from "@/entities/Article";
import { getCanEditArticle } from "../../model/selectors/article";
import { HStack } from "@/shared/ui/Stack";
import {RoutePath} from "@/shared/const/router";

interface ArticleDetailsPageHeaderProps {
className?: string;
Expand Down
27 changes: 27 additions & 0 deletions src/shared/const/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export enum AppRoutes {
MAIN = "main",
ABOUT = "about",
PROFILE = "profile",
ARTICLES = "articles",
ARTICLES_DETAILS = "article_details",
ARTICLE_CREATE = "article_create",
ARTICLE_EDIT = "article_edit",
ADMIN_PANEL = "admin_panel",
FORBIDDEN = "forbidden",
// last
NOT_FOUND = "not_found",
}

export const RoutePath: Record<AppRoutes, string> = {
[AppRoutes.MAIN]: "/",
[AppRoutes.ABOUT]: "/about",
[AppRoutes.PROFILE]: "/profile/",
[AppRoutes.ARTICLES]: "/articles",
[AppRoutes.ARTICLES_DETAILS]: "/articles/",
[AppRoutes.ARTICLE_CREATE]: "/articles/new",
[AppRoutes.ARTICLE_EDIT]: "/articles/:id/edit",
[AppRoutes.ADMIN_PANEL]: "/admin",
[AppRoutes.FORBIDDEN]: "/forbidden",

[AppRoutes.NOT_FOUND]: "*",
};
7 changes: 7 additions & 0 deletions src/shared/types/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {RouteProps} from "react-router-dom";
import {UserRole} from "src/entities/User";

export type AppRoutesProps = RouteProps & {
authOnly?: boolean;
roles?: UserRole[];
};
2 changes: 1 addition & 1 deletion src/widgets/Navbar/ui/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { useSelector } from "react-redux";
import { getUserAuthData } from "@/entities/User";
import { Text, TextTheme } from "@/shared/ui/Text/Text";
import { AppLink, AppLinkTheme } from "@/shared/ui/AppLink/AppLink";
import { RoutePath } from "@/shared/config/routeConfig/routeConfig";
import { HStack } from "@/shared/ui/Stack";
import { NotificationButton } from "@/features/notificationButton";
import { AvatarDropdown } from "@/features/avatarDropdown";
import { RoutePath } from "@/shared/const/router";

interface NavbarProps {
className?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/SideBar/model/selectors/getSideBarItems.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { createSelector } from "@reduxjs/toolkit";
import { getUserAuthData } from "@/entities/User";
import { RoutePath } from "@/shared/config/routeConfig/routeConfig";
import AboutIcon from "@/shared/assets/icons/About.svg";
import MainIcon from "@/shared/assets/icons/Home.svg";
import ProfileIcon from "@/shared/assets/icons/profile-20-20.svg";
import ArticleIcon from "@/shared/assets/icons/article-20-20.svg";
import { SidebarItemType } from "../types/sidebar";
import { RoutePath } from "@/shared/const/router";

export const getSideBarItems = createSelector(getUserAuthData, (userData) => {
const sidebarItemsList: SidebarItemType[] = [
Expand Down

0 comments on commit 0d7cabc

Please sign in to comment.