Added more UI improvements - Hide/Show Sidebar
This commit is contained in:
parent
7c716f5b27
commit
fe6ed86a76
@ -1,12 +1,15 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { LayoutWrapper } from "../features/dashboard/layout/layoutWrapper";
|
||||
import { MainContent } from "../features/dashboard/layout/mainContent";
|
||||
import SideBar from "../features/dashboard/sidebar/Sidebar";
|
||||
import Header from "../features/dashboard/header/Header";
|
||||
import { useTokenExpiration } from "../hooks/useTokenExpiration";
|
||||
import TokenExpirationInfo from "../components/TokenExpirationInfo";
|
||||
import { toggleSidebar } from "../redux/ui/uiSlice";
|
||||
import { RootState } from "../redux/types";
|
||||
|
||||
const DashboardLayout: React.FC<{ children: React.ReactNode }> = ({
|
||||
children,
|
||||
@ -14,9 +17,16 @@ const DashboardLayout: React.FC<{ children: React.ReactNode }> = ({
|
||||
// Monitor token expiration and auto-logout
|
||||
useTokenExpiration();
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const isSidebarOpen = useSelector((state: RootState) => state.ui.sidebarOpen);
|
||||
|
||||
const handleToggleSidebar = () => {
|
||||
dispatch(toggleSidebar());
|
||||
};
|
||||
|
||||
return (
|
||||
<LayoutWrapper>
|
||||
<SideBar />
|
||||
<SideBar isOpen={isSidebarOpen} onClose={handleToggleSidebar} />
|
||||
<div style={{ flexGrow: 1, display: "flex", flexDirection: "column" }}>
|
||||
<MainContent>
|
||||
<Header />
|
||||
|
||||
@ -1,23 +1,10 @@
|
||||
import React from "react";
|
||||
import { AppBar, Toolbar, IconButton } from "@mui/material";
|
||||
import MenuIcon from "@mui/icons-material/Menu";
|
||||
import { AppBar, Toolbar } from "@mui/material";
|
||||
import Dropdown from "./dropDown/DropDown";
|
||||
import AccountMenu from "./accountMenu/AccountMenu";
|
||||
import "./Header.scss";
|
||||
|
||||
const Header = () => {
|
||||
// const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||
|
||||
// // Handle menu open
|
||||
// const handleMenuClick = (event: React.MouseEvent<HTMLElement>) => {
|
||||
// setAnchorEl(event.currentTarget);
|
||||
// };
|
||||
|
||||
// // Handle menu close
|
||||
// const handleMenuClose = () => {
|
||||
// setAnchorEl(null);
|
||||
// };
|
||||
|
||||
const handleChange = () => {};
|
||||
|
||||
return (
|
||||
@ -30,9 +17,6 @@ const Header = () => {
|
||||
>
|
||||
<Toolbar className="header__toolbar">
|
||||
<div className="header__left-group">
|
||||
<IconButton edge="start" color="inherit" aria-label="menu">
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Dropdown onChange={handleChange} />
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
import { styled } from "@mui/system";
|
||||
|
||||
export const MainContent = styled("div")(({ theme }) => ({
|
||||
marginLeft: "240px",
|
||||
padding: theme.spacing(3),
|
||||
minHeight: "100vh",
|
||||
width: "calc(100% - 240px)",
|
||||
}));
|
||||
21
app/features/dashboard/layout/mainContent.tsx
Normal file
21
app/features/dashboard/layout/mainContent.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "../../redux/types";
|
||||
|
||||
interface MainContentProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const MainContent = ({ children }: MainContentProps) => {
|
||||
const isSidebarOpen = useSelector((state: RootState) => state.ui.sidebarOpen);
|
||||
|
||||
const style: React.CSSProperties = {
|
||||
marginLeft: isSidebarOpen ? "240px" : "30px",
|
||||
padding: "24px",
|
||||
minHeight: "100vh",
|
||||
width: isSidebarOpen ? "calc(100% - 240px)" : "calc(100% - 30px)",
|
||||
transition: "margin-left 0.3s ease-in-out, width 0.3s ease-in-out",
|
||||
};
|
||||
|
||||
return <div style={style}>{children}</div>;
|
||||
};
|
||||
@ -7,8 +7,15 @@ import PageLinks from "../../../components/PageLinks/PageLinks";
|
||||
import "./sideBar.scss";
|
||||
import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
|
||||
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
|
||||
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
|
||||
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
||||
|
||||
const SideBar = () => {
|
||||
interface SidebarProps {
|
||||
isOpen?: boolean;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
const SideBar = ({ isOpen = true, onClose }: SidebarProps) => {
|
||||
const [openMenus, setOpenMenus] = useState<Record<string, boolean>>({});
|
||||
|
||||
const toggleMenu = (title: string) => {
|
||||
@ -16,10 +23,13 @@ const SideBar = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<aside className="sidebar">
|
||||
<aside className={`sidebar ${!isOpen ? "sidebar--collapsed" : ""}`}>
|
||||
<button className="sidebar__toggle-button" onClick={onClose}>
|
||||
{isOpen ? <ChevronLeftIcon /> : <ChevronRightIcon />}
|
||||
</button>
|
||||
<div className="sidebar__header">
|
||||
<span>
|
||||
Betrise cashir
|
||||
Betrise cashier
|
||||
<DashboardIcon fontSize="small" className="sidebar__icon-spacing" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@ -11,6 +11,55 @@
|
||||
padding: 16px;
|
||||
z-index: 1100;
|
||||
border-right: 1px solid #333;
|
||||
transition: transform 0.3s ease-in-out;
|
||||
overflow: hidden;
|
||||
|
||||
&--collapsed {
|
||||
transform: translateX(-210px); // Hide 90% (210px out of 240px)
|
||||
|
||||
.sidebar__header,
|
||||
.sidebar__dropdown-button,
|
||||
.sidebar__submenu,
|
||||
a {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__toggle-button {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 0;
|
||||
background: var(--background-primary);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50% 0 0 50%;
|
||||
transition: all 0.2s ease;
|
||||
z-index: 1101;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-left: 1px solid #333;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
svg {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&--collapsed &__toggle-button {
|
||||
border-radius: 50%;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-left: 1px solid #333;
|
||||
}
|
||||
|
||||
&__header {
|
||||
font-size: 20px;
|
||||
@ -71,4 +120,36 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile responsiveness
|
||||
@media (max-width: 768px) {
|
||||
z-index: 1101;
|
||||
}
|
||||
}
|
||||
|
||||
// Sidebar overlay for mobile
|
||||
.sidebar-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1100;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
transition:
|
||||
opacity 0.3s ease-in-out,
|
||||
visibility 0.3s ease-in-out;
|
||||
|
||||
&--visible {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import { createTransform, persistReducer, persistStore } from "redux-persist";
|
||||
import { createEpicMiddleware, combineEpics } from "redux-observable";
|
||||
import advancedSearchReducer from "./advanedSearch/advancedSearchSlice";
|
||||
import authReducer from "./auth/authSlice";
|
||||
import uiReducer from "./ui/uiSlice";
|
||||
import userEpics from "./user/epic";
|
||||
import authEpics from "./auth/epic";
|
||||
|
||||
@ -36,6 +37,7 @@ const persistConfig = {
|
||||
const rootReducer = combineReducers({
|
||||
advancedSearch: advancedSearchReducer,
|
||||
auth: authReducer,
|
||||
ui: uiReducer,
|
||||
});
|
||||
|
||||
const rootEpic = combineEpics(...userEpics, ...authEpics);
|
||||
|
||||
25
app/redux/ui/uiSlice.ts
Normal file
25
app/redux/ui/uiSlice.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
interface UIState {
|
||||
sidebarOpen: boolean;
|
||||
}
|
||||
|
||||
const initialState: UIState = {
|
||||
sidebarOpen: true,
|
||||
};
|
||||
|
||||
const uiSlice = createSlice({
|
||||
name: "ui",
|
||||
initialState,
|
||||
reducers: {
|
||||
toggleSidebar: state => {
|
||||
state.sidebarOpen = !state.sidebarOpen;
|
||||
},
|
||||
setSidebarOpen: (state, action: PayloadAction<boolean>) => {
|
||||
state.sidebarOpen = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { toggleSidebar, setSidebarOpen } = uiSlice.actions;
|
||||
export default uiSlice.reducer;
|
||||
Loading…
x
Reference in New Issue
Block a user