diff --git a/src/layout/LayoutBreadcrumb.jsx b/src/layout/LayoutBreadcrumb.jsx
new file mode 100644
index 0000000..5889c90
--- /dev/null
+++ b/src/layout/LayoutBreadcrumb.jsx
@@ -0,0 +1,15 @@
+import React, { createContext, useContext, useState } from 'react';
+
+const BreadcrumbContext = createContext();
+
+export const BreadcrumbProvider = ({ children }) => {
+ const [breadcrumbItems, setBreadcrumbItems] = useState([]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useBreadcrumb = () => useContext(BreadcrumbContext);
\ No newline at end of file
diff --git a/src/layout/LayoutFooter.jsx b/src/layout/LayoutFooter.jsx
new file mode 100644
index 0000000..be22b02
--- /dev/null
+++ b/src/layout/LayoutFooter.jsx
@@ -0,0 +1,18 @@
+import React from 'react'
+import { Layout } from 'antd'
+import Link from 'antd/es/typography/Link';
+
+const { Footer } = Layout;
+const LayoutFooter = () => {
+ return (
+
+ )
+}
+
+export default LayoutFooter
diff --git a/src/layout/LayoutHeader.jsx b/src/layout/LayoutHeader.jsx
new file mode 100644
index 0000000..21a7717
--- /dev/null
+++ b/src/layout/LayoutHeader.jsx
@@ -0,0 +1,119 @@
+import React from 'react';
+import { Layout, theme, Space, Typography, Breadcrumb, Button } from 'antd';
+import { UserOutlined } from '@ant-design/icons';
+import handleLogOut from '../Utils/Auth/Logout';
+import { useBreadcrumb } from './LayoutBreadcrumb';
+import { decryptData } from '../components/Global/Formatter';
+import { useNavigate } from 'react-router-dom';
+
+const { Link, Text } = Typography;
+const { Header } = Layout;
+
+const LayoutHeader = () => {
+ const { breadcrumbItems } = useBreadcrumb();
+ const navigate = useNavigate();
+ const {
+ token: { colorBgContainer, colorBorder, colorText },
+ } = theme.useToken();
+
+ // Ambil data user dari localStorage dan dekripsi
+ const sessionData = localStorage.getItem('session');
+ const userData = sessionData ? decryptData(sessionData) : null;
+ // console.log(userData);
+
+ const roleName = userData?.user?.approval || userData?.user?.partner_name || 'Guest';
+
+ const userName = userData?.user?.name || userData?.user?.username || 'User';
+
+ return (
+ <>
+
+
+
+ Login AS {roleName}
+
+
+
+
+
+ {
+ handleLogOut();
+ navigate('/signin');
+ }}
+ aria-label="Log out from the application"
+ style={{
+ color: colorText,
+ whiteSpace: 'nowrap',
+ }}
+ >
+ Logout
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default LayoutHeader;
diff --git a/src/layout/LayoutLogo.jsx b/src/layout/LayoutLogo.jsx
new file mode 100644
index 0000000..086db57
--- /dev/null
+++ b/src/layout/LayoutLogo.jsx
@@ -0,0 +1,69 @@
+import { Image } from 'antd';
+import logoPiu from '../assets/freepik/LOGOPIU.png';
+import React from 'react';
+
+const LayoutLogo = () => {
+ return (
+
+
+ {/* Ring sebelum logo utama */}
+
+
+
+
+
+
+
+ );
+};
+
+export default LayoutLogo;
\ No newline at end of file
diff --git a/src/layout/LayoutMenu.jsx b/src/layout/LayoutMenu.jsx
new file mode 100644
index 0000000..33fb21f
--- /dev/null
+++ b/src/layout/LayoutMenu.jsx
@@ -0,0 +1,110 @@
+import React, { useState } from 'react';
+import { Link } from 'react-router-dom';
+import { Menu, Typography, Image } from 'antd';
+import { getSessionData } from '../components/Global/Formatter';
+import { HomeOutlined,
+ DatabaseOutlined,
+ SettingOutlined,
+ UserOutlined,
+ AntDesignOutlined,
+ ShoppingCartOutlined,
+ ShoppingOutlined,
+ HistoryOutlined,
+ DollarOutlined,
+ RollbackOutlined,
+ ProductOutlined
+} from '@ant-design/icons';
+
+const { Text } = Typography;
+
+const allItems = [
+ {
+ key: 'home',
+ icon: ,
+ label: Home,
+ },
+ {
+ key: 'master',
+ icon: ,
+ label: 'Master',
+ children: [
+ {
+ key: 'master-device',
+ icon: ,
+ label: Device,
+ },
+ ],
+ },
+];
+
+const LayoutMenu = () => {
+ const [stateOpenKeys, setStateOpenKeys] = useState(['home']);
+
+ const getLevelKeys = items1 => {
+ const key = {};
+ const func = (items2, level = 1) => {
+ items2.forEach(item => {
+ if (item.key) {
+ key[item.key] = level;
+ }
+ if (item.children) {
+ func(item.children, level + 1);
+ }
+ });
+ };
+ func(items1);
+ return key;
+ };
+
+ const levelKeys = getLevelKeys(allItems);
+
+ const onOpenChange = openKeys => {
+ const currentOpenKey = openKeys.find(key => stateOpenKeys.indexOf(key) === -1);
+ if (currentOpenKey !== undefined) {
+ const repeatIndex = openKeys.filter(key => key !== currentOpenKey).findIndex(key => levelKeys[key] === levelKeys[currentOpenKey]);
+ setStateOpenKeys(
+ openKeys.filter((_, index) => index !== repeatIndex).filter(key => levelKeys[key] <= levelKeys[currentOpenKey]),
+ );
+ } else {
+ setStateOpenKeys(openKeys);
+ }
+ };
+
+ const session = getSessionData();
+ const isAdmin = session?.user?.user_id;
+
+ const karyawan = ()=>{
+ return allItems.filter(
+ item => item.key !== 'setting'
+ // tambahkan menu jika terdapat menu yang di sembunyikan dari user karyawan
+ // && item.key !== 'master'
+ // && item.key !== 'master'
+ ).map(item=>{
+ if(item.key === 'master'){
+ return{
+ ...item,
+ // buka command dibawah jika terdapat sub menu yang di sembunyikan
+ // children: item.children.filter(
+ // child => child.key !== 'master-product'
+ // tambahkan menu jika terdapat menu yang di sembunyikan dari user karyawan
+ // && child.key !== 'master-service'
+ // )
+ }
+ }
+ return item;
+ });
+ };
+ const items = isAdmin === 1 ? allItems : karyawan();
+
+ return (
+
+ );
+};
+export default LayoutMenu;
\ No newline at end of file
diff --git a/src/layout/LayoutSidebar.jsx b/src/layout/LayoutSidebar.jsx
new file mode 100644
index 0000000..4589344
--- /dev/null
+++ b/src/layout/LayoutSidebar.jsx
@@ -0,0 +1,25 @@
+import React from 'react'
+import { Layout } from 'antd';
+import LayoutLogo from './LayoutLogo';
+import LayoutMenu from './LayoutMenu';
+
+const { Sider } = Layout;
+const LayoutSidebar = () => {
+ return (
+ {
+ // console.log(broken);
+ }}
+ onCollapse={(collapsed, type) => {
+ // console.log(collapsed, type);
+ }}
+ >
+
+
+
+ )
+}
+
+export default LayoutSidebar
diff --git a/src/layout/MainLayout.jsx b/src/layout/MainLayout.jsx
new file mode 100644
index 0000000..6d035f9
--- /dev/null
+++ b/src/layout/MainLayout.jsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import { Layout, theme } from 'antd';
+import LayoutFooter from './LayoutFooter';
+import LayoutHeader from './LayoutHeader';
+import LayoutSidebar from './LayoutSidebar';
+
+
+const { Content } = Layout;
+
+const MainLayout = ({ children }) => {
+ const {
+ token: { colorBgContainer, borderRadiusLG },
+ } = theme.useToken();
+
+ return (
+
+
+
+
+
+ {/* */}
+ {children}
+ {/*
*/}
+
+ {/* */}
+
+
+ );
+};
+export default MainLayout;
\ No newline at end of file