+
);
-}
+});
diff --git a/client/src/components/Dashboard/PrivatePages.js b/client/src/components/Dashboard/PrivatePages.js
index 0d0b5d06c..f49b356b7 100644
--- a/client/src/components/Dashboard/PrivatePages.js
+++ b/client/src/components/Dashboard/PrivatePages.js
@@ -17,16 +17,16 @@ export default function DashboardPrivatePages() {
return (
-
+ {/*
-
+ */}
-
+ {/* */}
-
+ {/* */}
diff --git a/client/src/components/Dashboard/PrivatePagesProvider.js b/client/src/components/Dashboard/PrivatePagesProvider.js
index 34db3a813..1e67ce2bc 100644
--- a/client/src/components/Dashboard/PrivatePagesProvider.js
+++ b/client/src/components/Dashboard/PrivatePagesProvider.js
@@ -7,10 +7,10 @@ import { useCurrentOrganization } from '../../hooks/query/organization';
*/
export function PrivatePagesProvider({ children }) {
// Fetches the current user's organization.
- const { isLoading } = useCurrentOrganization();
+ // const { isLoading } = useCurrentOrganization();
return (
-
+
{children}
)
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/Sidebar.js b/client/src/components/Sidebar/Sidebar.js
index 0cad24831..4dc1bc19a 100644
--- a/client/src/components/Sidebar/Sidebar.js
+++ b/client/src/components/Sidebar/Sidebar.js
@@ -1,12 +1,12 @@
import React from 'react';
-import { Menu, MenuItem } from '@blueprintjs/core';
import SidebarContainer from 'components/Sidebar/SidebarContainer';
import SidebarHead from 'components/Sidebar/SidebarHead';
import SidebarMenu from 'components/Sidebar/SidebarMenu';
+import SidebarOverlay from 'components/SidebarOverlay';
import 'style/containers/Dashboard/Sidebar.scss';
-export default function Sidebar() {
+export default function Sidebar({ dashboardContentRef }) {
return (
@@ -14,10 +14,8 @@ export default function Sidebar() {
-
-
+
+
- )
-}
\ No newline at end of file
+ );
+}
diff --git a/client/src/components/Sidebar/SidebarMenu.js b/client/src/components/Sidebar/SidebarMenu.js
index 31275978c..62164f715 100644
--- a/client/src/components/Sidebar/SidebarMenu.js
+++ b/client/src/components/Sidebar/SidebarMenu.js
@@ -6,45 +6,60 @@ import Icon from 'components/Icon';
import MenuItem from 'components/MenuItem';
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();
+ const [isOpen, setIsOpen] = React.useState(false);
+ const [currentItem, setCurrentItem] = React.useState(null);
+
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;
+ return item.matchExact
+ ? pathname === path
+ : pathname.indexOf(path) !== -1;
};
- const isActive = (item.children) ?
- item.children.some((c) => matchPath(location.pathname, c.href)) :
- (item.href && matchPath(location.pathname, item.href));
+ const isActive = (item.children
+ ? item.children.some((c) => matchPath(location.pathname, c.href))
+ : item.href && matchPath(location.pathname, item.href)) || currentItem ===item;
const handleItemClick = () => {
if (item.href) {
history.push(item.href);
}
+ setIsOpen(true);
+ setCurrentItem(item);
};
- const maybeRenderLabel = (item) => item.newTabHref ? (
- }
- onClick={(event) => {
- history.push(item.newTabHref);
- event.stopPropagation();
- }}
- />
- ) : null;
+ const maybeRenderLabel = (item) =>
+ item.newTabHref ? (
+ }
+ onClick={(event) => {
+ history.push(item.newTabHref);
+ event.stopPropagation();
+ }}
+ />
+ ) : null;
return item.spacer ? (
-
+
) : item.divider ? (
) : item.label ? (
@@ -57,20 +72,35 @@ 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);
- return ;
+ const handleSidebarOverlayClose = () => {
+ setIsOpen(false);
+ }
+
+ return (
+
+
{' '}
+
+
+
+ );
}
diff --git a/client/src/components/SidebarOverlay/SidebarOverlayContainer.tsx b/client/src/components/SidebarOverlay/SidebarOverlayContainer.tsx
new file mode 100644
index 000000000..0122127e1
--- /dev/null
+++ b/client/src/components/SidebarOverlay/SidebarOverlayContainer.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import { Scrollbar } from 'react-scrollbars-custom';
+
+interface ISidebarOverlayContainerProps {
+ children: JSX.Element | JSX.Element[],
+}
+
+/**
+ * Sidebar overlay container.
+ */
+export default function SidebarOverlayContainer({ children }: ISidebarOverlayContainerProps) {
+ return (
+
+ );
+}
diff --git a/client/src/components/SidebarOverlay/index.tsx b/client/src/components/SidebarOverlay/index.tsx
new file mode 100644
index 000000000..73efa51c0
--- /dev/null
+++ b/client/src/components/SidebarOverlay/index.tsx
@@ -0,0 +1,140 @@
+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;
+}
+
+interface ISidebarOverlayProps {
+ isOpen: boolean;
+ items: ISidebarOverlayItem[];
+ label: string;
+ onClose: Function;
+}
+
+interface ISidebarOverlayItemProps {
+ text: string;
+ href: string;
+ onLinkClick: Function;
+}
+
+interface ISidebarOverlayItemDivider {
+ divider: boolean;
+}
+/**
+ * Sidebar overlay item.
+ */
+function SidebarOverlayItem({
+ text,
+ href,
+ onLinkClick,
+}: ISidebarOverlayItemProps) {
+ const handleLinkClick = () => {
+ onLinkClick && onLinkClick();
+ };
+ return (
+
+
+ {text}
+
+
+ );
+}
+
+interface ISidebarOverlayItemLabel {
+ text: string;
+}
+
+function SidebarOverlayLabel({ text }: ISidebarOverlayItemLabel) {
+ return {text}
;
+}
+
+function SidebarOverlayDivider() {
+ return ;
+}
+
+/**
+ * Sidebar overlay component.
+ */
+export default function SidebarOverlay({
+ label,
+ isOpen: controllerdIsOpen,
+ onClose,
+ items,
+}: ISidebarOverlayProps) {
+ 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 d5ff66556..e7c627a3f 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',
+ },
],
},
{
@@ -124,6 +203,13 @@ export default [
text: ,
href: '/expenses',
},
+ {
+ text: 'New tasks',
+ label: true,
+ },
+ {
+ divider: true,
+ },
{
text: ,
href: '/expenses/new',
@@ -133,14 +219,6 @@ export default [
{
text: ,
children: [
- {
- text: ,
- href: '/financial-reports',
- matchExact: true,
- },
- {
- divider: true,
- },
{
text: ,
href: '/financial-reports/balance-sheet',
@@ -161,6 +239,10 @@ export default [
text: ,
href: '/financial-reports/profit-loss-sheet',
},
+ {
+ text: ,
+ href: '/financial-reports/cash-flow',
+ },
{
text: ,
href: '/financial-reports/receivable-aging-summary',
@@ -169,6 +251,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..01086f8fe 100644
--- a/client/src/lang/en/index.json
+++ b/client/src/lang/en/index.json
@@ -1172,5 +1172,10 @@
"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",
+ "Sales/Purchases": "Sales/Purchases"
}
\ No newline at end of file
diff --git a/client/src/style/App.scss b/client/src/style/App.scss
index 9426135d6..dee79b591 100644
--- a/client/src/style/App.scss
+++ b/client/src/style/App.scss
@@ -47,11 +47,13 @@ body.hide-scrollbar .Pane2 {
}
.bp3-fill {
+
.bp3-popover-wrapper,
.bp3-popover-target {
display: block;
width: 100%;
}
+
.bp3-button {
width: 100%;
justify-content: start;
@@ -61,6 +63,7 @@ body.hide-scrollbar .Pane2 {
.bp3-datepicker-caption .bp3-html-select::after {
margin-right: 6px;
}
+
.bp3-select-popover .bp3-menu {
max-height: 300px;
max-width: 400px;
@@ -100,27 +103,21 @@ body.hide-scrollbar .Pane2 {
background-color: rgba(0, 10, 30, 0.7);
}
-.ReactVirtualized__Collection {
-}
+.ReactVirtualized__Collection {}
-.ReactVirtualized__Collection__innerScrollContainer {
-}
+.ReactVirtualized__Collection__innerScrollContainer {}
/* Grid default theme */
-.ReactVirtualized__Grid {
-}
+.ReactVirtualized__Grid {}
-.ReactVirtualized__Grid__innerScrollContainer {
-}
+.ReactVirtualized__Grid__innerScrollContainer {}
/* Table default theme */
-.ReactVirtualized__Table {
-}
+.ReactVirtualized__Table {}
-.ReactVirtualized__Table__Grid {
-}
+.ReactVirtualized__Table__Grid {}
.ReactVirtualized__Table__headerRow {
font-weight: 700;
@@ -129,6 +126,7 @@ body.hide-scrollbar .Pane2 {
flex-direction: row;
align-items: center;
}
+
.ReactVirtualized__Table__row {
display: flex;
flex-direction: row;
@@ -148,6 +146,7 @@ body.hide-scrollbar .Pane2 {
margin-right: 10px;
min-width: 0px;
}
+
.ReactVirtualized__Table__rowColumn {
text-overflow: ellipsis;
white-space: nowrap;
@@ -157,6 +156,7 @@ body.hide-scrollbar .Pane2 {
.ReactVirtualized__Table__rowColumn:first-of-type {
margin-left: 10px;
}
+
.ReactVirtualized__Table__sortableHeaderColumn {
cursor: pointer;
}
@@ -165,32 +165,157 @@ body.hide-scrollbar .Pane2 {
display: flex;
align-items: center;
}
+
.ReactVirtualized__Table__sortableHeaderIcon {
flex: 0 0 24px;
height: 1em;
width: 1em;
fill: currentColor;
}
-.ReactVirtualized__Grid, .ReactVirtualized__List { direction: inherit !important; }
-/* List default theme */
+.ReactVirtualized__Grid,
.ReactVirtualized__List {
+ direction: inherit !important;
}
+/* List default theme */
-.bp3-drawer{
+.ReactVirtualized__List {}
+
+
+.bp3-drawer {
box-shadow: 0 0 0;
}
// RTL Icons.
html[dir="rtl"] {
- .bp3-icon-caret-right{
+ .bp3-icon-caret-right {
transform: scaleX(-1);
}
}
html[lang^="ar"] {
- body{
+ body {
letter-spacing: -0.01rem;
}
+}
+
+
+.sidebar-overlay {
+ background: #fff;
+ height: 100%;
+ width: 225px;
+ outline: 0;
+
+ &__scroll-wrapper {
+ height: 100%
+ }
+
+ .ScrollbarsCustom-Track {
+
+ &.ScrollbarsCustom-TrackY,
+ &.ScrollbarsCustom-TrackX {
+ background: rgba(0, 0, 0, 0);
+ }
+ }
+
+ .ScrollbarsCustom-Thumb {
+
+ &.ScrollbarsCustom-ThumbX,
+ &.ScrollbarsCustom-ThumbY {
+ background: rgba(0, 0, 0, 0);
+ }
+ }
+
+ .ScrollbarsCustom-Content {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ }
+
+ &:hover {
+ .ScrollbarsCustom-Thumb {
+
+ &.ScrollbarsCustom-ThumbX,
+ &.ScrollbarsCustom-ThumbY {
+ background: rgba(0, 0, 0, 0.5);
+ }
+ }
+ }
+
+ &__menu {
+ margin: 16px 0;
+ }
+
+ &__item {
+ font-size: 15px;
+ color: #00102b;
+
+ a {
+ color: inherit;
+ display: block;
+ padding: 10px 22px;
+ text-decoration: none;
+
+ &:hover,
+ &:focus{
+ background: #f3f3f3;
+ }
+ }
+ }
+
+ &__divider {
+ height: 1px;
+ margin: 6px 0;
+ background: #e2e5ec;
+ }
+
+ &__label{
+ text-transform: uppercase;
+ font-size: 12px;
+ 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 100ms ease-in-out;
+ }
+
+ &-appear-done,
+ &-enter-done {
+ transform: translateX(0) !important;
+ }
+
+ &-exit {
+ transform: translateX(0) !important;
+ }
+ &-exit-active {
+ transform: translateX(-100%) !important;
+ transition: all 100ms ease-in-out;
+ }
+ &-exit-done{
+ transform: translateX(-100%) !important;
+ }
+ }
+
+}
+.sidebar-overlay-backdrop{
+ background-color: rgba(0, 10, 30, 0.15);
}
\ No newline at end of file
diff --git a/client/src/style/containers/Dashboard/Sidebar.scss b/client/src/style/containers/Dashboard/Sidebar.scss
index 66ba237a3..392a31d0e 100644
--- a/client/src/style/containers/Dashboard/Sidebar.scss
+++ b/client/src/style/containers/Dashboard/Sidebar.scss
@@ -6,6 +6,7 @@
color: $sidebar-text-color;
height: 100%;
z-index: $sidebar-zindex;
+ position: relative;
.ScrollbarsCustom-Track {
@@ -347,5 +348,11 @@
margin-left: 12px;
font-weight: 600;
}
+
+ &__divider{
+ margin: 4px 0;
+ height: 1px;
+ background: #ebebeb;
+ }
}
}
diff --git a/client/src/style/variables.scss b/client/src/style/variables.scss
index 02561ebe9..38f267d88 100644
--- a/client/src/style/variables.scss
+++ b/client/src/style/variables.scss
@@ -15,7 +15,7 @@ $menu-item-color-active: $light-gray3;
$breadcrumbs-collapsed-icon: url("data:image/svg+xml,");
-$sidebar-zindex: 15;
+$sidebar-zindex: 21;
$pt-font-family: 'Noto Sans', -apple-system, BlinkMacSystemFont,
Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Open Sans, Helvetica Neue,
Icons16, sans-serif;