From 885bcd2421ef7de011b7a02e149a73eed1ef0c83 Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Mon, 2 Aug 2021 09:49:16 +0200 Subject: [PATCH] feat: Sidebar overlay. --- client/src/components/MenuItem.js | 3 +- client/src/components/Sidebar/SidebarMenu.js | 23 ++- .../src/components/SidebarOverlay/index.tsx | 78 +++++++-- client/src/config/sidebarMenu.js | 152 ++++++++++++++++-- client/src/lang/en/index.json | 6 +- client/src/style/App.scss | 60 +++++-- 6 files changed, 274 insertions(+), 48 deletions(-) diff --git a/client/src/components/MenuItem.js b/client/src/components/MenuItem.js index 22fa80922..74144e45b 100644 --- a/client/src/components/MenuItem.js +++ b/client/src/components/MenuItem.js @@ -145,9 +145,10 @@ export default class MenuItem extends AbstractPureComponent2 { tagName = "a", dropdownType, caretIconSize = 16, + hasSubmenu, ...htmlProps } = this.props; - const hasSubmenu = children != null; + const intentClass = Classes.intentClass(intent); const anchorClasses = classNames( diff --git a/client/src/components/Sidebar/SidebarMenu.js b/client/src/components/Sidebar/SidebarMenu.js index 8b665903c..62164f715 100644 --- a/client/src/components/Sidebar/SidebarMenu.js +++ b/client/src/components/Sidebar/SidebarMenu.js @@ -8,6 +8,11 @@ import { MenuItemLabel } from 'components'; import classNames from 'classnames'; import SidebarOverlay from 'components/SidebarOverlay'; +const DEFAULT_ITEM = { + text: '', + href: '', +} + export default function SidebarMenu() { const history = useHistory(); const location = useLocation(); @@ -17,18 +22,16 @@ export default function SidebarMenu() { const menuItemsMapper = (list) => { return list.map((item, index) => { - const children = Array.isArray(item.children) - ? menuItemsMapper(item.children) - : null; + const hasChildren = Array.isArray(item.children); const matchPath = (pathname, path) => { return item.matchExact ? pathname === path : pathname.indexOf(path) !== -1; }; - const isActive = item.children + const isActive = (item.children ? item.children.some((c) => matchPath(location.pathname, c.href)) - : item.href && matchPath(location.pathname, item.href); + : item.href && matchPath(location.pathname, item.href)) || currentItem ===item; const handleItemClick = () => { if (item.href) { @@ -69,28 +72,34 @@ export default function SidebarMenu() { text={item.text} label={maybeRenderLabel(item)} disabled={item.disabled} - children={children} dropdownType={item.dropdownType || 'collapse'} caretIconSize={16} onClick={handleItemClick} callapseActive={!!isActive} itemClassName={classNames({ 'is-active': isActive, - 'has-icon': !children && item.icon, + 'has-icon': !hasChildren && item.icon, })} + hasSubmenu={hasChildren} /> ); }); }; const items = menuItemsMapper(sidebarMenuList); + const handleSidebarOverlayClose = () => { + setIsOpen(false); + } + return (
{items}{' '}
); diff --git a/client/src/components/SidebarOverlay/index.tsx b/client/src/components/SidebarOverlay/index.tsx index e5759fc1c..200194f0c 100644 --- a/client/src/components/SidebarOverlay/index.tsx +++ b/client/src/components/SidebarOverlay/index.tsx @@ -2,24 +2,24 @@ import React from 'react'; import { Overlay } from '@blueprintjs/core'; import { Link } from 'react-router-dom'; import SidebarOverlayContainer from './SidebarOverlayContainer'; - interface ISidebarOverlayItem { text: string; href: string; divider?: boolean; - label?: boolean + label?: boolean; } interface ISidebarOverlayProps { isOpen: boolean; items: ISidebarOverlayItem[]; - overlayProps: any; - overlayContainerRef: any; + label: string; + onClose: Function; } interface ISidebarOverlayItemProps { text: string; href: string; + onLinkClick: Function; } interface ISidebarOverlayItemDivider { @@ -28,16 +28,25 @@ interface ISidebarOverlayItemDivider { /** * Sidebar overlay item. */ -function SidebarOverlayItem({ text, href }: ISidebarOverlayItemProps) { +function SidebarOverlayItem({ + text, + href, + onLinkClick, +}: ISidebarOverlayItemProps) { + const handleLinkClick = () => { + onLinkClick && onLinkClick(); + }; return (
- {text} + + {text} +
); } interface ISidebarOverlayItemLabel { - text: string; + text: string; } function SidebarOverlayLabel({ text }: ISidebarOverlayItemLabel) { @@ -52,34 +61,75 @@ function SidebarOverlayDivider() { * Sidebar overlay component. */ export default function SidebarOverlay({ - isOpen = false, + label, + isOpen: controllerdIsOpen, + onClose, items, }: ISidebarOverlayProps) { - // - if (!isOpen) { + const [isEverOpened, setEverOpened] = React.useState(false); + const [isOpen, setIsOpen] = React.useState(controllerdIsOpen); + + React.useEffect(() => { + if (controllerdIsOpen && isOpen !== controllerdIsOpen) { + setIsOpen(controllerdIsOpen); + } + }, [controllerdIsOpen, setIsOpen, isOpen]); + + React.useEffect(() => { + if (isOpen && !isEverOpened) { + setEverOpened(true); + } + }, [isEverOpened, isOpen]); + + if (!isEverOpened) { return ''; } + // Handle overlay close event. const handleOverlayClose = () => { - + setIsOpen(false); + onClose && onClose(); + }; + // Handle overlay open event. + const handleOverlayOpen = () => { + setIsOpen(true); + }; + // Handle sidebar item link click. + const handleItemClick = () => { + setIsOpen(false); + onClose && onClose(); }; return ( -
+
+ {label && ( + <> + + + + )} + {items.map((item) => item.divider ? ( ) : item.label ? ( ) : ( - + ), )}
diff --git a/client/src/config/sidebarMenu.js b/client/src/config/sidebarMenu.js index 02fa39ce6..725281380 100644 --- a/client/src/config/sidebarMenu.js +++ b/client/src/config/sidebarMenu.js @@ -27,6 +27,28 @@ export default [ text: , href: '/items/categories', }, + { + text: 'New tasks', + label: true, + }, + { + divider: true, + }, + { + text: , + href: '/items/new', + }, + { + text: , + href: '/items/new', + }, + { + text: , + href: '/items/categories/new', + }, + { + text: 'New inventory adjustment', + }, ], }, { @@ -48,14 +70,34 @@ export default [ href: '/payment-receives', newTabHref: '/payment-receives/new', }, - { - divider: true, - }, { text: , href: '/receipts', newTabHref: '/receipts/new', }, + { + text: 'New tasks', + label: true, + }, + { + divider: true, + }, + { + text: , + href: '/estimates/new', + }, + { + text: , + href: '/invoices/new', + }, + { + text: , + href: '/receipts/new', + }, + { + text: , + href: '/payment-receives/new', + }, ], }, { @@ -71,6 +113,21 @@ export default [ href: '/payment-mades', newTabHref: '/payment-mades/new', }, + { + text: 'New tasks', + label: true, + }, + { + divider: true, + }, + { + text: , + href: '/bills/new', + }, + { + text: , + href: '/payment-mades/new', + }, ], }, { @@ -86,6 +143,21 @@ export default [ href: '/vendors', newTabHref: '/vendors/new', }, + { + text: 'New tasks', + label: true, + }, + { + divider: true, + }, + { + text: , + href: '/customers/new', + }, + { + text: , + href: '/vendors/new', + }, ], }, { @@ -103,14 +175,21 @@ export default [ text: , href: '/manual-journals', }, - { - text: , - href: '/make-journal-entry', - }, { text: , href: '/exchange-rates', }, + { + text: 'New tasks', + label: true, + }, + { + divider: true, + }, + { + text: , + href: '/make-journal-entry', + }, ], }, { @@ -133,15 +212,6 @@ export default [ { text: , children: [ - { - text: , - href: '/financial-reports', - matchExact: true, - label: true - }, - { - divider: true, - }, { text: , href: '/financial-reports/balance-sheet', @@ -162,6 +232,10 @@ export default [ text: , href: '/financial-reports/profit-loss-sheet', }, + { + text: , + href: '/financial-reports/cash-flow', + }, { text: , href: '/financial-reports/receivable-aging-summary', @@ -170,6 +244,52 @@ export default [ text: , href: '/financial-reports/payable-aging-summary', }, + { + text: , + label: true, + }, + { + divider: true, + }, + { + text: , + href: '/financial-reports/purchases-by-items', + }, + { + text: , + href: '/financial-reports/sales-by-items', + }, + { + text: , + href: '/financial-reports/transactions-by-customers', + }, + { + text: , + href: '/financial-reports/transactions-by-vendors', + }, + { + text: , + href: '/financial-reports/customers-balance-summary', + }, + { + text: , + href: '/financial-reports/vendors-balance-summary', + }, + { + text: , + label: true, + }, + { + divider: true, + }, + { + text: , + href: '/financial-reports/inventory-item-details', + }, + { + text: , + href: '/financial-reports/inventory-valuation', + }, ], }, { diff --git a/client/src/lang/en/index.json b/client/src/lang/en/index.json index 384702549..6b2767ed4 100644 --- a/client/src/lang/en/index.json +++ b/client/src/lang/en/index.json @@ -1172,5 +1172,9 @@ "invoice_details":"Invoice details", "receipt_details":"Receipt details", "payment_receive_details":"Payment receive details", - "payment_made_details":"Payment made details" + "payment_made_details":"Payment made details", + "New item category": "New item category", + "New service": "New service", + "New inventory item": "New inventory item", + "New purchase invoice": "New purchase invoice" } \ No newline at end of file diff --git a/client/src/style/App.scss b/client/src/style/App.scss index a014aa95d..187fd8ed9 100644 --- a/client/src/style/App.scss +++ b/client/src/style/App.scss @@ -204,7 +204,8 @@ html[lang^="ar"] { .sidebar-overlay { background: #fff; height: 100%; - width: 300px; + width: 240px; + outline: 0; &__scroll-wrapper { height: 100% @@ -237,23 +238,23 @@ html[lang^="ar"] { &.ScrollbarsCustom-ThumbX, &.ScrollbarsCustom-ThumbY { - background: rgba(255, 255, 255, 0.25); + background: rgba(0, 0, 0, 0.5); } } } &__menu { - margin: 20px 0; + margin: 16px 0; } &__item { font-size: 15px; - color: #032259; + color: #001944; a { color: inherit; display: block; - padding: 9px 22px; + padding: 10px 22px; text-decoration: none; &:hover, @@ -265,15 +266,56 @@ html[lang^="ar"] { &__divider { height: 1px; - margin: 4px 0; - background: #ebebeb; + margin: 6px 0; + background: #e2e5ec; } &__label{ text-transform: uppercase; font-size: 12px; - padding: 4px 20px; - letter-spacing: 0.8px; + padding: 14px 20px 10px; + letter-spacing: 1px; color: #707a85; } + + &__label + .sidebar-overlay__divider{ + margin-top: 0; + } +} + +.sidebar-overlay-transition { + transform: translateX(-100%); + + &.bp3-overlay{ + &-appear, + &-enter { + transform: translateX(-100%) + } + + &-appear-active, + &-enter-active { + transform: translateX(0) !important; + transition: all 200ms ease-in-out; + } + + &-appear-done, + &-enter-done { + transform: translateX(0) !important; + } + + &-exit { + transform: translateX(0) !important; + } + &-exit-active { + transform: translateX(-100%) !important; + transition: all 200ms ease-in-out; + } + &-exit-done{ + transform: translateX(-100%) !important; + } + } + +} +.sidebar-overlay-backdrop{ + background-color: rgba(0, 10, 30, 0.6); } \ No newline at end of file