Skip to content

Commit

Permalink
feat: add layout and additional pages
Browse files Browse the repository at this point in the history
  • Loading branch information
ridhlab committed Dec 28, 2023
1 parent 996f649 commit b2fc0bf
Show file tree
Hide file tree
Showing 14 changed files with 328 additions and 16 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
8 changes: 8 additions & 0 deletions src/assets/hoc/withTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Tooltip } from "antd";
import React from "react";

const withTooltip = (component: React.ReactNode, title: React.ReactNode) => {
return <Tooltip title={title}>{component}</Tooltip>;
};

export default withTooltip;
47 changes: 47 additions & 0 deletions src/components/layout/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -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: (
<Space>
<UserOutlined style={{ color: colorConfig.neutral.gray }} />
Profile
</Space>
),
},
{
key: "logout",
label: (
<Space>
<LogoutOutlined
style={{ color: colorConfig.neutral.gray }}
/>
Logout
</Space>
),
},
];

return (
<Dropdown
placement="bottomRight"
menu={{
items,
}}
>
<AvatarAntd
size={50}
icon={<UserOutlined />}
style={{ cursor: "pointer" }}
/>
</Dropdown>
);
};

export default Avatar;
2 changes: 1 addition & 1 deletion src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
}

body{
background-color: rgb(242, 242, 242);
background-color:#E7E7E7;
}
155 changes: 155 additions & 0 deletions src/layouts/MainLayout.tsx
Original file line number Diff line number Diff line change
@@ -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<IProps> = ({ 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<ItemType<MenuItemType>[]>(
() => [
{
key: menuKey.Dashboard,
label: "Dashboard",
icon: <PieChartOutlined style={iconSidebarStyle} />,
onClick: () => navigate(Routes.Dashboard),
},
{
key: menuKey.VariableInput,
label: "Variable Input",
icon: <DatabaseOutlined style={iconSidebarStyle} />,
onClick: () => navigate(Routes.VariableInputIndex),
},
{
key: menuKey.VariableOutput,
label: "Variable Output",
icon: <DatabaseOutlined style={iconSidebarStyle} />,
onClick: () => navigate(Routes.VariableOutputIndex),
},
{
key: menuKey.Result,
label: "Result Predict",
icon: <LineChartOutlined style={iconSidebarStyle} />,
onClick: () => navigate(Routes.ResultIndex),
},
],
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);

React.useEffect(() => {
setIsSiderCollapsed(!md);
}, [md]);

React.useEffect(() => {
setActiveMenuKey(location.pathname);
}, [location]);

return (
<Layout hasSider>
<Sider
style={{
overflow: "auto",
height: "100vh",
position: "fixed",
left: 0,
top: 0,
bottom: 0,
padding: "1rem 0",
}}
trigger={null}
collapsible
collapsed={isSiderCollapsed}
collapsedWidth={50}
>
<Row justify="center" style={{ marginBottom: "2rem" }}>
<img src="/vite.svg" />
</Row>
<Menu
theme="dark"
mode="inline"
selectedKeys={[activeMenuKey]}
items={menuItems}
/>
</Sider>
<Layout>
<Header
style={{
background: colorConfig.neutral.white,
display: "flex",
alignItems: "center",
}}
>
<Row
justify="space-between"
style={{
width: "100%",
paddingLeft: isSiderCollapsed ? "1rem" : "10rem",
}}
align="middle"
>
<Button
type="text"
icon={
isSiderCollapsed ? (
<MenuUnfoldOutlined />
) : (
<MenuFoldOutlined />
)
}
onClick={() =>
setIsSiderCollapsed(!isSiderCollapsed)
}
/>
<Avatar />
</Row>
</Header>
<Content
style={{
backgroundColor: colorConfig.neutral.lightGray,
padding: isSiderCollapsed
? "2rem 2rem 2rem 5rem"
: "2rem 2rem 2rem 14.5rem",
}}
>
{children}
</Content>
</Layout>
</Layout>
);
};

export default MainLayout;
16 changes: 13 additions & 3 deletions src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,26 @@ 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();

ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<Suspense fallback={<LoaderFullscreen />}>
<QueryClientProvider client={queryClient}>
<AuthContextProvider>
<RouterProvider router={router} />
</AuthContextProvider>
<ConfigProvider
theme={{
token: {
colorPrimary: colorConfig.primary.main,
},
}}
>
<AuthContextProvider>
<RouterProvider router={router} />
</AuthContextProvider>
</ConfigProvider>
</QueryClientProvider>
</Suspense>
</React.StrictMode>
Expand Down
10 changes: 7 additions & 3 deletions src/pages/Dashboard/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<MainLayout>
<Card title="Dashboard"></Card>
</MainLayout>
);
};

export default Dashboard;
13 changes: 13 additions & 0 deletions src/pages/Result/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import MainLayout from "@/layouts/MainLayout";
import { Card } from "antd";
import React from "react";

const ResultIndex: React.FC = () => {
return (
<MainLayout>
<Card title="Result"></Card>
</MainLayout>
);
};

export default ResultIndex;
13 changes: 13 additions & 0 deletions src/pages/VariableInput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import MainLayout from "@/layouts/MainLayout";
import { Card } from "antd";
import React from "react";

const VariableInputIndex: React.FC = () => {
return (
<MainLayout>
<Card title="Variable Input"></Card>
</MainLayout>
);
};

export default VariableInputIndex;
13 changes: 13 additions & 0 deletions src/pages/VariableOutput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import MainLayout from "@/layouts/MainLayout";
import { Card } from "antd";
import React from "react";

const VariableOutputIndex: React.FC = () => {
return (
<MainLayout>
<Card title="Variable Output"></Card>
</MainLayout>
);
};

export default VariableOutputIndex;
47 changes: 39 additions & 8 deletions src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <Suspense fallback={<LoaderFullscreen />}>{component}</Suspense>;
};

export const router = createBrowserRouter([
{
path: Routes.Dashboard,
element: withSuspense(
<PrivateRoute>
<DashboardPage />
</PrivateRoute>
),
},
{
path: Routes.Login,
element: withSuspense(
Expand All @@ -39,4 +38,36 @@ export const router = createBrowserRouter([
</PublicRoute>
),
},
{
path: Routes.Dashboard,
element: withSuspense(
<PrivateRoute>
<DashboardPage />
</PrivateRoute>
),
},
{
path: Routes.VariableInputIndex,
element: withSuspense(
<PrivateRoute>
<VariableInputIndexPage />
</PrivateRoute>
),
},
{
path: Routes.VariableOutputIndex,
element: withSuspense(
<PrivateRoute>
<VariableOutputIndexPage />
</PrivateRoute>
),
},
{
path: Routes.ResultIndex,
element: withSuspense(
<PrivateRoute>
<ResultIndexPage />
</PrivateRoute>
),
},
]);
4 changes: 4 additions & 0 deletions src/routes/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit b2fc0bf

Please sign in to comment.