datastake-daf 0.6.526 → 0.6.528
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/context/index.js +10 -22
- package/dist/layouts/index.css +1 -1
- package/dist/layouts/index.js +71 -89
- package/package.json +1 -1
- package/src/@daf/core/context/Resize/index.js +12 -22
- package/src/@daf/layouts/AppLayout/AppLayout.stories.js +194 -2
- package/src/@daf/layouts/AppLayout/components/MobileDrawer/index.js +2 -4
- package/src/@daf/layouts/AppLayout/components/Sidenav/index.js +43 -56
- package/src/@daf/layouts/AppLayout/index.jsx +24 -20
- package/src/@daf/layouts/AppLayout/styles/variables.scss +8 -7
package/dist/context/index.js
CHANGED
|
@@ -33,17 +33,6 @@ const ResizeProvider = ({
|
|
|
33
33
|
const [isNestedSidebarCollapsed, setIsNestedSidebarCollapsed] = React.useState(_isNestedSidebarCollapsed);
|
|
34
34
|
const [loading, setLoading] = React.useState(false);
|
|
35
35
|
const [dif, setDif] = React.useState();
|
|
36
|
-
|
|
37
|
-
// ADD THIS DEBUG
|
|
38
|
-
console.log('ResizeProvider render - isCollapsed:', isCollapsed);
|
|
39
|
-
|
|
40
|
-
// Wrap setIsCollapsed to add debugging
|
|
41
|
-
const setIsCollapsedDebug = React__default["default"].useCallback(value => {
|
|
42
|
-
console.log('ResizeProvider: setIsCollapsed called with:', value);
|
|
43
|
-
console.log('ResizeProvider: current isCollapsed:', isCollapsed);
|
|
44
|
-
setIsCollapsed(value);
|
|
45
|
-
console.log('ResizeProvider: setIsCollapsed done');
|
|
46
|
-
}, [isCollapsed]);
|
|
47
36
|
const resizeEvent = React.useCallback(() => {
|
|
48
37
|
setLoading(true);
|
|
49
38
|
clearTimeout(timeOut);
|
|
@@ -56,20 +45,19 @@ const ResizeProvider = ({
|
|
|
56
45
|
}, [windowWidth]);
|
|
57
46
|
React.useEffect(() => {
|
|
58
47
|
window.addEventListener('resize', resizeEvent);
|
|
48
|
+
// Fix: Should remove the event listener on cleanup
|
|
59
49
|
return () => window.removeEventListener('resize', resizeEvent);
|
|
60
50
|
}, [resizeEvent]);
|
|
61
|
-
const value = React__default["default"].useMemo(() => ({
|
|
62
|
-
resizeLoading: loading,
|
|
63
|
-
windowWidth,
|
|
64
|
-
resizeDif: dif,
|
|
65
|
-
isCollapsed,
|
|
66
|
-
setIsCollapsed: setIsCollapsedDebug,
|
|
67
|
-
// Use the debug wrapper
|
|
68
|
-
isNestedSidebarCollapsed,
|
|
69
|
-
setIsNestedSidebarCollapsed
|
|
70
|
-
}), [loading, windowWidth, dif, isCollapsed, isNestedSidebarCollapsed, setIsCollapsedDebug]);
|
|
71
51
|
return /*#__PURE__*/React__default["default"].createElement(ResizeContext.Provider, {
|
|
72
|
-
value
|
|
52
|
+
value: {
|
|
53
|
+
resizeLoading: loading,
|
|
54
|
+
windowWidth,
|
|
55
|
+
resizeDif: dif,
|
|
56
|
+
isCollapsed,
|
|
57
|
+
setIsCollapsed,
|
|
58
|
+
isNestedSidebarCollapsed,
|
|
59
|
+
setIsNestedSidebarCollapsed
|
|
60
|
+
}
|
|
73
61
|
}, children);
|
|
74
62
|
};
|
|
75
63
|
const useResizeContext = () => {
|
package/dist/layouts/index.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.index_components-layout__BppiJ{display:flex;flex-direction:row;height:100dvh;max-height:100dvh;overflow:hidden;width:100vw}.index_components-layout__BppiJ .index_layout-content-wrapper__ANOdo{display:flex;flex-direction:column;min-height:100dvh;width:100%}.index_layout-children__gWZas{background:#fff;flex:1;min-height:calc(100vh - 64px);overflow-y:auto;padding:24px;position:relative}@media (max-width:768px){.index_layout-children__gWZas{padding:16px}}.index_mod-name__ZAqSo{align-items:center;border-bottom:1px solid
|
|
1
|
+
.index_components-layout__BppiJ{display:flex;flex-direction:row;height:100dvh;max-height:100dvh;overflow:hidden;width:100vw}.index_components-layout__BppiJ .index_layout-content-wrapper__ANOdo{display:flex;flex-direction:column;min-height:100dvh;width:100%}.index_layout-children__gWZas{background:#fff;flex:1;min-height:calc(100vh - 64px);overflow-y:auto;padding:24px;position:relative}@media (max-width:768px){.index_layout-children__gWZas{padding:16px}}.index_mod-name__ZAqSo{align-items:center;border-bottom:1px solid var(--layout-border-color,#ffffff1a);color:var(--layout-text-primary,#fff);cursor:pointer;display:flex;gap:12px;padding:20px;transition:all .3s}.index_mod-name__ZAqSo:hover{background:var(--layout-hover-bg,#ffffff1a)}.index_mod-name__ZAqSo.index_is-collapsed__4rEBC{justify-content:center;padding:20px 10px}.index_mod-name__ZAqSo.index_is-collapsed__4rEBC h1{display:none}.index_mod-name__ZAqSo .index_icon__tIPRE{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.index_mod-name__ZAqSo .index_icon__tIPRE img,.index_mod-name__ZAqSo .index_icon__tIPRE svg{height:100%;object-fit:contain;width:100%}.index_mod-name__ZAqSo h1{font-size:16px;font-weight:600;line-height:1.2;margin:0}.index_layout-header__uP-hH{align-items:center;background:var(--layout-primary-bg,#1a1d29);box-shadow:0 2px 8px #00000026;display:flex;height:64px;justify-content:space-between;padding:0 24px;position:relative;z-index:1000}.index_layout-header__uP-hH .index_left-sidebar__rf0f7,.index_layout-header__uP-hH .index_right-sidebar__b2OCD{align-items:center;display:flex;gap:16px}.index_layout-header__uP-hH .index_left-sidebar__rf0f7{flex:1}.index_layout-header__uP-hH .index_trigger__UMbTb{color:var(--layout-text-primary,#fff);cursor:pointer;font-size:18px;line-height:64px;margin:0 -24px 0 0;padding:0 24px;transition:color .3s}.index_layout-header__uP-hH .index_trigger__UMbTb:hover{color:#1890ff}.index_layout-header__uP-hH .index_desktop__sAat1{display:flex}@media (max-width:768px){.index_layout-header__uP-hH .index_desktop__sAat1{display:none}}.index_layout-header__uP-hH .index_mobile__exhDj{display:none}@media (max-width:768px){.index_layout-header__uP-hH .index_mobile__exhDj{align-items:center;cursor:pointer;display:flex}}.index_layout-header__uP-hH .index_mobile__exhDj img{height:32px;width:auto}.index_layout-header__uP-hH .index_mobile__exhDj .index_mobile-burger__HLNGn{color:var(--layout-text-primary,#fff);font-size:20px}.index_layout-header__uP-hH .index_notification-icon__rzMrK{align-items:center;color:var(--layout-text-primary,#fff);cursor:pointer;display:flex;font-size:18px;padding:8px;position:relative;transition:color .3s}.index_layout-header__uP-hH .index_notification-icon__rzMrK:hover{color:#1890ff}.index_layout-header__uP-hH .index_notification-icon__rzMrK .index_noti-loader__OF-Nt{animation:index_pulse__tnSN4 2s infinite;background:#52c41a;border-radius:50%;height:8px;position:absolute;right:5px;top:5px;width:8px}.index_layout-header__uP-hH .index_notification-icon__rzMrK .index_noti-more-cont__Glzl6{align-items:center;background:#ff4d4f;border-radius:10px;color:#fff;display:flex;font-size:12px;font-weight:600;height:18px;justify-content:center;min-width:18px;padding:2px 6px;position:absolute;right:5px;top:5px}.index_layout-header__uP-hH .index_language-select__eSaHK{min-width:100px}.index_layout-header__uP-hH .index_language-select__eSaHK .index_ant-select-selector__G-MXN{background:#0000!important;border:none!important;box-shadow:none!important;color:var(--layout-text-primary,#fff)!important}.index_layout-header__uP-hH .index_language-select__eSaHK .index_ant-select-arrow__hcasC{color:var(--layout-text-primary,#fff)}.index_layout-header__uP-hH .index_language-select__eSaHK .index_row-cont__G2wqI{align-items:center;display:flex;gap:8px}.index_layout-header__uP-hH .index_user-details__TajEC{align-items:center;display:flex}.index_dark-select-popup__-UN-9.index_ant-select-dropdown__PAJxh{background:var(--layout-primary-bg,#1a1d29)}.index_dark-select-popup__-UN-9.index_ant-select-dropdown__PAJxh .index_ant-select-item__-KnB8{color:var(--layout-text-primary,#fff)}.index_dark-select-popup__-UN-9.index_ant-select-dropdown__PAJxh .index_ant-select-item-option-selected__C7atp,.index_dark-select-popup__-UN-9.index_ant-select-dropdown__PAJxh .index_ant-select-item__-KnB8:hover{background:var(--layout-hover-bg,#ffffff1a)}.index_user-dropdown-layout__jsdUj.index_ant-dropdown__yk3cn .index_ant-dropdown-menu__-Vi2g{min-width:200px;padding:0}.index_user-dropdown-layout__jsdUj.index_ant-dropdown__yk3cn .index_ant-dropdown-menu__-Vi2g .index_ant-dropdown-menu-item__cxyFd{padding:0}.index_user-dropdown-layout__jsdUj.index_ant-dropdown__yk3cn .index_ant-dropdown-menu__-Vi2g .index_ant-dropdown-menu-item__cxyFd:hover{background:#0000}.index_user-dropdown-layout__jsdUj .index_drop-header__4udrF{border-bottom:1px solid #f0f0f0;padding:16px}.index_user-dropdown-layout__jsdUj .index_drop-header__4udrF h4{color:#262626;font-size:14px;font-weight:600;margin:0 0 4px}.index_user-dropdown-layout__jsdUj .index_drop-header__4udrF p{color:var(--layout-text-secondary,#8c8c8c);font-size:12px;margin:0}.index_user-dropdown-layout__jsdUj .index_list__JZPtv{padding:8px 0}.index_user-dropdown-layout__jsdUj .index_list__JZPtv .index_list-item__jgxiJ{color:#262626;cursor:pointer;font-size:14px;padding:10px 16px;transition:background .3s}.index_user-dropdown-layout__jsdUj .index_list__JZPtv .index_list-item__jgxiJ:hover{background:#f5f5f5}.index_dark-menu__oxCSP.index_ant-dropdown__yk3cn .index_ant-dropdown-menu__-Vi2g{background:var(--layout-primary-bg,#1a1d29);padding:4px 0}.index_dark-menu__oxCSP.index_ant-dropdown__yk3cn .index_ant-dropdown-menu__-Vi2g .index_ant-dropdown-menu-item__cxyFd{align-items:center;color:var(--layout-text-primary,#fff);display:flex;gap:8px;padding:8px 12px}.index_dark-menu__oxCSP.index_ant-dropdown__yk3cn .index_ant-dropdown-menu__-Vi2g .index_ant-dropdown-menu-item__cxyFd:hover{background:var(--layout-hover-bg,#ffffff1a)}.index_dark-menu__oxCSP.index_ant-dropdown__yk3cn .index_ant-dropdown-menu__-Vi2g .index_ant-dropdown-menu-item-disabled__8Zr1C{color:#ffffff4d;cursor:not-allowed}.index_dark-menu__oxCSP.index_ant-dropdown__yk3cn .index_ant-dropdown-menu__-Vi2g .index_ant-dropdown-menu-item-disabled__8Zr1C:hover{background:#0000}.index_dark-menu__oxCSP.index_ant-dropdown__yk3cn .index_ant-dropdown-menu__-Vi2g .index_ant-dropdown-menu-item__cxyFd .index_anticon__mmT-3{color:var(--layout-text-primary,#fff)}@keyframes index_pulse__tnSN4{0%{box-shadow:0 0 0 0 #52c41ab3}70%{box-shadow:0 0 0 6px #52c41a00}to{box-shadow:0 0 0 0 #52c41a00}}.index_sidenav-sider__hWcZw{background:var(--layout-primary-bg,#1a1d29);display:flex;flex-direction:column;height:100dvh;position:relative;transition:all .3s;z-index:999}@media (max-width:768px){.index_sidenav-sider__hWcZw.index_desktop-sider__qQ7Y5{display:none}}.index_sidenav-sider__hWcZw .index_logo__ThlDP{background:var(--layout-primary-bg,#1a1d29);border-bottom:1px solid var(--layout-border-color,#ffffff1a);padding:20px;text-align:center}.index_sidenav-sider__hWcZw .index_logo__ThlDP img{cursor:pointer;height:auto;max-height:40px;max-width:100%;object-fit:contain;transition:all .3s}.index_sidenav-sider__hWcZw .index_logo__ThlDP img:hover{opacity:.8}.index_sidenav-sider__hWcZw.index_sidenav-sider-collapsed__PBdKB{min-width:70px!important;width:70px!important}.index_sidenav-sider__hWcZw.index_sidenav-sider-collapsed__PBdKB .index_logo__ThlDP{padding:20px 10px}.index_sidenav-sider__hWcZw.index_sidenav-sider-collapsed__PBdKB .index_logo__ThlDP img{max-height:32px}.index_sidenav-sider__hWcZw.index_sidenav-sider-opened__tBCYr{min-width:250px;width:250px}.index_sidenav-menu__etWhC{flex:1;overflow-x:hidden;overflow-y:auto}.index_sidenav-menu__etWhC::-webkit-scrollbar{width:6px}.index_sidenav-menu__etWhC::-webkit-scrollbar-track{background:#0000}.index_sidenav-menu__etWhC::-webkit-scrollbar-thumb{background:#fff3;border-radius:3px}.index_sidenav-menu__etWhC::-webkit-scrollbar-thumb:hover{background:#ffffff4d}@media (max-width:768px){.index_components-layout__BppiJ .index_sidenav-sider__hWcZw.index_desktop-sider__qQ7Y5{display:none}.index_components-layout__BppiJ .index_layout-header__uP-hH{padding:0 16px}.index_components-layout__BppiJ .index_layout-header__uP-hH .index_left-sidebar__rf0f7,.index_components-layout__BppiJ .index_layout-header__uP-hH .index_right-sidebar__b2OCD{gap:12px}.index_components-layout__BppiJ .index_layout-children__gWZas,.index_user-dropdown-layout__jsdUj .index_drop-header__4udrF{padding:12px}.index_user-dropdown-layout__jsdUj .index_drop-header__4udrF h4{font-size:13px}.index_user-dropdown-layout__jsdUj .index_drop-header__4udrF p{font-size:11px}.index_user-dropdown-layout__jsdUj .index_list__JZPtv .index_list-item__jgxiJ{font-size:13px;padding:8px 12px}}@media (min-width:1920px){.index_layout-children__gWZas{margin:0 auto;max-width:1600px}}
|
package/dist/layouts/index.js
CHANGED
|
@@ -5098,73 +5098,53 @@ const PageInterface = ({
|
|
|
5098
5098
|
})]
|
|
5099
5099
|
});
|
|
5100
5100
|
};
|
|
5101
|
+
|
|
5102
|
+
/**
|
|
5103
|
+
* Renders the module interface based on configuration
|
|
5104
|
+
*
|
|
5105
|
+
* @param {Object} params
|
|
5106
|
+
* @param {boolean} params.isCollapsed - Whether the sidebar is collapsed
|
|
5107
|
+
* @param {Function} params.onClick - Click handler for the module interface
|
|
5108
|
+
* @param {Object|null} params.moduleInterfaceConfig - Configuration for the module interface
|
|
5109
|
+
*
|
|
5110
|
+
* @example
|
|
5111
|
+
* // The app determines the role and passes the appropriate config:
|
|
5112
|
+
* const moduleInterfaceConfig = {
|
|
5113
|
+
* title: "Implementer",
|
|
5114
|
+
* icon: "/assets/images/SVG/implementer.svg" // or icon: <CustomIcon />
|
|
5115
|
+
* }
|
|
5116
|
+
*
|
|
5117
|
+
* // Or for admin:
|
|
5118
|
+
* const moduleInterfaceConfig = {
|
|
5119
|
+
* title: "ADMIN",
|
|
5120
|
+
* icon: <svg>...</svg>
|
|
5121
|
+
* }
|
|
5122
|
+
*/
|
|
5101
5123
|
const renderModule = ({
|
|
5102
5124
|
isCollapsed,
|
|
5103
5125
|
onClick,
|
|
5104
|
-
|
|
5105
|
-
userHelpers = {},
|
|
5106
|
-
goTo = () => {}
|
|
5126
|
+
moduleInterfaceConfig = null
|
|
5107
5127
|
}) => {
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
userIsSbgPartner
|
|
5112
|
-
} = userHelpers;
|
|
5113
|
-
const isAdmin = userIsAdmin?.(user);
|
|
5114
|
-
const hasStandardInterface = userIsSbgImplementor?.(user);
|
|
5115
|
-
const hasPartnerInterface = userIsSbgPartner?.(user);
|
|
5116
|
-
if (isAdmin) {
|
|
5117
|
-
return /*#__PURE__*/jsxRuntime.jsx(PageInterface, {
|
|
5118
|
-
isCollapsed: isCollapsed,
|
|
5119
|
-
onClick: onClick,
|
|
5120
|
-
title: "ADMIN",
|
|
5121
|
-
children: /*#__PURE__*/jsxRuntime.jsx("svg", {
|
|
5122
|
-
viewBox: "0 0 14 14",
|
|
5123
|
-
fill: "none",
|
|
5124
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
5125
|
-
width: "14",
|
|
5126
|
-
height: "14",
|
|
5127
|
-
children: /*#__PURE__*/jsxRuntime.jsx("path", {
|
|
5128
|
-
d: "M9.03367 5H2.66667C1.74619 5 1 4.25381 1 3.33333C1 2.41286 1.74619 1.66667 2.66667 1.66667H9.03367M4.96633 12.3333H11.3333C12.2538 12.3333 13 11.5871 13 10.6667C13 9.74619 12.2538 9 11.3333 9H4.96633M1 10.6667C1 11.9553 2.04467 13 3.33333 13C4.622 13 5.66667 11.9553 5.66667 10.6667C5.66667 9.378 4.622 8.33333 3.33333 8.33333C2.04467 8.33333 1 9.378 1 10.6667ZM13 3.33333C13 4.622 11.9553 5.66667 10.6667 5.66667C9.378 5.66667 8.33333 4.622 8.33333 3.33333C8.33333 2.04467 9.378 1 10.6667 1C11.9553 1 13 2.04467 13 3.33333Z",
|
|
5129
|
-
stroke: "#B9C0D4",
|
|
5130
|
-
strokeWidth: "1.2",
|
|
5131
|
-
strokeLinecap: "round",
|
|
5132
|
-
strokeLinejoin: "round"
|
|
5133
|
-
})
|
|
5134
|
-
})
|
|
5135
|
-
});
|
|
5136
|
-
}
|
|
5137
|
-
if (hasStandardInterface) {
|
|
5138
|
-
return /*#__PURE__*/jsxRuntime.jsx(PageInterface, {
|
|
5139
|
-
isCollapsed: isCollapsed,
|
|
5140
|
-
onClick: onClick,
|
|
5141
|
-
title: "Implementer",
|
|
5142
|
-
children: /*#__PURE__*/jsxRuntime.jsx("img", {
|
|
5143
|
-
src: "/assets/images/SVG/implementer.svg",
|
|
5144
|
-
alt: "implementer"
|
|
5145
|
-
})
|
|
5146
|
-
});
|
|
5147
|
-
} else if (hasPartnerInterface) {
|
|
5148
|
-
return /*#__PURE__*/jsxRuntime.jsx(PageInterface, {
|
|
5149
|
-
isCollapsed: isCollapsed,
|
|
5150
|
-
onClick: onClick,
|
|
5151
|
-
title: "Partner",
|
|
5152
|
-
children: /*#__PURE__*/jsxRuntime.jsx("img", {
|
|
5153
|
-
src: "/assets/images/SVG/partner-building.svg",
|
|
5154
|
-
alt: "partner"
|
|
5155
|
-
})
|
|
5156
|
-
});
|
|
5157
|
-
} else if (!hasStandardInterface) {
|
|
5158
|
-
return /*#__PURE__*/jsxRuntime.jsx(PageInterface, {
|
|
5159
|
-
isCollapsed: isCollapsed,
|
|
5160
|
-
onClick: onClick,
|
|
5161
|
-
title: "Coordinator",
|
|
5162
|
-
children: /*#__PURE__*/jsxRuntime.jsx("img", {
|
|
5163
|
-
src: "/assets/images/SVG/coordinator.svg",
|
|
5164
|
-
alt: "coordinator"
|
|
5165
|
-
})
|
|
5166
|
-
});
|
|
5128
|
+
// If no config provided, don't render anything
|
|
5129
|
+
if (!moduleInterfaceConfig) {
|
|
5130
|
+
return null;
|
|
5167
5131
|
}
|
|
5132
|
+
const {
|
|
5133
|
+
title,
|
|
5134
|
+
icon
|
|
5135
|
+
} = moduleInterfaceConfig;
|
|
5136
|
+
|
|
5137
|
+
// Convert string icon paths to img elements
|
|
5138
|
+
const iconElement = typeof icon === 'string' ? /*#__PURE__*/jsxRuntime.jsx("img", {
|
|
5139
|
+
src: icon,
|
|
5140
|
+
alt: title.toLowerCase()
|
|
5141
|
+
}) : icon;
|
|
5142
|
+
return /*#__PURE__*/jsxRuntime.jsx(PageInterface, {
|
|
5143
|
+
isCollapsed: isCollapsed,
|
|
5144
|
+
onClick: onClick,
|
|
5145
|
+
title: title,
|
|
5146
|
+
children: iconElement
|
|
5147
|
+
});
|
|
5168
5148
|
};
|
|
5169
5149
|
const Sidenav = ({
|
|
5170
5150
|
user,
|
|
@@ -5178,6 +5158,7 @@ const Sidenav = ({
|
|
|
5178
5158
|
t,
|
|
5179
5159
|
changeNotificationState,
|
|
5180
5160
|
userHelpers = {},
|
|
5161
|
+
moduleInterfaceConfig = null,
|
|
5181
5162
|
isDev = false,
|
|
5182
5163
|
appName = 'app',
|
|
5183
5164
|
getRedirectLink = () => {},
|
|
@@ -5197,7 +5178,7 @@ const Sidenav = ({
|
|
|
5197
5178
|
const {
|
|
5198
5179
|
pathname
|
|
5199
5180
|
} = location || {};
|
|
5200
|
-
|
|
5181
|
+
o.useMemo(() => module, [module, user]);
|
|
5201
5182
|
const checkPath = i => {
|
|
5202
5183
|
if (!matchPath || !pathname) return false;
|
|
5203
5184
|
return matchPath({
|
|
@@ -5305,17 +5286,14 @@ const Sidenav = ({
|
|
|
5305
5286
|
setSelectedKeys([pathname]);
|
|
5306
5287
|
}
|
|
5307
5288
|
}, [pathname]);
|
|
5308
|
-
|
|
5289
|
+
o.useMemo(() => module, [user, module]);
|
|
5309
5290
|
return /*#__PURE__*/jsxRuntime.jsxs(o__default["default"].Fragment, {
|
|
5310
5291
|
children: [renderModule({
|
|
5311
|
-
module: userModule,
|
|
5312
5292
|
isCollapsed,
|
|
5313
5293
|
onClick: () => checkOnClick({
|
|
5314
5294
|
event: () => goTo(getRedirectLink(`/app`))
|
|
5315
5295
|
}),
|
|
5316
|
-
|
|
5317
|
-
user,
|
|
5318
|
-
userHelpers
|
|
5296
|
+
moduleInterfaceConfig
|
|
5319
5297
|
}), /*#__PURE__*/jsxRuntime.jsx(Sidenav$1, {
|
|
5320
5298
|
module: module,
|
|
5321
5299
|
isCollapsed: isCollapsed,
|
|
@@ -5893,6 +5871,7 @@ function MobileDrawer({
|
|
|
5893
5871
|
isUserDropdown = false,
|
|
5894
5872
|
user,
|
|
5895
5873
|
sidenavConfig = {},
|
|
5874
|
+
moduleInterfaceConfig = null,
|
|
5896
5875
|
goTo = () => {},
|
|
5897
5876
|
getRedirectLink = () => {},
|
|
5898
5877
|
t = key => key,
|
|
@@ -6012,10 +5991,7 @@ function MobileDrawer({
|
|
|
6012
5991
|
className: "flex-1",
|
|
6013
5992
|
children: mod === 'app' || !user ? null : renderModule({
|
|
6014
5993
|
isCollapsed,
|
|
6015
|
-
|
|
6016
|
-
module: mod,
|
|
6017
|
-
user,
|
|
6018
|
-
userHelpers
|
|
5994
|
+
moduleInterfaceConfig
|
|
6019
5995
|
})
|
|
6020
5996
|
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
6021
5997
|
className: "cursor-pointer close-icon",
|
|
@@ -6947,6 +6923,8 @@ const {
|
|
|
6947
6923
|
* @param {Object} props.appLogos - Logo URLs { collapsed, expanded }
|
|
6948
6924
|
* @param {Object} props.languageConfig - Language selector configuration
|
|
6949
6925
|
* @param {Function} props.renderChildren - Custom render function for children
|
|
6926
|
+
* @param {Object} props.theme - Theme object with layout color customization
|
|
6927
|
+
* @param {Object|null} props.moduleInterfaceConfig - Module interface config { title, icon }
|
|
6950
6928
|
*/
|
|
6951
6929
|
function AppLayout({
|
|
6952
6930
|
// User & Auth
|
|
@@ -6986,6 +6964,7 @@ function AppLayout({
|
|
|
6986
6964
|
setIsCollapsed,
|
|
6987
6965
|
// Config
|
|
6988
6966
|
sidenavConfig = {},
|
|
6967
|
+
moduleInterfaceConfig = null,
|
|
6989
6968
|
appName = 'app',
|
|
6990
6969
|
appLogos = {
|
|
6991
6970
|
collapsed: '/assets/images/logo-small.svg',
|
|
@@ -7008,6 +6987,8 @@ function AppLayout({
|
|
|
7008
6987
|
onCollapse = () => {},
|
|
7009
6988
|
// Custom renderers
|
|
7010
6989
|
renderChildren,
|
|
6990
|
+
// Theme
|
|
6991
|
+
theme = {},
|
|
7011
6992
|
// Children
|
|
7012
6993
|
children
|
|
7013
6994
|
}) {
|
|
@@ -7019,9 +7000,6 @@ function AppLayout({
|
|
|
7019
7000
|
const {
|
|
7020
7001
|
logOutPopupVisible = false
|
|
7021
7002
|
} = generalContext;
|
|
7022
|
-
o.useEffect(() => {
|
|
7023
|
-
console.log('isCollapsed changed to:', isCollapsed);
|
|
7024
|
-
}, [isCollapsed]);
|
|
7025
7003
|
const canViewNotifications = checkPermission({
|
|
7026
7004
|
permission: 'notifications.canView',
|
|
7027
7005
|
permissions: user?.role?.permissions
|
|
@@ -7042,13 +7020,8 @@ function AppLayout({
|
|
|
7042
7020
|
_fetchPreferences();
|
|
7043
7021
|
}, [getUserPreference]);
|
|
7044
7022
|
const setIsCollapse = (val = false) => {
|
|
7045
|
-
console.log('setIsCollapse called with:', val);
|
|
7046
|
-
console.log('setIsCollapsed function:', setIsCollapsed);
|
|
7047
|
-
console.log('typeof setIsCollapsed:', typeof setIsCollapsed);
|
|
7048
7023
|
localStorage.setItem('is_collapsed', val ? 'true' : 'false');
|
|
7049
|
-
console.log('Calling setIsCollapsed with:', val);
|
|
7050
7024
|
setIsCollapsed(val);
|
|
7051
|
-
console.log('setIsCollapsed called');
|
|
7052
7025
|
if (onCollapse && typeof onCollapse === 'function') {
|
|
7053
7026
|
onCollapse(val);
|
|
7054
7027
|
}
|
|
@@ -7100,14 +7073,23 @@ function AppLayout({
|
|
|
7100
7073
|
onYes: () => goTo(getRedirectLink('/app'))
|
|
7101
7074
|
});
|
|
7102
7075
|
};
|
|
7076
|
+
|
|
7077
|
+
// Apply theme CSS custom properties
|
|
7078
|
+
const layoutStyle = o.useMemo(() => ({
|
|
7079
|
+
display: 'flex',
|
|
7080
|
+
flexDirection: 'row',
|
|
7081
|
+
width: '100vw',
|
|
7082
|
+
height: '100dvh',
|
|
7083
|
+
maxHeight: '100dvh',
|
|
7084
|
+
'--layout-primary-bg': theme.layoutPrimaryBg,
|
|
7085
|
+
'--layout-secondary-bg': theme.layoutSecondaryBg,
|
|
7086
|
+
'--layout-border-color': theme.layoutBorderColor,
|
|
7087
|
+
'--layout-text-primary': theme.layoutTextPrimary,
|
|
7088
|
+
'--layout-text-secondary': theme.layoutTextSecondary,
|
|
7089
|
+
'--layout-hover-bg': theme.layoutHoverBg
|
|
7090
|
+
}), [theme]);
|
|
7103
7091
|
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
7104
|
-
style:
|
|
7105
|
-
display: 'flex',
|
|
7106
|
-
flexDirection: 'row',
|
|
7107
|
-
width: '100vw',
|
|
7108
|
-
height: '100dvh',
|
|
7109
|
-
maxHeight: '100dvh'
|
|
7110
|
-
},
|
|
7092
|
+
style: layoutStyle,
|
|
7111
7093
|
className: "components-layout",
|
|
7112
7094
|
children: [!isAppNavigation ? /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
7113
7095
|
className: formatClassname([isCollapsed ? 'sidenav-sider-collapsed sidenav-sider desktop-sider' : 'sidenav-sider sidenav-sider-opened desktop-sider', appName]),
|
|
@@ -7129,6 +7111,7 @@ function AppLayout({
|
|
|
7129
7111
|
isCollapsed: isCollapsed,
|
|
7130
7112
|
user: user,
|
|
7131
7113
|
sidenavConfig: sidenavConfig,
|
|
7114
|
+
moduleInterfaceConfig: moduleInterfaceConfig,
|
|
7132
7115
|
goTo: goTo,
|
|
7133
7116
|
location: location,
|
|
7134
7117
|
matchPath: matchPath,
|
|
@@ -7159,9 +7142,7 @@ function AppLayout({
|
|
|
7159
7142
|
children: isAppNavigation ? null : /*#__PURE__*/o__default["default"].createElement(isCollapsed ? icons.MenuUnfoldOutlined : icons.MenuFoldOutlined, {
|
|
7160
7143
|
className: 'trigger',
|
|
7161
7144
|
onClick: () => {
|
|
7162
|
-
console.log('Trigger clicked! Current isCollapsed:', isCollapsed);
|
|
7163
7145
|
const newValue = !isCollapsed;
|
|
7164
|
-
console.log('Setting to:', newValue);
|
|
7165
7146
|
setIsCollapse(newValue);
|
|
7166
7147
|
}
|
|
7167
7148
|
})
|
|
@@ -7281,6 +7262,7 @@ function AppLayout({
|
|
|
7281
7262
|
drawerOpened: drawerOpened,
|
|
7282
7263
|
user: user,
|
|
7283
7264
|
sidenavConfig: sidenavConfig,
|
|
7265
|
+
moduleInterfaceConfig: moduleInterfaceConfig,
|
|
7284
7266
|
navigate: goTo,
|
|
7285
7267
|
t: t,
|
|
7286
7268
|
checkPermission: checkPermission,
|
package/package.json
CHANGED
|
@@ -25,17 +25,6 @@ export const ResizeProvider = ({ children }) => {
|
|
|
25
25
|
const [loading, setLoading] = useState(false);
|
|
26
26
|
const [dif, setDif] = useState();
|
|
27
27
|
|
|
28
|
-
// ADD THIS DEBUG
|
|
29
|
-
console.log('ResizeProvider render - isCollapsed:', isCollapsed);
|
|
30
|
-
|
|
31
|
-
// Wrap setIsCollapsed to add debugging
|
|
32
|
-
const setIsCollapsedDebug = React.useCallback((value) => {
|
|
33
|
-
console.log('ResizeProvider: setIsCollapsed called with:', value);
|
|
34
|
-
console.log('ResizeProvider: current isCollapsed:', isCollapsed);
|
|
35
|
-
setIsCollapsed(value);
|
|
36
|
-
console.log('ResizeProvider: setIsCollapsed done');
|
|
37
|
-
}, [isCollapsed]);
|
|
38
|
-
|
|
39
28
|
const resizeEvent = useCallback(() => {
|
|
40
29
|
setLoading(true);
|
|
41
30
|
clearTimeout(timeOut);
|
|
@@ -49,22 +38,23 @@ export const ResizeProvider = ({ children }) => {
|
|
|
49
38
|
|
|
50
39
|
useEffect(() => {
|
|
51
40
|
window.addEventListener('resize', resizeEvent);
|
|
41
|
+
// Fix: Should remove the event listener on cleanup
|
|
52
42
|
return () => window.removeEventListener('resize', resizeEvent);
|
|
53
43
|
}, [resizeEvent]);
|
|
54
44
|
|
|
55
|
-
const value = React.useMemo(() => ({
|
|
56
|
-
resizeLoading: loading,
|
|
57
|
-
windowWidth,
|
|
58
|
-
resizeDif: dif,
|
|
59
|
-
isCollapsed,
|
|
60
|
-
setIsCollapsed: setIsCollapsedDebug, // Use the debug wrapper
|
|
61
|
-
isNestedSidebarCollapsed,
|
|
62
|
-
setIsNestedSidebarCollapsed,
|
|
63
|
-
}), [loading, windowWidth, dif, isCollapsed, isNestedSidebarCollapsed, setIsCollapsedDebug]);
|
|
64
|
-
|
|
65
45
|
return React.createElement(
|
|
66
46
|
ResizeContext.Provider,
|
|
67
|
-
{
|
|
47
|
+
{
|
|
48
|
+
value: {
|
|
49
|
+
resizeLoading: loading,
|
|
50
|
+
windowWidth,
|
|
51
|
+
resizeDif: dif,
|
|
52
|
+
isCollapsed,
|
|
53
|
+
setIsCollapsed,
|
|
54
|
+
isNestedSidebarCollapsed,
|
|
55
|
+
setIsNestedSidebarCollapsed,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
68
58
|
children
|
|
69
59
|
);
|
|
70
60
|
};
|
|
@@ -173,8 +173,44 @@ const mockCheckPermission = ({ permission, permissions }) => {
|
|
|
173
173
|
// Mock user helpers
|
|
174
174
|
const mockUserHelpers = {
|
|
175
175
|
userIsAdmin: (user) => user?.role?.id === "APP_ADMIN",
|
|
176
|
-
userIsSbgImplementor: (user) =>
|
|
177
|
-
userIsSbgPartner: (user) =>
|
|
176
|
+
userIsSbgImplementor: (user) => user?.role?.id === "SBG_IMPLEMENTOR",
|
|
177
|
+
userIsSbgPartner: (user) => user?.role?.id === "SBG_PARTNER",
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// Module Interface Configurations
|
|
181
|
+
const AdminIcon = () => (
|
|
182
|
+
<svg viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" width="14" height="14">
|
|
183
|
+
<path d="M9.03367 5H2.66667C1.74619 5 1 4.25381 1 3.33333C1 2.41286 1.74619 1.66667 2.66667 1.66667H9.03367M4.96633 12.3333H11.3333C12.2538 12.3333 13 11.5871 13 10.6667C13 9.74619 12.2538 9 11.3333 9H4.96633M1 10.6667C1 11.9553 2.04467 13 3.33333 13C4.622 13 5.66667 11.9553 5.66667 10.6667C5.66667 9.378 4.622 8.33333 3.33333 8.33333C2.04467 8.33333 1 9.378 1 10.6667ZM13 3.33333C13 4.622 11.9553 5.66667 10.6667 5.66667C9.378 5.66667 8.33333 4.622 8.33333 3.33333C8.33333 2.04467 9.378 1 10.6667 1C11.9953 1 13 2.04467 13 3.33333Z" stroke="#B9C0D4" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"></path>
|
|
184
|
+
</svg>
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const getModuleInterfaceConfig = (user, userHelpers) => {
|
|
188
|
+
if (userHelpers.userIsAdmin(user)) {
|
|
189
|
+
return {
|
|
190
|
+
title: "ADMIN",
|
|
191
|
+
icon: <AdminIcon />
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (userHelpers.userIsSbgImplementor(user)) {
|
|
196
|
+
return {
|
|
197
|
+
title: "Implementer",
|
|
198
|
+
icon: "/assets/images/SVG/implementer.svg"
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (userHelpers.userIsSbgPartner(user)) {
|
|
203
|
+
return {
|
|
204
|
+
title: "Partner",
|
|
205
|
+
icon: "/assets/images/SVG/partner-building.svg"
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Default/Coordinator
|
|
210
|
+
return {
|
|
211
|
+
title: "Coordinator",
|
|
212
|
+
icon: "/assets/images/SVG/coordinator.svg"
|
|
213
|
+
};
|
|
178
214
|
};
|
|
179
215
|
|
|
180
216
|
// Language configuration
|
|
@@ -325,6 +361,7 @@ export const Default = {
|
|
|
325
361
|
|
|
326
362
|
// Config
|
|
327
363
|
sidenavConfig={mockSidenavConfig}
|
|
364
|
+
moduleInterfaceConfig={getModuleInterfaceConfig(mockUser, mockUserHelpers)}
|
|
328
365
|
appName="sbg"
|
|
329
366
|
appLogos={appLogos}
|
|
330
367
|
languageConfig={languageConfig}
|
|
@@ -359,6 +396,7 @@ export const AdminUser = {
|
|
|
359
396
|
notificationHandlers={mockNotificationHandlers}
|
|
360
397
|
NotificationsHistoryProvider={MockNotificationsHistoryProvider}
|
|
361
398
|
sidenavConfig={mockSidenavConfig}
|
|
399
|
+
moduleInterfaceConfig={getModuleInterfaceConfig(mockAdminUser, mockUserHelpers)}
|
|
362
400
|
appName="sbg"
|
|
363
401
|
appLogos={appLogos}
|
|
364
402
|
languageConfig={languageConfig}
|
|
@@ -391,6 +429,7 @@ export const AppNavigation = {
|
|
|
391
429
|
notificationHandlers={mockNotificationHandlers}
|
|
392
430
|
NotificationsHistoryProvider={MockNotificationsHistoryProvider}
|
|
393
431
|
sidenavConfig={mockSidenavConfig}
|
|
432
|
+
moduleInterfaceConfig={getModuleInterfaceConfig(mockUser, mockUserHelpers)}
|
|
394
433
|
appName="sbg"
|
|
395
434
|
appLogos={appLogos}
|
|
396
435
|
languageConfig={languageConfig}
|
|
@@ -429,6 +468,7 @@ export const WithLoginPopup = {
|
|
|
429
468
|
notificationHandlers={mockNotificationHandlers}
|
|
430
469
|
NotificationsHistoryProvider={MockNotificationsHistoryProvider}
|
|
431
470
|
sidenavConfig={mockSidenavConfig}
|
|
471
|
+
moduleInterfaceConfig={getModuleInterfaceConfig(mockUser, mockUserHelpers)}
|
|
432
472
|
appName="sbg"
|
|
433
473
|
appLogos={appLogos}
|
|
434
474
|
languageConfig={languageConfig}
|
|
@@ -474,6 +514,7 @@ export const NoNotifications = {
|
|
|
474
514
|
notificationHandlers={mockNotificationHandlers}
|
|
475
515
|
NotificationsHistoryProvider={MockNotificationsHistoryProvider}
|
|
476
516
|
sidenavConfig={mockSidenavConfig}
|
|
517
|
+
moduleInterfaceConfig={getModuleInterfaceConfig(userWithoutNotifications, mockUserHelpers)}
|
|
477
518
|
appName="sbg"
|
|
478
519
|
appLogos={appLogos}
|
|
479
520
|
languageConfig={languageConfig}
|
|
@@ -506,6 +547,7 @@ export const WithCustomChildren = {
|
|
|
506
547
|
notificationHandlers={mockNotificationHandlers}
|
|
507
548
|
NotificationsHistoryProvider={MockNotificationsHistoryProvider}
|
|
508
549
|
sidenavConfig={mockSidenavConfig}
|
|
550
|
+
moduleInterfaceConfig={getModuleInterfaceConfig(mockUser, mockUserHelpers)}
|
|
509
551
|
appName="sbg"
|
|
510
552
|
appLogos={appLogos}
|
|
511
553
|
languageConfig={languageConfig}
|
|
@@ -529,4 +571,154 @@ export const WithCustomChildren = {
|
|
|
529
571
|
</div>
|
|
530
572
|
</AppLayout>
|
|
531
573
|
),
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
// Implementer Role
|
|
577
|
+
export const ImplementerRole = {
|
|
578
|
+
name: "Implementer Role",
|
|
579
|
+
render: () => {
|
|
580
|
+
const implementorUser = {
|
|
581
|
+
...mockUser,
|
|
582
|
+
role: {
|
|
583
|
+
id: "SBG_IMPLEMENTOR",
|
|
584
|
+
name: "Implementer",
|
|
585
|
+
permissions: {
|
|
586
|
+
"dashboard.canView": true,
|
|
587
|
+
"notifications.canView": true,
|
|
588
|
+
"users.canView": false,
|
|
589
|
+
"settings.canView": false,
|
|
590
|
+
"projects.canView": true,
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
return (
|
|
596
|
+
<AppLayout
|
|
597
|
+
user={implementorUser}
|
|
598
|
+
module="sbg"
|
|
599
|
+
logout={() => console.log("Logout clicked")}
|
|
600
|
+
exitImpersonation={() => console.log("Exit impersonation")}
|
|
601
|
+
updateLanguage={(lng) => console.log("Language changed to:", lng)}
|
|
602
|
+
getUserOptions={(lang) => console.log("Get user options for:", lang)}
|
|
603
|
+
navigate={mockNavigate}
|
|
604
|
+
location={mockLocation}
|
|
605
|
+
matchPath={mockMatchPath}
|
|
606
|
+
Outlet={MockOutlet}
|
|
607
|
+
t={mockT}
|
|
608
|
+
checkPermission={mockCheckPermission}
|
|
609
|
+
generalContext={mockGeneralContext}
|
|
610
|
+
getUserPreference={mockGetUserPreference}
|
|
611
|
+
notificationHandlers={mockNotificationHandlers}
|
|
612
|
+
NotificationsHistoryProvider={MockNotificationsHistoryProvider}
|
|
613
|
+
sidenavConfig={mockSidenavConfig}
|
|
614
|
+
moduleInterfaceConfig={getModuleInterfaceConfig(implementorUser, mockUserHelpers)}
|
|
615
|
+
appName="sbg"
|
|
616
|
+
appLogos={appLogos}
|
|
617
|
+
languageConfig={languageConfig}
|
|
618
|
+
userHelpers={mockUserHelpers}
|
|
619
|
+
isDev={true}
|
|
620
|
+
onCollapse={(collapsed) => console.log("Sidebar collapsed:", collapsed)}
|
|
621
|
+
/>
|
|
622
|
+
);
|
|
623
|
+
},
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
// Partner Role
|
|
627
|
+
export const PartnerRole = {
|
|
628
|
+
name: "Partner Role",
|
|
629
|
+
render: () => {
|
|
630
|
+
const partnerUser = {
|
|
631
|
+
...mockUser,
|
|
632
|
+
role: {
|
|
633
|
+
id: "SBG_PARTNER",
|
|
634
|
+
name: "Partner",
|
|
635
|
+
permissions: {
|
|
636
|
+
"dashboard.canView": true,
|
|
637
|
+
"notifications.canView": true,
|
|
638
|
+
"users.canView": false,
|
|
639
|
+
"settings.canView": false,
|
|
640
|
+
"projects.canView": true,
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
return (
|
|
646
|
+
<AppLayout
|
|
647
|
+
user={partnerUser}
|
|
648
|
+
module="sbg"
|
|
649
|
+
logout={() => console.log("Logout clicked")}
|
|
650
|
+
exitImpersonation={() => console.log("Exit impersonation")}
|
|
651
|
+
updateLanguage={(lng) => console.log("Language changed to:", lng)}
|
|
652
|
+
getUserOptions={(lang) => console.log("Get user options for:", lang)}
|
|
653
|
+
navigate={mockNavigate}
|
|
654
|
+
location={mockLocation}
|
|
655
|
+
matchPath={mockMatchPath}
|
|
656
|
+
Outlet={MockOutlet}
|
|
657
|
+
t={mockT}
|
|
658
|
+
checkPermission={mockCheckPermission}
|
|
659
|
+
generalContext={mockGeneralContext}
|
|
660
|
+
getUserPreference={mockGetUserPreference}
|
|
661
|
+
notificationHandlers={mockNotificationHandlers}
|
|
662
|
+
NotificationsHistoryProvider={MockNotificationsHistoryProvider}
|
|
663
|
+
sidenavConfig={mockSidenavConfig}
|
|
664
|
+
moduleInterfaceConfig={getModuleInterfaceConfig(partnerUser, mockUserHelpers)}
|
|
665
|
+
appName="sbg"
|
|
666
|
+
appLogos={appLogos}
|
|
667
|
+
languageConfig={languageConfig}
|
|
668
|
+
userHelpers={mockUserHelpers}
|
|
669
|
+
isDev={true}
|
|
670
|
+
onCollapse={(collapsed) => console.log("Sidebar collapsed:", collapsed)}
|
|
671
|
+
/>
|
|
672
|
+
);
|
|
673
|
+
},
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
// Coordinator Role (Default)
|
|
677
|
+
export const CoordinatorRole = {
|
|
678
|
+
name: "Coordinator Role",
|
|
679
|
+
render: () => {
|
|
680
|
+
const coordinatorUser = {
|
|
681
|
+
...mockUser,
|
|
682
|
+
role: {
|
|
683
|
+
id: "SBG_COORDINATOR",
|
|
684
|
+
name: "Coordinator",
|
|
685
|
+
permissions: {
|
|
686
|
+
"dashboard.canView": true,
|
|
687
|
+
"notifications.canView": true,
|
|
688
|
+
"users.canView": true,
|
|
689
|
+
"settings.canView": true,
|
|
690
|
+
"projects.canView": true,
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
|
|
695
|
+
return (
|
|
696
|
+
<AppLayout
|
|
697
|
+
user={coordinatorUser}
|
|
698
|
+
module="sbg"
|
|
699
|
+
logout={() => console.log("Logout clicked")}
|
|
700
|
+
exitImpersonation={() => console.log("Exit impersonation")}
|
|
701
|
+
updateLanguage={(lng) => console.log("Language changed to:", lng)}
|
|
702
|
+
getUserOptions={(lang) => console.log("Get user options for:", lang)}
|
|
703
|
+
navigate={mockNavigate}
|
|
704
|
+
location={mockLocation}
|
|
705
|
+
matchPath={mockMatchPath}
|
|
706
|
+
Outlet={MockOutlet}
|
|
707
|
+
t={mockT}
|
|
708
|
+
checkPermission={mockCheckPermission}
|
|
709
|
+
generalContext={mockGeneralContext}
|
|
710
|
+
getUserPreference={mockGetUserPreference}
|
|
711
|
+
notificationHandlers={mockNotificationHandlers}
|
|
712
|
+
NotificationsHistoryProvider={MockNotificationsHistoryProvider}
|
|
713
|
+
sidenavConfig={mockSidenavConfig}
|
|
714
|
+
moduleInterfaceConfig={getModuleInterfaceConfig(coordinatorUser, mockUserHelpers)}
|
|
715
|
+
appName="sbg"
|
|
716
|
+
appLogos={appLogos}
|
|
717
|
+
languageConfig={languageConfig}
|
|
718
|
+
userHelpers={mockUserHelpers}
|
|
719
|
+
isDev={true}
|
|
720
|
+
onCollapse={(collapsed) => console.log("Sidebar collapsed:", collapsed)}
|
|
721
|
+
/>
|
|
722
|
+
);
|
|
723
|
+
},
|
|
532
724
|
};
|
|
@@ -15,6 +15,7 @@ export default function MobileDrawer({
|
|
|
15
15
|
isUserDropdown = false,
|
|
16
16
|
user,
|
|
17
17
|
sidenavConfig = {},
|
|
18
|
+
moduleInterfaceConfig = null,
|
|
18
19
|
goTo = () => {},
|
|
19
20
|
getRedirectLink = () => {},
|
|
20
21
|
t = (key) => key,
|
|
@@ -165,10 +166,7 @@ export default function MobileDrawer({
|
|
|
165
166
|
<div className="flex-1">
|
|
166
167
|
{mod === 'app' || !user ? null : renderModule({
|
|
167
168
|
isCollapsed,
|
|
168
|
-
|
|
169
|
-
module: mod,
|
|
170
|
-
user,
|
|
171
|
-
userHelpers
|
|
169
|
+
moduleInterfaceConfig
|
|
172
170
|
})}
|
|
173
171
|
</div>
|
|
174
172
|
<div className="cursor-pointer close-icon" onClick={toggle}>
|
|
@@ -21,64 +21,53 @@ const PageInterface = ({ isCollapsed, onClick, title, children }) => {
|
|
|
21
21
|
);
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Renders the module interface based on configuration
|
|
26
|
+
*
|
|
27
|
+
* @param {Object} params
|
|
28
|
+
* @param {boolean} params.isCollapsed - Whether the sidebar is collapsed
|
|
29
|
+
* @param {Function} params.onClick - Click handler for the module interface
|
|
30
|
+
* @param {Object|null} params.moduleInterfaceConfig - Configuration for the module interface
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // The app determines the role and passes the appropriate config:
|
|
34
|
+
* const moduleInterfaceConfig = {
|
|
35
|
+
* title: "Implementer",
|
|
36
|
+
* icon: "/assets/images/SVG/implementer.svg" // or icon: <CustomIcon />
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
* // Or for admin:
|
|
40
|
+
* const moduleInterfaceConfig = {
|
|
41
|
+
* title: "ADMIN",
|
|
42
|
+
* icon: <svg>...</svg>
|
|
43
|
+
* }
|
|
44
|
+
*/
|
|
24
45
|
export const renderModule = ({
|
|
25
46
|
isCollapsed,
|
|
26
47
|
onClick,
|
|
27
|
-
|
|
28
|
-
userHelpers = {},
|
|
29
|
-
goTo = () => {},
|
|
48
|
+
moduleInterfaceConfig = null,
|
|
30
49
|
}) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const hasStandardInterface = userIsSbgImplementor?.(user);
|
|
35
|
-
const hasPartnerInterface = userIsSbgPartner?.(user);
|
|
36
|
-
|
|
37
|
-
if (isAdmin) {
|
|
38
|
-
return (
|
|
39
|
-
<PageInterface
|
|
40
|
-
isCollapsed={isCollapsed}
|
|
41
|
-
onClick={onClick}
|
|
42
|
-
title="ADMIN"
|
|
43
|
-
>
|
|
44
|
-
<svg viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" width="14" height="14">
|
|
45
|
-
<path d="M9.03367 5H2.66667C1.74619 5 1 4.25381 1 3.33333C1 2.41286 1.74619 1.66667 2.66667 1.66667H9.03367M4.96633 12.3333H11.3333C12.2538 12.3333 13 11.5871 13 10.6667C13 9.74619 12.2538 9 11.3333 9H4.96633M1 10.6667C1 11.9553 2.04467 13 3.33333 13C4.622 13 5.66667 11.9553 5.66667 10.6667C5.66667 9.378 4.622 8.33333 3.33333 8.33333C2.04467 8.33333 1 9.378 1 10.6667ZM13 3.33333C13 4.622 11.9553 5.66667 10.6667 5.66667C9.378 5.66667 8.33333 4.622 8.33333 3.33333C8.33333 2.04467 9.378 1 10.6667 1C11.9553 1 13 2.04467 13 3.33333Z" stroke="#B9C0D4" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round"></path>
|
|
46
|
-
</svg>
|
|
47
|
-
</PageInterface>
|
|
48
|
-
);
|
|
50
|
+
// If no config provided, don't render anything
|
|
51
|
+
if (!moduleInterfaceConfig) {
|
|
52
|
+
return null;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
>
|
|
68
|
-
<img src="/assets/images/SVG/partner-building.svg" alt="partner" />
|
|
69
|
-
</PageInterface>
|
|
70
|
-
);
|
|
71
|
-
} else if (!hasStandardInterface) {
|
|
72
|
-
return (
|
|
73
|
-
<PageInterface
|
|
74
|
-
isCollapsed={isCollapsed}
|
|
75
|
-
onClick={onClick}
|
|
76
|
-
title="Coordinator"
|
|
77
|
-
>
|
|
78
|
-
<img src="/assets/images/SVG/coordinator.svg" alt="coordinator" />
|
|
79
|
-
</PageInterface>
|
|
80
|
-
);
|
|
81
|
-
}
|
|
55
|
+
const { title, icon } = moduleInterfaceConfig;
|
|
56
|
+
|
|
57
|
+
// Convert string icon paths to img elements
|
|
58
|
+
const iconElement = typeof icon === 'string'
|
|
59
|
+
? <img src={icon} alt={title.toLowerCase()} />
|
|
60
|
+
: icon;
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<PageInterface
|
|
64
|
+
isCollapsed={isCollapsed}
|
|
65
|
+
onClick={onClick}
|
|
66
|
+
title={title}
|
|
67
|
+
>
|
|
68
|
+
{iconElement}
|
|
69
|
+
</PageInterface>
|
|
70
|
+
);
|
|
82
71
|
};
|
|
83
72
|
|
|
84
73
|
const Sidenav = ({
|
|
@@ -93,6 +82,7 @@ const Sidenav = ({
|
|
|
93
82
|
t,
|
|
94
83
|
changeNotificationState,
|
|
95
84
|
userHelpers = {},
|
|
85
|
+
moduleInterfaceConfig = null,
|
|
96
86
|
isDev = false,
|
|
97
87
|
appName = 'app',
|
|
98
88
|
getRedirectLink = () => {},
|
|
@@ -238,14 +228,11 @@ const Sidenav = ({
|
|
|
238
228
|
return (
|
|
239
229
|
<React.Fragment>
|
|
240
230
|
{renderModule({
|
|
241
|
-
module: userModule,
|
|
242
231
|
isCollapsed,
|
|
243
232
|
onClick: () => checkOnClick({
|
|
244
233
|
event: () => goTo(getRedirectLink(`/app`))
|
|
245
234
|
}),
|
|
246
|
-
|
|
247
|
-
user,
|
|
248
|
-
userHelpers
|
|
235
|
+
moduleInterfaceConfig
|
|
249
236
|
})}
|
|
250
237
|
<DAFSidenav
|
|
251
238
|
module={module}
|
|
@@ -53,6 +53,8 @@ const { Content } = Layout;
|
|
|
53
53
|
* @param {Object} props.appLogos - Logo URLs { collapsed, expanded }
|
|
54
54
|
* @param {Object} props.languageConfig - Language selector configuration
|
|
55
55
|
* @param {Function} props.renderChildren - Custom render function for children
|
|
56
|
+
* @param {Object} props.theme - Theme object with layout color customization
|
|
57
|
+
* @param {Object|null} props.moduleInterfaceConfig - Module interface config { title, icon }
|
|
56
58
|
*/
|
|
57
59
|
function AppLayout({
|
|
58
60
|
// User & Auth
|
|
@@ -101,6 +103,7 @@ function AppLayout({
|
|
|
101
103
|
|
|
102
104
|
// Config
|
|
103
105
|
sidenavConfig = {},
|
|
106
|
+
moduleInterfaceConfig = null,
|
|
104
107
|
appName = 'app',
|
|
105
108
|
appLogos = {
|
|
106
109
|
collapsed: '/assets/images/logo-small.svg',
|
|
@@ -118,6 +121,9 @@ function AppLayout({
|
|
|
118
121
|
// Custom renderers
|
|
119
122
|
renderChildren,
|
|
120
123
|
|
|
124
|
+
// Theme
|
|
125
|
+
theme = {},
|
|
126
|
+
|
|
121
127
|
// Children
|
|
122
128
|
children,
|
|
123
129
|
}) {
|
|
@@ -128,10 +134,6 @@ function AppLayout({
|
|
|
128
134
|
const [hasPrevious, setPrevious] = useState(false);
|
|
129
135
|
const { logOutPopupVisible = false } = generalContext;
|
|
130
136
|
|
|
131
|
-
useEffect(() => {
|
|
132
|
-
console.log('isCollapsed changed to:', isCollapsed);
|
|
133
|
-
}, [isCollapsed]);
|
|
134
|
-
|
|
135
137
|
const canViewNotifications = checkPermission({
|
|
136
138
|
permission: 'notifications.canView',
|
|
137
139
|
permissions: user?.role?.permissions
|
|
@@ -153,15 +155,8 @@ function AppLayout({
|
|
|
153
155
|
}, [getUserPreference]);
|
|
154
156
|
|
|
155
157
|
const setIsCollapse = (val = false) => {
|
|
156
|
-
console.log('setIsCollapse called with:', val);
|
|
157
|
-
console.log('setIsCollapsed function:', setIsCollapsed);
|
|
158
|
-
console.log('typeof setIsCollapsed:', typeof setIsCollapsed);
|
|
159
|
-
|
|
160
158
|
localStorage.setItem('is_collapsed', val ? 'true' : 'false');
|
|
161
|
-
|
|
162
|
-
console.log('Calling setIsCollapsed with:', val);
|
|
163
159
|
setIsCollapsed(val);
|
|
164
|
-
console.log('setIsCollapsed called');
|
|
165
160
|
|
|
166
161
|
if (onCollapse && typeof onCollapse === 'function') {
|
|
167
162
|
onCollapse(val);
|
|
@@ -223,15 +218,24 @@ function AppLayout({
|
|
|
223
218
|
changeNotificationState({ onYes: () => goTo(getRedirectLink('/app')) });
|
|
224
219
|
};
|
|
225
220
|
|
|
221
|
+
// Apply theme CSS custom properties
|
|
222
|
+
const layoutStyle = useMemo(() => ({
|
|
223
|
+
display: 'flex',
|
|
224
|
+
flexDirection: 'row',
|
|
225
|
+
width: '100vw',
|
|
226
|
+
height: '100dvh',
|
|
227
|
+
maxHeight: '100dvh',
|
|
228
|
+
'--layout-primary-bg': theme.layoutPrimaryBg,
|
|
229
|
+
'--layout-secondary-bg': theme.layoutSecondaryBg,
|
|
230
|
+
'--layout-border-color': theme.layoutBorderColor,
|
|
231
|
+
'--layout-text-primary': theme.layoutTextPrimary,
|
|
232
|
+
'--layout-text-secondary': theme.layoutTextSecondary,
|
|
233
|
+
'--layout-hover-bg': theme.layoutHoverBg,
|
|
234
|
+
}), [theme]);
|
|
235
|
+
|
|
226
236
|
return (
|
|
227
237
|
<div
|
|
228
|
-
style={
|
|
229
|
-
display: 'flex',
|
|
230
|
-
flexDirection: 'row',
|
|
231
|
-
width: '100vw',
|
|
232
|
-
height: '100dvh',
|
|
233
|
-
maxHeight: '100dvh'
|
|
234
|
-
}}
|
|
238
|
+
style={layoutStyle}
|
|
235
239
|
className="components-layout"
|
|
236
240
|
>
|
|
237
241
|
{!isAppNavigation ? (
|
|
@@ -259,6 +263,7 @@ function AppLayout({
|
|
|
259
263
|
isCollapsed={isCollapsed}
|
|
260
264
|
user={user}
|
|
261
265
|
sidenavConfig={sidenavConfig}
|
|
266
|
+
moduleInterfaceConfig={moduleInterfaceConfig}
|
|
262
267
|
goTo={goTo}
|
|
263
268
|
location={location}
|
|
264
269
|
matchPath={matchPath}
|
|
@@ -292,9 +297,7 @@ function AppLayout({
|
|
|
292
297
|
{
|
|
293
298
|
className: 'trigger',
|
|
294
299
|
onClick: () => {
|
|
295
|
-
console.log('Trigger clicked! Current isCollapsed:', isCollapsed);
|
|
296
300
|
const newValue = !isCollapsed;
|
|
297
|
-
console.log('Setting to:', newValue);
|
|
298
301
|
setIsCollapse(newValue);
|
|
299
302
|
},
|
|
300
303
|
}
|
|
@@ -415,6 +418,7 @@ function AppLayout({
|
|
|
415
418
|
drawerOpened={drawerOpened}
|
|
416
419
|
user={user}
|
|
417
420
|
sidenavConfig={sidenavConfig}
|
|
421
|
+
moduleInterfaceConfig={moduleInterfaceConfig}
|
|
418
422
|
navigate={goTo}
|
|
419
423
|
t={t}
|
|
420
424
|
checkPermission={checkPermission}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
$
|
|
4
|
-
$
|
|
5
|
-
$
|
|
6
|
-
$text-
|
|
7
|
-
$
|
|
1
|
+
// CSS Custom Properties (can be overridden dynamically)
|
|
2
|
+
// These will be set via inline styles in AppLayout component
|
|
3
|
+
$primary-bg: var(--layout-primary-bg, #1a1d29);
|
|
4
|
+
$secondary-bg: var(--layout-secondary-bg, #262b3d);
|
|
5
|
+
$border-color: var(--layout-border-color, rgba(255, 255, 255, 0.1));
|
|
6
|
+
$text-primary: var(--layout-text-primary, #ffffff);
|
|
7
|
+
$text-secondary: var(--layout-text-secondary, #8c8c8c);
|
|
8
|
+
$hover-bg: var(--layout-hover-bg, rgba(255, 255, 255, 0.1));
|
|
8
9
|
|
|
9
10
|
// Spacing
|
|
10
11
|
$header-height: 64px;
|