From b2fc0bfade96e6de4f1a1045faa61ed429cd8506 Mon Sep 17 00:00:00 2001 From: ridhlab Date: Thu, 28 Dec 2023 13:45:15 +0700 Subject: [PATCH] feat: add layout and additional pages --- package.json | 1 + src/assets/hoc/withTooltip.tsx | 8 ++ src/components/layout/Avatar.tsx | 47 +++++++++ src/index.css | 2 +- src/layouts/MainLayout.tsx | 155 +++++++++++++++++++++++++++++ src/main.tsx | 16 ++- src/pages/Dashboard/index.tsx | 10 +- src/pages/Result/index.tsx | 13 +++ src/pages/VariableInput/index.tsx | 13 +++ src/pages/VariableOutput/index.tsx | 13 +++ src/routes/index.tsx | 47 +++++++-- src/routes/routes.ts | 4 + src/themes/config.ts | 13 +++ yarn.lock | 2 +- 14 files changed, 328 insertions(+), 16 deletions(-) create mode 100644 src/assets/hoc/withTooltip.tsx create mode 100644 src/components/layout/Avatar.tsx create mode 100644 src/layouts/MainLayout.tsx create mode 100644 src/pages/Result/index.tsx create mode 100644 src/pages/VariableInput/index.tsx create mode 100644 src/pages/VariableOutput/index.tsx create mode 100644 src/themes/config.ts diff --git a/package.json b/package.json index 32687b9..bd7ea3b 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "@ant-design/icons": "^5.2.6", "@tanstack/react-query": "^5.14.6", "antd": "^5.12.5", "axios": "^1.6.2", diff --git a/src/assets/hoc/withTooltip.tsx b/src/assets/hoc/withTooltip.tsx new file mode 100644 index 0000000..e133cc1 --- /dev/null +++ b/src/assets/hoc/withTooltip.tsx @@ -0,0 +1,8 @@ +import { Tooltip } from "antd"; +import React from "react"; + +const withTooltip = (component: React.ReactNode, title: React.ReactNode) => { + return {component}; +}; + +export default withTooltip; diff --git a/src/components/layout/Avatar.tsx b/src/components/layout/Avatar.tsx new file mode 100644 index 0000000..05c5953 --- /dev/null +++ b/src/components/layout/Avatar.tsx @@ -0,0 +1,47 @@ +import { colorConfig } from "@/themes/config"; +import { LogoutOutlined, UserOutlined } from "@ant-design/icons"; +import { Avatar as AvatarAntd, Dropdown, Space } from "antd"; +import { ItemType } from "antd/es/menu/hooks/useItems"; +import React from "react"; + +const Avatar: React.FC = () => { + const items: ItemType[] = [ + { + key: "profile", + label: ( + + + Profile + + ), + }, + { + key: "logout", + label: ( + + + Logout + + ), + }, + ]; + + return ( + + } + style={{ cursor: "pointer" }} + /> + + ); +}; + +export default Avatar; diff --git a/src/index.css b/src/index.css index 41b591a..67075e3 100644 --- a/src/index.css +++ b/src/index.css @@ -7,5 +7,5 @@ } body{ - background-color: rgb(242, 242, 242); + background-color:#E7E7E7; } \ No newline at end of file diff --git a/src/layouts/MainLayout.tsx b/src/layouts/MainLayout.tsx new file mode 100644 index 0000000..6a079f9 --- /dev/null +++ b/src/layouts/MainLayout.tsx @@ -0,0 +1,155 @@ +import { Button, Grid, Layout, Menu, Row } from "antd"; +import Sider from "antd/es/layout/Sider"; +import { Content, Header } from "antd/es/layout/layout"; +import React from "react"; +import { + DatabaseOutlined, + LineChartOutlined, + MenuFoldOutlined, + MenuUnfoldOutlined, + PieChartOutlined, +} from "@ant-design/icons"; +import { ItemType, MenuItemType } from "antd/es/menu/hooks/useItems"; +import { colorConfig } from "@/themes/config"; +import Avatar from "@/components/layout/Avatar"; +import { useLocation, useNavigate } from "react-router-dom"; +import { Routes } from "@/routes/routes"; + +interface IProps { + children: React.ReactNode; +} + +const iconSidebarStyle = { + fontSize: 20, + color: colorConfig.neutral.lightGray, +}; + +const menuKey = { + Dashboard: Routes.Dashboard, + VariableInput: Routes.VariableInputIndex, + VariableOutput: Routes.VariableOutputIndex, + Result: Routes.ResultIndex, +}; + +const MainLayout: React.FC = ({ children }) => { + const [isSiderCollapsed, setIsSiderCollapsed] = React.useState(false); + const { md } = Grid.useBreakpoint(); + const navigate = useNavigate(); + const location = useLocation(); + + const [activeMenuKey, setActiveMenuKey] = React.useState(null); + + const menuItems = React.useMemo[]>( + () => [ + { + key: menuKey.Dashboard, + label: "Dashboard", + icon: , + onClick: () => navigate(Routes.Dashboard), + }, + { + key: menuKey.VariableInput, + label: "Variable Input", + icon: , + onClick: () => navigate(Routes.VariableInputIndex), + }, + { + key: menuKey.VariableOutput, + label: "Variable Output", + icon: , + onClick: () => navigate(Routes.VariableOutputIndex), + }, + { + key: menuKey.Result, + label: "Result Predict", + icon: , + onClick: () => navigate(Routes.ResultIndex), + }, + ], + // eslint-disable-next-line react-hooks/exhaustive-deps + [] + ); + + React.useEffect(() => { + setIsSiderCollapsed(!md); + }, [md]); + + React.useEffect(() => { + setActiveMenuKey(location.pathname); + }, [location]); + + return ( + + + + + + + + +
+ +
+ + {children} + +
+ + ); +}; + +export default MainLayout; diff --git a/src/main.tsx b/src/main.tsx index a04471a..5e5fb45 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -7,6 +7,8 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import "./index.css"; import { AuthContextProvider } from "./contexts/AuthContext"; import LoaderFullscreen from "./components/shared/Loader/LoaderFullscreen"; +import { ConfigProvider } from "antd"; +import { colorConfig } from "./themes/config"; const queryClient = new QueryClient(); @@ -14,9 +16,17 @@ ReactDOM.createRoot(document.getElementById("root")!).render( }> - - - + + + + + diff --git a/src/pages/Dashboard/index.tsx b/src/pages/Dashboard/index.tsx index 724ce96..831d889 100644 --- a/src/pages/Dashboard/index.tsx +++ b/src/pages/Dashboard/index.tsx @@ -1,9 +1,13 @@ -import { useAuthContext } from "@/contexts/AuthContext"; +import MainLayout from "@/layouts/MainLayout"; +import { Card } from "antd"; import React from "react"; const Dashboard: React.FC = () => { - const { user } = useAuthContext(); - return JSON.stringify(user); + return ( + + + + ); }; export default Dashboard; diff --git a/src/pages/Result/index.tsx b/src/pages/Result/index.tsx new file mode 100644 index 0000000..8cbaf19 --- /dev/null +++ b/src/pages/Result/index.tsx @@ -0,0 +1,13 @@ +import MainLayout from "@/layouts/MainLayout"; +import { Card } from "antd"; +import React from "react"; + +const ResultIndex: React.FC = () => { + return ( + + + + ); +}; + +export default ResultIndex; diff --git a/src/pages/VariableInput/index.tsx b/src/pages/VariableInput/index.tsx new file mode 100644 index 0000000..9f16feb --- /dev/null +++ b/src/pages/VariableInput/index.tsx @@ -0,0 +1,13 @@ +import MainLayout from "@/layouts/MainLayout"; +import { Card } from "antd"; +import React from "react"; + +const VariableInputIndex: React.FC = () => { + return ( + + + + ); +}; + +export default VariableInputIndex; diff --git a/src/pages/VariableOutput/index.tsx b/src/pages/VariableOutput/index.tsx new file mode 100644 index 0000000..81d09de --- /dev/null +++ b/src/pages/VariableOutput/index.tsx @@ -0,0 +1,13 @@ +import MainLayout from "@/layouts/MainLayout"; +import { Card } from "antd"; +import React from "react"; + +const VariableOutputIndex: React.FC = () => { + return ( + + + + ); +}; + +export default VariableOutputIndex; diff --git a/src/routes/index.tsx b/src/routes/index.tsx index f8629fa..2d62b0b 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -9,20 +9,19 @@ import PrivateRoute from "./PrivateRoute"; const LoginPage = React.lazy(() => import("@/pages/Auth/Login")); const RegisterPage = React.lazy(() => import("@/pages/Auth/Register")); const DashboardPage = React.lazy(() => import("@/pages/Dashboard")); +const VariableInputIndexPage = React.lazy( + () => import("@/pages/VariableInput") +); +const VariableOutputIndexPage = React.lazy( + () => import("@/pages/VariableOutput") +); +const ResultIndexPage = React.lazy(() => import("@/pages/Result")); export const withSuspense = (component: ReactNode) => { return }>{component}; }; export const router = createBrowserRouter([ - { - path: Routes.Dashboard, - element: withSuspense( - - - - ), - }, { path: Routes.Login, element: withSuspense( @@ -39,4 +38,36 @@ export const router = createBrowserRouter([ ), }, + { + path: Routes.Dashboard, + element: withSuspense( + + + + ), + }, + { + path: Routes.VariableInputIndex, + element: withSuspense( + + + + ), + }, + { + path: Routes.VariableOutputIndex, + element: withSuspense( + + + + ), + }, + { + path: Routes.ResultIndex, + element: withSuspense( + + + + ), + }, ]); diff --git a/src/routes/routes.ts b/src/routes/routes.ts index fcb732c..7755c2d 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -2,6 +2,10 @@ export enum Routes { Login = "/login", Register = "/register", Dashboard = "/dashboard", + Profile = "/profile", + VariableInputIndex = "/variable-input", + VariableOutputIndex = "/variable-output", + ResultIndex = "/result", } export enum EndpointApi { diff --git a/src/themes/config.ts b/src/themes/config.ts new file mode 100644 index 0000000..81dc2d6 --- /dev/null +++ b/src/themes/config.ts @@ -0,0 +1,13 @@ +export const colorConfig = { + primary: { + main: "#1677FF", + lighter: "#BAE0FF", + darker: "#0958d9", + }, + neutral: { + black: "#000000", + gray: "#C4C4C4", + lightGray: "#E7E7E7", + white: "#FFFFFF", + }, +}; diff --git a/yarn.lock b/yarn.lock index aff309d..c21ee24 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34,7 +34,7 @@ "@ant-design/icons@^5.2.6": version "5.2.6" - resolved "https://registry.npmjs.org/@ant-design/icons/-/icons-5.2.6.tgz" + resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-5.2.6.tgz#2d4a9a37f531eb2a20cebec01d6fb69cf593900d" integrity sha512-4wn0WShF43TrggskBJPRqCD0fcHbzTYjnaoskdiJrVHg86yxoZ8ZUqsXvyn4WUqehRiFKnaclOhqk9w4Ui2KVw== dependencies: "@ant-design/colors" "^7.0.0"