@antscorp/antsomi-ui 1.3.5-beta.209 → 1.3.5-beta.210
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/es/components/organism/LeftMenu/components/HomeMenu/constants.js +2 -2
- package/es/components/organism/LeftMenu/components/HomeMenu/useHomeMenu.js +2 -2
- package/es/components/organism/LeftMenu/components/common/ChildMenu/index.js +8 -8
- package/es/components/organism/LeftMenu/components/common/ChildMenu/styled.js +5 -0
- package/es/components/organism/LeftMenu/components/common/ChildMenu/utils.d.ts +12 -0
- package/es/components/organism/LeftMenu/components/common/ChildMenu/utils.js +13 -4
- package/es/components/organism/LeftMenu/hooks/useLeftMenu.d.ts +0 -1
- package/es/components/organism/LeftMenu/hooks/useLeftMenu.js +26 -6
- package/es/components/organism/LeftMenu/hooks/useNavigatePath.d.ts +5 -0
- package/es/components/organism/LeftMenu/hooks/useNavigatePath.js +43 -0
- package/es/components/organism/LeftMenu/index.d.ts +2 -0
- package/es/components/organism/LeftMenu/index.js +4 -6
- package/es/components/organism/LeftMenu/styled.js +1 -1
- package/es/components/organism/LeftMenu/utils/index.d.ts +6 -1
- package/es/components/organism/LeftMenu/utils/index.js +39 -12
- package/es/components/template/Layout/Layout.d.ts +3 -1
- package/es/components/template/Layout/Layout.js +22 -7
- package/es/components/template/Layout/constants/index.d.ts +2 -0
- package/es/components/template/Layout/constants/index.js +2 -0
- package/es/components/template/Layout/constants/menuCode.d.ts +29 -0
- package/es/components/template/Layout/constants/menuCode.js +30 -0
- package/es/components/template/Layout/constants/permission.d.ts +6 -0
- package/es/components/template/Layout/constants/permission.js +6 -0
- package/es/components/template/Layout/stores/index.d.ts +5 -0
- package/es/components/template/Layout/stores/index.js +4 -0
- package/es/components/template/Layout/utils/index.d.ts +1 -0
- package/es/components/template/Layout/utils/index.js +1 -0
- package/es/components/template/Layout/utils/permission.d.ts +16 -0
- package/es/components/template/Layout/utils/permission.js +48 -0
- package/package.json +1 -1
- package/es/services/LeftMenu/utils.d.ts +0 -9
- package/es/services/LeftMenu/utils.js +0 -135
|
@@ -33,7 +33,7 @@ export const useHomeMenu = () => {
|
|
|
33
33
|
const { optionKey, menuItemKey } = args;
|
|
34
34
|
switch (optionKey) {
|
|
35
35
|
case CONFIG_OPTIONS.CONFIGURE.key: {
|
|
36
|
-
const newPathName = getGeneratePath(getHomePath(HOME_REPORT_ROUTES.CONFIGURE), Object.assign(Object.assign({}, auth), {
|
|
36
|
+
const newPathName = getGeneratePath(getHomePath(HOME_REPORT_ROUTES.CONFIGURE), Object.assign(Object.assign({}, auth), { dashboardId: menuItemKey }));
|
|
37
37
|
if (newPathName !== pathname) {
|
|
38
38
|
history.push(newPathName);
|
|
39
39
|
}
|
|
@@ -54,7 +54,7 @@ export const useHomeMenu = () => {
|
|
|
54
54
|
history.push(getGeneratePath(getHomePath(HOME_REPORT_ROUTES.CREATE), auth));
|
|
55
55
|
}, [auth, history, getHomePath]);
|
|
56
56
|
const onMenuClick = useCallback((key, _) => {
|
|
57
|
-
const newPathName = getGeneratePath(getHomePath(HOME_REPORT_ROUTES.DETAIL), Object.assign(Object.assign({}, auth), {
|
|
57
|
+
const newPathName = getGeneratePath(getHomePath(HOME_REPORT_ROUTES.DETAIL), Object.assign(Object.assign({}, auth), { dashboardId: key }));
|
|
58
58
|
if (newPathName !== pathname) {
|
|
59
59
|
history.push(newPathName);
|
|
60
60
|
}
|
|
@@ -12,19 +12,19 @@ import { MenuItemImage } from './components';
|
|
|
12
12
|
import { LabelCustom, MenuWrapper } from './styled';
|
|
13
13
|
// Constants
|
|
14
14
|
import { ICON_SIZE } from '../../../constants';
|
|
15
|
-
import { ENV } from '@antscorp/antsomi-ui/es/config';
|
|
16
15
|
// Contexts
|
|
17
16
|
import { AppConfigContext } from '@antscorp/antsomi-ui/es/providers';
|
|
18
17
|
// Utils
|
|
19
|
-
import { findActiveAppCodeByUrl,
|
|
20
|
-
import {
|
|
18
|
+
import { findActiveAppCodeByUrl, findLastMatchedCodeByUrl } from '../../../utils';
|
|
19
|
+
import { recursiveFindParentOfActiveItem } from './utils';
|
|
21
20
|
import { random } from '@antscorp/antsomi-ui/es/utils';
|
|
21
|
+
// Hooks
|
|
22
22
|
import { useLeftMenuStore } from '../../../stores';
|
|
23
|
+
import { useNavigatePath } from '../../../hooks/useNavigatePath';
|
|
23
24
|
export const ChildMenu = memo(props => {
|
|
24
25
|
const { items = [], parentKey, onMenuClick } = props;
|
|
25
26
|
// Contexts
|
|
26
27
|
const auth = useContextSelector(AppConfigContext, state => state === null || state === void 0 ? void 0 : state.auth);
|
|
27
|
-
const env = useContextSelector(AppConfigContext, state => state === null || state === void 0 ? void 0 : state.env);
|
|
28
28
|
// Stores
|
|
29
29
|
const activeAppCode = useLeftMenuStore(store => store.state.activeAppCode);
|
|
30
30
|
const menuItems = useLeftMenuStore(store => store.state.menuItems);
|
|
@@ -36,11 +36,12 @@ export const ChildMenu = memo(props => {
|
|
|
36
36
|
const randomMenuWrapperId = random(10);
|
|
37
37
|
// Hooks
|
|
38
38
|
const { pathname, hash, search } = useLocation();
|
|
39
|
+
const { isPushDifferentDomain, getPath, navigatePath } = useNavigatePath();
|
|
39
40
|
// Side Effects
|
|
40
41
|
useEffect(() => {
|
|
41
42
|
const url = `${pathname}${hash}${search}`;
|
|
42
43
|
/** Active menu item by current url */
|
|
43
|
-
const activeMenuItem =
|
|
44
|
+
const activeMenuItem = findLastMatchedCodeByUrl({ url, menuItems, auth });
|
|
44
45
|
if (activeMenuItem && activeMenuItem !== currentActiveItem) {
|
|
45
46
|
setCurrentActiveItem(activeMenuItem);
|
|
46
47
|
/** Find parent key of active menu item to open it */
|
|
@@ -75,8 +76,7 @@ export const ChildMenu = memo(props => {
|
|
|
75
76
|
var _a;
|
|
76
77
|
return (_a = args === null || args === void 0 ? void 0 : args.items) === null || _a === void 0 ? void 0 : _a.map(item => {
|
|
77
78
|
var _a;
|
|
78
|
-
const { key, label, children, icon, logo_url, menu_item_path, menu_item_domain, options, optionCallback, } = item;
|
|
79
|
-
const domain = !isNil(menu_item_domain) && env === ENV.DEV ? menu_item_domain : '';
|
|
79
|
+
const { key, label, children, icon, logo_url, menu_item_path = null, menu_item_domain = null, options, optionCallback, } = item;
|
|
80
80
|
const labelComponent = () => (!children || isEmpty(children)) && !isEmpty(options) ? (React.createElement(Flex, { gap: 10, align: "center", justify: "space-between", style: { width: '100%' }, className: "child-menu-label" },
|
|
81
81
|
React.createElement(LabelCustom, { ellipsis: { tooltip: label } }, label),
|
|
82
82
|
React.createElement(Dropdown, { menu: {
|
|
@@ -90,7 +90,7 @@ export const ChildMenu = memo(props => {
|
|
|
90
90
|
React.createElement(Icon, { className: "child-menu-item-icon", type: "icon-ants-three-dot-vertical", style: { marginTop: '2px', zIndex: 1000 } })))) : (React.createElement(LabelCustom, { ellipsis: { tooltip: label } }, label));
|
|
91
91
|
return {
|
|
92
92
|
key,
|
|
93
|
-
label: isString(menu_item_path) ? (React.createElement(
|
|
93
|
+
label: isString(menu_item_path) ? (isPushDifferentDomain(menu_item_domain, menu_item_path) ? (React.createElement("div", { onClick: () => navigatePath(menu_item_domain, menu_item_path), className: "menu-link" }, labelComponent())) : (React.createElement(Link, { to: getPath(menu_item_domain, menu_item_path), className: "menu-link" }, labelComponent()))) : (labelComponent()),
|
|
94
94
|
icon: !isNil(icon) ? (React.createElement(Icon, { type: icon, style: { fontSize: ICON_SIZE } })) : !isNil(logo_url) ? (React.createElement(MenuItemImage, { imageUrl: logo_url, fallbackIcon: (_a = args === null || args === void 0 ? void 0 : args.parent) === null || _a === void 0 ? void 0 : _a.icon })) : null,
|
|
95
95
|
children: customMenuItems({ parent: item, items: children }),
|
|
96
96
|
};
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { TFeatureMenu } from '@antscorp/antsomi-ui/es/models/LeftMenu';
|
|
2
2
|
import { PayloadInfo } from '@antscorp/antsomi-ui/es/types';
|
|
3
|
+
/**
|
|
4
|
+
* Finds the active menu item code based on the provided URL within the given menu items.
|
|
5
|
+
* ATTENTION: Start finding from level 2 because level 1 contains apps
|
|
6
|
+
*
|
|
7
|
+
* @param {Object} args - The arguments object.
|
|
8
|
+
* @param {string} args.url - The URL to match against menu item paths.
|
|
9
|
+
* @param {TFeatureMenu[]} args.menuItems - The array of menu items to search within.
|
|
10
|
+
* @param {Partial<PayloadInfo>} [args.auth] - Additional authentication information (optional).
|
|
11
|
+
* @returns {string | undefined} The menu item code of the active menu item or undefined if not found.
|
|
12
|
+
*
|
|
13
|
+
* @throws Will throw an error if any issue occurs during the process.
|
|
14
|
+
*/
|
|
3
15
|
export declare const findActiveMenuItemByUrl: (args: {
|
|
4
16
|
url: string;
|
|
5
17
|
menuItems: TFeatureMenu[];
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
// Libraries
|
|
2
|
-
import { isNil } from 'lodash';
|
|
3
1
|
// Utils
|
|
4
2
|
import { getGeneratePath } from '../../../utils';
|
|
5
3
|
import { handleError } from '@antscorp/antsomi-ui/es/utils';
|
|
6
4
|
const PATH = 'src/components/organism/LeftMenu/components/common/ChildMenu/utils.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Finds the active menu item code based on the provided URL within the given menu items.
|
|
7
|
+
* ATTENTION: Start finding from level 2 because level 1 contains apps
|
|
8
|
+
*
|
|
9
|
+
* @param {Object} args - The arguments object.
|
|
10
|
+
* @param {string} args.url - The URL to match against menu item paths.
|
|
11
|
+
* @param {TFeatureMenu[]} args.menuItems - The array of menu items to search within.
|
|
12
|
+
* @param {Partial<PayloadInfo>} [args.auth] - Additional authentication information (optional).
|
|
13
|
+
* @returns {string | undefined} The menu item code of the active menu item or undefined if not found.
|
|
14
|
+
*
|
|
15
|
+
* @throws Will throw an error if any issue occurs during the process.
|
|
16
|
+
*/
|
|
7
17
|
export const findActiveMenuItemByUrl = (args) => {
|
|
8
18
|
try {
|
|
9
19
|
const { url, menuItems, auth } = args;
|
|
@@ -12,8 +22,7 @@ export const findActiveMenuItemByUrl = (args) => {
|
|
|
12
22
|
const recursiveFindActiveItem = (items) => {
|
|
13
23
|
let activeItem;
|
|
14
24
|
for (const item of items) {
|
|
15
|
-
if (
|
|
16
|
-
url.includes(getGeneratePath(item.menu_item_path, auth))) {
|
|
25
|
+
if (!!(item === null || item === void 0 ? void 0 : item.menu_item_path) && url.includes(getGeneratePath(item.menu_item_path, auth))) {
|
|
17
26
|
activeItem = item === null || item === void 0 ? void 0 : item.menu_item_code;
|
|
18
27
|
break;
|
|
19
28
|
}
|
|
@@ -7,7 +7,6 @@ export declare const useLeftMenu: (props: LeftMenuProps) => {
|
|
|
7
7
|
state: TState;
|
|
8
8
|
activeAppCode: string;
|
|
9
9
|
permissionMenu: import("@antscorp/antsomi-ui/es/models/LeftMenu").TFeatureMenu[];
|
|
10
|
-
appConfig: import("@antscorp/antsomi-ui/es/providers").AppConfigProviderProps;
|
|
11
10
|
onToggleChildMenu: () => void;
|
|
12
11
|
onMouseEnter: (key: string) => void;
|
|
13
12
|
onMouseLeave: () => void;
|
|
@@ -8,7 +8,7 @@ import { AppConfigContext } from '@antscorp/antsomi-ui/es/providers';
|
|
|
8
8
|
// Queries
|
|
9
9
|
import { useGetDashboard, useGetDestinationChannel, useGetListMenu, useGetListMenuPermission, } from '@antscorp/antsomi-ui/es/queries/LeftMenu';
|
|
10
10
|
// Utils
|
|
11
|
-
import { findActiveAppCodeByUrl, flattenMenuArray, getMappingAppChildren, recursivePermissionMenu, } from '../utils';
|
|
11
|
+
import { findActiveAppCodeByUrl, findLastMatchedCodeByUrl, flattenMenuArray, getMappingAppChildren, recursivePermissionMenu, } from '../utils';
|
|
12
12
|
// Store
|
|
13
13
|
import { useLeftMenuStore } from '../stores';
|
|
14
14
|
const initialState = {
|
|
@@ -17,7 +17,7 @@ const initialState = {
|
|
|
17
17
|
};
|
|
18
18
|
export const useLeftMenu = (props) => {
|
|
19
19
|
// Props
|
|
20
|
-
const { objectType = 'OVERVIEW', objectId = 1, isGrouped = true } = props;
|
|
20
|
+
const { objectType = 'OVERVIEW', objectId = 1, isGrouped = true, onActiveMenuCodeChange } = props;
|
|
21
21
|
// Hooks
|
|
22
22
|
const { pathname, hash, search } = useLocation();
|
|
23
23
|
// Contexts
|
|
@@ -93,9 +93,7 @@ export const useLeftMenu = (props) => {
|
|
|
93
93
|
// Variables
|
|
94
94
|
const flattenMenuPermission = flattenMenuArray(menuListPermission || [], 'childs');
|
|
95
95
|
// Memos
|
|
96
|
-
const permissionMenu = useMemo(() => sortBy(
|
|
97
|
-
'level_position',
|
|
98
|
-
]), [menuList === null || menuList === void 0 ? void 0 : menuList.rows, flattenMenuPermission]);
|
|
96
|
+
const permissionMenu = useMemo(() => recursivePermissionMenu(sortBy((menuList === null || menuList === void 0 ? void 0 : menuList.rows) || [], ['level_position']), flattenMenuPermission), [menuList === null || menuList === void 0 ? void 0 : menuList.rows, flattenMenuPermission]);
|
|
99
97
|
const mappingChildrenMenu = useMemo(() => getMappingAppChildren({
|
|
100
98
|
menuList: permissionMenu,
|
|
101
99
|
auth,
|
|
@@ -103,6 +101,9 @@ export const useLeftMenu = (props) => {
|
|
|
103
101
|
destinationChannelEntries: destinationChannel === null || destinationChannel === void 0 ? void 0 : destinationChannel.entries,
|
|
104
102
|
}), [auth, dashboardData, destinationChannel === null || destinationChannel === void 0 ? void 0 : destinationChannel.entries, permissionMenu]);
|
|
105
103
|
// Side Effects
|
|
104
|
+
/**
|
|
105
|
+
* Change list menu children when hovering or activating items, giving priority to hovering items
|
|
106
|
+
*/
|
|
106
107
|
useEffect(() => {
|
|
107
108
|
var _a;
|
|
108
109
|
const appCode = state.hoverItem ? state.hoverItem : activeAppCode;
|
|
@@ -133,6 +134,26 @@ export const useLeftMenu = (props) => {
|
|
|
133
134
|
search,
|
|
134
135
|
setLeftMenuState,
|
|
135
136
|
]);
|
|
137
|
+
/**
|
|
138
|
+
* Callback function when url change
|
|
139
|
+
*/
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
const url = `${pathname}${hash}${search}`;
|
|
142
|
+
const matchedCode = findLastMatchedCodeByUrl({
|
|
143
|
+
url,
|
|
144
|
+
menuItems: mappingChildrenMenu,
|
|
145
|
+
auth,
|
|
146
|
+
});
|
|
147
|
+
onActiveMenuCodeChange === null || onActiveMenuCodeChange === void 0 ? void 0 : onActiveMenuCodeChange(matchedCode, flattenMenuPermission);
|
|
148
|
+
}, [
|
|
149
|
+
auth,
|
|
150
|
+
flattenMenuPermission,
|
|
151
|
+
hash,
|
|
152
|
+
mappingChildrenMenu,
|
|
153
|
+
onActiveMenuCodeChange,
|
|
154
|
+
pathname,
|
|
155
|
+
search,
|
|
156
|
+
]);
|
|
136
157
|
/* Callbacks */
|
|
137
158
|
const onToggleChildMenu = useCallback(() => {
|
|
138
159
|
setState(prev => (Object.assign(Object.assign({}, prev), { isExpandMenu: !prev.isExpandMenu })));
|
|
@@ -154,7 +175,6 @@ export const useLeftMenu = (props) => {
|
|
|
154
175
|
activeAppCode,
|
|
155
176
|
/* Data Queries */
|
|
156
177
|
permissionMenu,
|
|
157
|
-
appConfig,
|
|
158
178
|
/* Callbacks */
|
|
159
179
|
onToggleChildMenu,
|
|
160
180
|
onMouseEnter,
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Libraries
|
|
2
|
+
import { useContextSelector } from 'use-context-selector';
|
|
3
|
+
import { useCallback } from 'react';
|
|
4
|
+
import { isNil } from 'lodash';
|
|
5
|
+
// Contexts
|
|
6
|
+
import { AppConfigContext } from '@antscorp/antsomi-ui/es/providers';
|
|
7
|
+
// Utils
|
|
8
|
+
import { getGeneratePath } from '../utils';
|
|
9
|
+
// Constants
|
|
10
|
+
import { ENV } from '@antscorp/antsomi-ui/es/config';
|
|
11
|
+
export const useNavigatePath = () => {
|
|
12
|
+
// Contexts
|
|
13
|
+
const { auth, env } = useContextSelector(AppConfigContext, state => state);
|
|
14
|
+
// Callbacks
|
|
15
|
+
const isPushDifferentDomain = useCallback((domain, path) => {
|
|
16
|
+
var _a, _b, _c, _d, _e, _f;
|
|
17
|
+
if (env === ENV.DEV)
|
|
18
|
+
return false;
|
|
19
|
+
const customDomain = domain !== null && domain !== void 0 ? domain : '';
|
|
20
|
+
const splitNextPath = (path === null || path === void 0 ? void 0 : path.split('#')) || ['', ''];
|
|
21
|
+
const isCurrentPathIncludeHash = (_b = (_a = window.location) === null || _a === void 0 ? void 0 : _a.href) === null || _b === void 0 ? void 0 : _b.includes('#');
|
|
22
|
+
const isNextPathIncludeHash = path === null || path === void 0 ? void 0 : path.includes('#');
|
|
23
|
+
if (isCurrentPathIncludeHash && isNextPathIncludeHash) {
|
|
24
|
+
const currentRoute = ((_e = (_d = (_c = window.location.href) === null || _c === void 0 ? void 0 : _c.split) === null || _d === void 0 ? void 0 : _d['#']) === null || _e === void 0 ? void 0 : _e[0]) || '';
|
|
25
|
+
const nextRoute = `${customDomain}${splitNextPath[0]}`;
|
|
26
|
+
return currentRoute !== nextRoute;
|
|
27
|
+
}
|
|
28
|
+
return !!customDomain && customDomain !== ((_f = window.location) === null || _f === void 0 ? void 0 : _f.origin);
|
|
29
|
+
}, [env]);
|
|
30
|
+
const getPath = useCallback((domain, path) => {
|
|
31
|
+
var _a;
|
|
32
|
+
if ((path === null || path === void 0 ? void 0 : path.includes('#')) && isPushDifferentDomain(domain, path)) {
|
|
33
|
+
const customPath = ((_a = path === null || path === void 0 ? void 0 : path.split('#')) === null || _a === void 0 ? void 0 : _a[1]) || '';
|
|
34
|
+
return getGeneratePath(customPath, auth);
|
|
35
|
+
}
|
|
36
|
+
return getGeneratePath(`${path !== null && path !== void 0 ? path : ''}`, auth);
|
|
37
|
+
}, [auth, isPushDifferentDomain]);
|
|
38
|
+
const navigatePath = useCallback((domain, path) => {
|
|
39
|
+
const newDomain = isNil(domain) || env === ENV.DEV ? '' : domain;
|
|
40
|
+
window.location.assign(getGeneratePath(`${newDomain}${path}`, auth));
|
|
41
|
+
}, [auth, env]);
|
|
42
|
+
return { isPushDifferentDomain, getPath, navigatePath };
|
|
43
|
+
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { FeatureMenuPermission } from '@antscorp/antsomi-ui/es/models/LeftMenu';
|
|
2
3
|
export interface LeftMenuProps {
|
|
3
4
|
objectType?: string;
|
|
4
5
|
objectId?: number;
|
|
5
6
|
isGrouped?: boolean;
|
|
6
7
|
style?: React.CSSProperties;
|
|
7
8
|
className?: string;
|
|
9
|
+
onActiveMenuCodeChange?: (activeMenuCode?: string, flattenPermissionList?: FeatureMenuPermission[]) => void;
|
|
8
10
|
}
|
|
9
11
|
export declare const LeftMenu: React.FC<LeftMenuProps>;
|
|
@@ -10,14 +10,12 @@ import SubLogoAntsomi from '@antscorp/antsomi-ui/es/assets/images/logo/sub-logo-
|
|
|
10
10
|
// Styled
|
|
11
11
|
import { ChildMenuWrapper, ExpandWrapper, FeatureMenu, FeatureMenuItem, LeftMenuNav, LeftMenuNavWrapper, PopoverWrapper, NavLogoWrapper, FeatureMenuWrapper, } from './styled';
|
|
12
12
|
// Constants
|
|
13
|
-
import { ENV } from '@antscorp/antsomi-ui/es/config';
|
|
14
13
|
import { APP_KEYS, ICON_SIZE } from './constants';
|
|
15
14
|
// Components
|
|
16
15
|
import { ProfilesMenu, ContentMenu, DataMenu, MarketingMenu, HomeMenu, InsightsMenu, SettingsMenu, TemplatesMenu, } from './components';
|
|
17
16
|
// Hooks
|
|
18
17
|
import { useLeftMenu } from './hooks';
|
|
19
|
-
|
|
20
|
-
import { getGeneratePath } from './utils';
|
|
18
|
+
import { useNavigatePath } from './hooks/useNavigatePath';
|
|
21
19
|
export const LeftMenu = memo(props => {
|
|
22
20
|
var _a;
|
|
23
21
|
const { style, className } = props;
|
|
@@ -28,9 +26,10 @@ export const LeftMenu = memo(props => {
|
|
|
28
26
|
/* Store */
|
|
29
27
|
activeAppCode,
|
|
30
28
|
/* Data Queries */
|
|
31
|
-
permissionMenu,
|
|
29
|
+
permissionMenu,
|
|
32
30
|
/* Callbacks */
|
|
33
31
|
onToggleChildMenu, onMouseEnter, onMouseLeave, } = useLeftMenu(props);
|
|
32
|
+
const { isPushDifferentDomain, getPath, navigatePath } = useNavigatePath();
|
|
34
33
|
// Memo
|
|
35
34
|
const childMenu = useMemo(() => {
|
|
36
35
|
const selectedFeatureKey = state.hoverItem ? state.hoverItem : activeAppCode;
|
|
@@ -66,14 +65,13 @@ export const LeftMenu = memo(props => {
|
|
|
66
65
|
// Render components
|
|
67
66
|
const renderFeatureMenuItems = (item) => {
|
|
68
67
|
const { menu_item_name, menu_item, icon_name, menu_item_code, menu_item_path, menu_item_domain, } = item;
|
|
69
|
-
const domain = !isNil(menu_item_domain) && (appConfig === null || appConfig === void 0 ? void 0 : appConfig.env) === ENV.DEV ? menu_item_domain : '';
|
|
70
68
|
const isActive = activeAppCode === menu_item_code;
|
|
71
69
|
const isHover = state.hoverItem === menu_item_code;
|
|
72
70
|
const labelComponent = () => (React.createElement("li", { role: "menuitem", className: classNames({ isActive, isHover }) },
|
|
73
71
|
React.createElement("div", { className: "icon-wrapper" }, isNil(icon_name) ? null : React.createElement(Icon, { type: icon_name, style: { fontSize: ICON_SIZE } })),
|
|
74
72
|
React.createElement(Typography.Text, null, menu_item_name),
|
|
75
73
|
React.createElement("div", { className: "popup-triangle" })));
|
|
76
|
-
return (React.createElement(FeatureMenuItem, { key: menu_item, onMouseEnter: () => onMouseEnter(menu_item_code) }, isString(menu_item_path) ? (React.createElement(
|
|
74
|
+
return (React.createElement(FeatureMenuItem, { key: menu_item, onMouseEnter: () => onMouseEnter(menu_item_code) }, isString(menu_item_path) ? (isPushDifferentDomain(menu_item_domain, menu_item_path) ? (React.createElement("div", { onClick: () => navigatePath(menu_item_domain, menu_item_path) }, labelComponent())) : (React.createElement(Link, { to: getPath(menu_item_domain, menu_item_path), className: "menu-link" }, labelComponent()))) : (labelComponent())));
|
|
77
75
|
};
|
|
78
76
|
return (React.createElement(LeftMenuNavWrapper, { style: style, className: className },
|
|
79
77
|
React.createElement(LeftMenuNav, null,
|
|
@@ -11,7 +11,7 @@ export const PopoverWrapper = styled.div `
|
|
|
11
11
|
visibility: hidden;
|
|
12
12
|
position: absolute;
|
|
13
13
|
background-color: white;
|
|
14
|
-
left:
|
|
14
|
+
left: 69px;
|
|
15
15
|
border-radius: ${(_a = THEME === null || THEME === void 0 ? void 0 : THEME.token) === null || _a === void 0 ? void 0 : _a.borderRadiusXL}px;
|
|
16
16
|
bottom: 15px;
|
|
17
17
|
width: 230px;
|
|
@@ -25,7 +25,7 @@ export declare const recursivePermissionMenu: (menuItems: TFeatureMenu[], MenuPe
|
|
|
25
25
|
* @returns {string} The generated path with replaced parameters.
|
|
26
26
|
*/
|
|
27
27
|
export declare const getGeneratePath: (path: string, params?: Partial<PayloadInfo> & {
|
|
28
|
-
|
|
28
|
+
dashboardId?: string;
|
|
29
29
|
channelId?: number;
|
|
30
30
|
}) => string;
|
|
31
31
|
/**
|
|
@@ -54,3 +54,8 @@ export declare const findActiveAppCodeByUrl: (args: {
|
|
|
54
54
|
menuItems: TFeatureMenu[];
|
|
55
55
|
auth?: Partial<PayloadInfo>;
|
|
56
56
|
}) => string | undefined;
|
|
57
|
+
export declare const findLastMatchedCodeByUrl: (args: {
|
|
58
|
+
url: string;
|
|
59
|
+
menuItems: TFeatureMenu[];
|
|
60
|
+
auth?: Partial<PayloadInfo>;
|
|
61
|
+
}) => string | undefined;
|
|
@@ -10,7 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
// Libraries
|
|
13
|
-
import { isArray, isEmpty,
|
|
13
|
+
import { isArray, isEmpty, sortBy } from 'lodash';
|
|
14
14
|
import { generatePath } from 'react-router-dom';
|
|
15
15
|
// Constants
|
|
16
16
|
import { APP_KEYS, MARKETING_CHANNEL_KEY, HOME_MENU_ITEMS, MARKETING_ROUTES, MENU_ITEM_TYPE, MARKETING_CHANNEL_CODE, RENDER_OPTION, } from '../constants';
|
|
@@ -54,9 +54,11 @@ export const recursivePermissionMenu = (menuItems, MenuPermissions) => {
|
|
|
54
54
|
if (menu_item_type !== MENU_ITEM_TYPE.MENU) {
|
|
55
55
|
return true;
|
|
56
56
|
}
|
|
57
|
-
return MenuPermissions === null || MenuPermissions === void 0 ? void 0 : MenuPermissions.find(({ app_code = '', menu_code = '' }) =>
|
|
57
|
+
return MenuPermissions === null || MenuPermissions === void 0 ? void 0 : MenuPermissions.find(({ app_code = '', menu_code = '' }) => !!permission_code && [app_code, menu_code].includes(permission_code));
|
|
58
58
|
})) === null || _a === void 0 ? void 0 : _a.map(item => (Object.assign(Object.assign({}, item), (isArray(item.children)
|
|
59
|
-
? {
|
|
59
|
+
? {
|
|
60
|
+
children: recursivePermissionMenu(sortBy(item.children || [], ['level_position']), MenuPermissions),
|
|
61
|
+
}
|
|
60
62
|
: {}))))) === null || _b === void 0 ? void 0 : _b.filter(item => !(isArray(item.children) && isEmpty(item.children)));
|
|
61
63
|
return menu;
|
|
62
64
|
};
|
|
@@ -66,12 +68,13 @@ export const recursivePermissionMenu = (menuItems, MenuPermissions) => {
|
|
|
66
68
|
*/
|
|
67
69
|
export const getGeneratePath = (path, params) => {
|
|
68
70
|
try {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const { portalId, userId, dashboardId, channelId } = params || {};
|
|
72
|
+
return generatePath(path, {
|
|
73
|
+
user_id: userId !== null && userId !== void 0 ? userId : '-1',
|
|
74
|
+
networkId: portalId !== null && portalId !== void 0 ? portalId : -1,
|
|
75
|
+
portalId: portalId !== null && portalId !== void 0 ? portalId : -1,
|
|
76
|
+
dashboardId: dashboardId !== null && dashboardId !== void 0 ? dashboardId : '-1',
|
|
77
|
+
channelId: channelId !== null && channelId !== void 0 ? channelId : -1,
|
|
75
78
|
});
|
|
76
79
|
}
|
|
77
80
|
catch (error) {
|
|
@@ -162,8 +165,7 @@ export const findActiveAppCodeByUrl = (args) => {
|
|
|
162
165
|
const recursiveCheckHasActiveChild = (items) => {
|
|
163
166
|
let matchAppCode = false;
|
|
164
167
|
for (const item of items) {
|
|
165
|
-
if (
|
|
166
|
-
url.includes(getGeneratePath(item.menu_item_path, auth))) {
|
|
168
|
+
if (!!(item === null || item === void 0 ? void 0 : item.menu_item_path) && url.includes(getGeneratePath(item.menu_item_path, auth))) {
|
|
167
169
|
matchAppCode = true;
|
|
168
170
|
break;
|
|
169
171
|
}
|
|
@@ -177,7 +179,7 @@ export const findActiveAppCodeByUrl = (args) => {
|
|
|
177
179
|
return matchAppCode;
|
|
178
180
|
};
|
|
179
181
|
for (const menuItem of menuItems) {
|
|
180
|
-
if (
|
|
182
|
+
if (!!(menuItem === null || menuItem === void 0 ? void 0 : menuItem.menu_item_path) &&
|
|
181
183
|
url.includes(getGeneratePath(menuItem.menu_item_path, auth))) {
|
|
182
184
|
matchAppCode = menuItem.menu_item_code;
|
|
183
185
|
break;
|
|
@@ -198,3 +200,28 @@ export const findActiveAppCodeByUrl = (args) => {
|
|
|
198
200
|
});
|
|
199
201
|
}
|
|
200
202
|
};
|
|
203
|
+
export const findLastMatchedCodeByUrl = (args) => {
|
|
204
|
+
try {
|
|
205
|
+
const { url, menuItems, auth } = args;
|
|
206
|
+
const matchedItemCodes = [];
|
|
207
|
+
const recursiveFindActiveItem = (items) => {
|
|
208
|
+
for (const item of items) {
|
|
209
|
+
if (!!(item === null || item === void 0 ? void 0 : item.menu_item_path) && url.includes(getGeneratePath(item.menu_item_path, auth))) {
|
|
210
|
+
matchedItemCodes.push(item.menu_item_code);
|
|
211
|
+
}
|
|
212
|
+
if ((item === null || item === void 0 ? void 0 : item.children) && item.children.length) {
|
|
213
|
+
recursiveFindActiveItem(item.children);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
recursiveFindActiveItem(menuItems || []);
|
|
218
|
+
return matchedItemCodes === null || matchedItemCodes === void 0 ? void 0 : matchedItemCodes.pop();
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
handleError(error, {
|
|
222
|
+
path: PATH,
|
|
223
|
+
name: findLastMatchedCodeByUrl.name,
|
|
224
|
+
args,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
};
|
|
@@ -7,7 +7,9 @@ interface LayoutProps {
|
|
|
7
7
|
headerProps?: Partial<HeaderV2Props>;
|
|
8
8
|
leftMenuProps?: LeftMenuProps;
|
|
9
9
|
processingNotificationProps?: Partial<ProcessingNotificationProps>;
|
|
10
|
-
workspaceProps?: React.HTMLAttributes<HTMLDivElement
|
|
10
|
+
workspaceProps?: React.HTMLAttributes<HTMLDivElement> & {
|
|
11
|
+
workspaceContentProps?: React.HTMLAttributes<HTMLDivElement>;
|
|
12
|
+
};
|
|
11
13
|
}
|
|
12
14
|
export declare const Layout: React.FC<PropsWithChildren<LayoutProps>>;
|
|
13
15
|
declare global {
|
|
@@ -10,7 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
// Libraries
|
|
13
|
-
import React, { memo, useMemo } from 'react';
|
|
13
|
+
import React, { memo, useCallback, useMemo, useState } from 'react';
|
|
14
14
|
import { useContextSelector } from 'use-context-selector';
|
|
15
15
|
import AntsProcessingNotification from '@antscorp/processing-notification';
|
|
16
16
|
import { merge } from 'lodash';
|
|
@@ -27,16 +27,19 @@ import { PERMISSION_API, SOCKET_API } from '../../../constants';
|
|
|
27
27
|
// Css
|
|
28
28
|
import '@antscorp/processing-notification/dist/index.css';
|
|
29
29
|
import { useLayoutStore } from './stores';
|
|
30
|
+
import { checkingRoleScope } from './utils';
|
|
30
31
|
export const Layout = memo(props => {
|
|
31
32
|
const { leftMenuProps, headerProps = {}, workspaceProps, processingNotificationProps, children, } = props;
|
|
32
33
|
const _a = leftMenuProps || {}, { className = '' } = _a, restOfLeftMenuProps = __rest(_a, ["className"]);
|
|
34
|
+
const _b = workspaceProps || {}, { workspaceContentProps } = _b, restOfWorkspaceProps = __rest(_b, ["workspaceContentProps"]);
|
|
33
35
|
// Selectors
|
|
34
36
|
const { auth, languageCode } = useContextSelector(AppConfigContext, state => state);
|
|
35
37
|
const { token, userId, portalId } = auth || {};
|
|
36
38
|
const headerStore = useLayoutStore(store => store.state.header);
|
|
39
|
+
const [showAccountSelection, setShowAccountSelection] = useState(false);
|
|
37
40
|
// Memo
|
|
38
41
|
const initialHeaderProps = useMemo(() => {
|
|
39
|
-
var _a;
|
|
42
|
+
var _a, _b;
|
|
40
43
|
return (Object.assign(Object.assign({ className: 'layout-header' }, headerProps), { helpConfig: {
|
|
41
44
|
configs: Object.assign(Object.assign({}, (_a = headerProps === null || headerProps === void 0 ? void 0 : headerProps.helpConfig) === null || _a === void 0 ? void 0 : _a.configs), { appCode: 'SANDBOX_MARKETING', avatar: '//c0-platform.ants.tech/avatar/2021/09/17/0xgbkurioo.png', config: {
|
|
42
45
|
p_timezone: 'Asia/Singapore',
|
|
@@ -45,18 +48,30 @@ export const Layout = memo(props => {
|
|
|
45
48
|
embeddedData: {},
|
|
46
49
|
INSIGHT_U_OGS: 'uogs',
|
|
47
50
|
} }),
|
|
48
|
-
}, accountSharingConfig: Object.assign(Object.assign({}, headerProps === null || headerProps === void 0 ? void 0 : headerProps.accountSharingConfig), { u_ogs: 'uogs', appCode: 'APP_CUSTOMER_360' }) }));
|
|
49
|
-
}, [headerProps]);
|
|
51
|
+
}, accountSharingConfig: Object.assign(Object.assign({}, headerProps === null || headerProps === void 0 ? void 0 : headerProps.accountSharingConfig), { u_ogs: 'uogs', appCode: 'APP_CUSTOMER_360' }), accountSelection: Object.assign(Object.assign({}, headerProps === null || headerProps === void 0 ? void 0 : headerProps.accountSelection), { show: ((_b = headerProps === null || headerProps === void 0 ? void 0 : headerProps.accountSelection) === null || _b === void 0 ? void 0 : _b.show) && showAccountSelection }) }));
|
|
52
|
+
}, [headerProps, showAccountSelection]);
|
|
50
53
|
const mergeHeaderProps = useMemo(() => merge(initialHeaderProps, headerStore), [initialHeaderProps, headerStore]);
|
|
51
54
|
const antsProcessingNotificationConfig = useMemo(() => (Object.assign({ permissionDomain: PERMISSION_API, socketDomain: SOCKET_API, token, accountId: userId, userId, lang: languageCode, networkId: portalId }, processingNotificationProps)), [languageCode, portalId, token, userId, processingNotificationProps]);
|
|
55
|
+
// const showAccountSelection = useMemo(() => HIDE_MODAL_ACCOUNT.includes(menuCodeActive), []);
|
|
56
|
+
// const showAccountSelection =
|
|
57
|
+
// !state.hasRoleBreadcrumb ||
|
|
58
|
+
// HIDE_MODAL_ACCOUNT.includes(menuCodeActive) ||
|
|
59
|
+
// isHiddenAccountJourney;
|
|
60
|
+
const onActiveMenuCodeChange = useCallback((activeMenuCode, flattenPermissionList) => {
|
|
61
|
+
const menuPermission = flattenPermissionList === null || flattenPermissionList === void 0 ? void 0 : flattenPermissionList.find(item => activeMenuCode === item.app_code || activeMenuCode === item.menu_code);
|
|
62
|
+
const roleScope = activeMenuCode && menuPermission
|
|
63
|
+
? checkingRoleScope({ menuCode: activeMenuCode, menuPermission })
|
|
64
|
+
: false;
|
|
65
|
+
setShowAccountSelection(roleScope);
|
|
66
|
+
}, []);
|
|
52
67
|
return (React.createElement(LayoutWrapper, null,
|
|
53
68
|
React.createElement(HeaderV2, Object.assign({}, mergeHeaderProps)),
|
|
54
69
|
React.createElement(Flex, { className: "layout-body" },
|
|
55
|
-
React.createElement(LeftMenu, Object.assign({ className: `layout-body__menu ${className}` }, restOfLeftMenuProps)),
|
|
70
|
+
React.createElement(LeftMenu, Object.assign({ className: `layout-body__menu ${className}` }, restOfLeftMenuProps, { onActiveMenuCodeChange: onActiveMenuCodeChange })),
|
|
56
71
|
React.createElement(ContentWrapper, null,
|
|
57
|
-
React.createElement("div", Object.assign({},
|
|
72
|
+
React.createElement("div", Object.assign({}, restOfWorkspaceProps, { className: `layout-body__content ${(workspaceProps === null || workspaceProps === void 0 ? void 0 : workspaceProps.className) || ''}` }),
|
|
58
73
|
React.createElement(NotificationWrapper, null,
|
|
59
74
|
React.createElement(AntsProcessingNotification, Object.assign({}, antsProcessingNotificationConfig))),
|
|
60
|
-
React.createElement(ChildrenWrapper,
|
|
75
|
+
React.createElement(ChildrenWrapper, Object.assign({}, workspaceContentProps),
|
|
61
76
|
React.createElement("div", null, children)))))));
|
|
62
77
|
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare const MENU_CODE: {
|
|
2
|
+
VISITOR: string;
|
|
3
|
+
PLANNINGS: string;
|
|
4
|
+
CUSTOMER: string;
|
|
5
|
+
SEGMENT: string;
|
|
6
|
+
EVENT_SOURCES: string;
|
|
7
|
+
ANALYTICS_MODELS: string;
|
|
8
|
+
JOURNEY: string;
|
|
9
|
+
DESTINATIONS_HUB: string;
|
|
10
|
+
ACCOUNT: string;
|
|
11
|
+
DATA_ENCRYPT: string;
|
|
12
|
+
PORTAL_PREFERENCES: string;
|
|
13
|
+
BUSINESS_OBJECT: string;
|
|
14
|
+
PROMOTION_CENTER: string;
|
|
15
|
+
LABELS: string;
|
|
16
|
+
DASHBOARD_OVERVIEW: string;
|
|
17
|
+
MEDIA_TEMPLATE: string;
|
|
18
|
+
JSON_TEMPLATE: string;
|
|
19
|
+
EMAIL_TEMPLATE: string;
|
|
20
|
+
DIAGRAM: string;
|
|
21
|
+
RFM: string;
|
|
22
|
+
LINK_MANAGEMENT: string;
|
|
23
|
+
CONVERSION: string;
|
|
24
|
+
OVERVIEW: string;
|
|
25
|
+
DASHBOARD: string;
|
|
26
|
+
DATA_VIEW: string;
|
|
27
|
+
DATA_OBJECT: string;
|
|
28
|
+
JOURNEY_TACTIC: string;
|
|
29
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const MENU_CODE = {
|
|
2
|
+
VISITOR: `VISITOR`,
|
|
3
|
+
PLANNINGS: 'PLANNINGS',
|
|
4
|
+
CUSTOMER: `CUSTOMER`,
|
|
5
|
+
SEGMENT: `SEGMENT`,
|
|
6
|
+
EVENT_SOURCES: `EVENT_SOURCES`,
|
|
7
|
+
ANALYTICS_MODELS: `ANALYTICS_MODELS`,
|
|
8
|
+
JOURNEY: `JOURNEY`,
|
|
9
|
+
DESTINATIONS_HUB: `DESTINATIONS_HUB`,
|
|
10
|
+
ACCOUNT: `ACCOUNT`,
|
|
11
|
+
DATA_ENCRYPT: `DATA_ENCRYPT`,
|
|
12
|
+
PORTAL_PREFERENCES: 'PORTAL_PREFERENCES',
|
|
13
|
+
// PORTAL_PREFERENCES: 'ACCOUNT',
|
|
14
|
+
BUSINESS_OBJECT: 'BUSINESS_OBJECT',
|
|
15
|
+
PROMOTION_CENTER: 'PROMOTION_CENTER',
|
|
16
|
+
LABELS: 'LABELS',
|
|
17
|
+
DASHBOARD_OVERVIEW: 'DASHBOARD_OVERVIEW',
|
|
18
|
+
MEDIA_TEMPLATE: 'MEDIA_TEMPLATE',
|
|
19
|
+
JSON_TEMPLATE: 'JSON_TEMPLATE',
|
|
20
|
+
EMAIL_TEMPLATE: 'EMAIL_TEMPLATE',
|
|
21
|
+
DIAGRAM: 'DATA_SCHEMA',
|
|
22
|
+
RFM: 'RFM',
|
|
23
|
+
LINK_MANAGEMENT: 'LINK_MANAGEMENT',
|
|
24
|
+
CONVERSION: 'CONVERSION',
|
|
25
|
+
OVERVIEW: 'JOURNEY_OVERVIEW',
|
|
26
|
+
DASHBOARD: 'DASHBOARD',
|
|
27
|
+
DATA_VIEW: 'DATA_VIEW',
|
|
28
|
+
DATA_OBJECT: 'DATA_OBJECT',
|
|
29
|
+
JOURNEY_TACTIC: 'JOURNEY_TACTIC',
|
|
30
|
+
};
|
|
@@ -2,15 +2,20 @@ import { HeaderV2Props } from '../../../molecules';
|
|
|
2
2
|
import { DeepPartial } from '@antscorp/antsomi-ui/es/types';
|
|
3
3
|
export interface HeaderStore extends Partial<HeaderV2Props> {
|
|
4
4
|
}
|
|
5
|
+
export interface LeftMenuStore {
|
|
6
|
+
menuCodeActive?: string;
|
|
7
|
+
}
|
|
5
8
|
export interface WorkspaceStore {
|
|
6
9
|
}
|
|
7
10
|
export interface LayoutStoreState {
|
|
8
11
|
header: HeaderStore;
|
|
12
|
+
leftMenu: LeftMenuStore;
|
|
9
13
|
workspace: WorkspaceStore;
|
|
10
14
|
}
|
|
11
15
|
interface LayoutStore {
|
|
12
16
|
state: LayoutStoreState;
|
|
13
17
|
setHeaderState: (state: DeepPartial<HeaderStore>) => void;
|
|
18
|
+
setLeftMenuState: (state: DeepPartial<LeftMenuStore>) => void;
|
|
14
19
|
setWorkspaceState: (state: Partial<WorkspaceStore>) => void;
|
|
15
20
|
setLayoutState: (state: DeepPartial<LayoutStoreState>) => void;
|
|
16
21
|
}
|
|
@@ -3,6 +3,7 @@ import { create } from 'zustand';
|
|
|
3
3
|
import { merge } from 'lodash';
|
|
4
4
|
const initialState = {
|
|
5
5
|
header: {},
|
|
6
|
+
leftMenu: {},
|
|
6
7
|
workspace: {},
|
|
7
8
|
};
|
|
8
9
|
export const useLayoutStore = create(set => ({
|
|
@@ -11,6 +12,9 @@ export const useLayoutStore = create(set => ({
|
|
|
11
12
|
setHeaderState: newState => set(store => ({
|
|
12
13
|
state: Object.assign(Object.assign({}, store.state), { header: Object.assign(Object.assign({}, store.state.header), newState) }),
|
|
13
14
|
})),
|
|
15
|
+
setLeftMenuState: newState => set(store => ({
|
|
16
|
+
state: Object.assign(Object.assign({}, store.state), { leftMenu: Object.assign(Object.assign({}, store.state.leftMenu), newState) }),
|
|
17
|
+
})),
|
|
14
18
|
setWorkspaceState: newState => set(store => ({
|
|
15
19
|
state: Object.assign(Object.assign({}, store.state), { workspace: Object.assign(Object.assign({}, store.state.workspace), newState) }),
|
|
16
20
|
})),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './permission';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './permission';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FeatureMenuPermission } from '@antscorp/antsomi-ui/es/models/LeftMenu';
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* @param {*} menuCode MENU_CODE
|
|
5
|
+
* @param {*} action APP_ACTION
|
|
6
|
+
* @param {*} scope APP_ROLE_SCOPE
|
|
7
|
+
* @param {*} isExactly
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
export declare const checkingRoleScope: (args: {
|
|
11
|
+
menuCode: string;
|
|
12
|
+
menuPermission: FeatureMenuPermission;
|
|
13
|
+
action?: string;
|
|
14
|
+
scope?: string;
|
|
15
|
+
isExactly?: boolean;
|
|
16
|
+
}) => boolean;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { MENU_CODE, APP_ROLE_SCOPE } from '../constants';
|
|
2
|
+
const EDIT_ROLE = new Set(['CREATE', 'UPDATE', 'DELETE']);
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {*} menuCode MENU_CODE
|
|
6
|
+
* @param {*} action APP_ACTION
|
|
7
|
+
* @param {*} scope APP_ROLE_SCOPE
|
|
8
|
+
* @param {*} isExactly
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
export const checkingRoleScope = (args) => {
|
|
12
|
+
const { menuCode, menuPermission, scope = APP_ROLE_SCOPE.NONE, action = 'NONE', isExactly = false, } = args;
|
|
13
|
+
if (![
|
|
14
|
+
MENU_CODE.JOURNEY,
|
|
15
|
+
MENU_CODE.LABELS,
|
|
16
|
+
MENU_CODE.DASHBOARD_OVERVIEW,
|
|
17
|
+
MENU_CODE.MEDIA_TEMPLATE,
|
|
18
|
+
MENU_CODE.EMAIL_TEMPLATE,
|
|
19
|
+
MENU_CODE.SEGMENT,
|
|
20
|
+
MENU_CODE.DESTINATIONS_HUB,
|
|
21
|
+
MENU_CODE.BUSINESS_OBJECT,
|
|
22
|
+
MENU_CODE.DATA_OBJECT,
|
|
23
|
+
MENU_CODE.DATA_VIEW,
|
|
24
|
+
].includes(menuCode))
|
|
25
|
+
return false;
|
|
26
|
+
const menuRole = menuPermission;
|
|
27
|
+
let isOK = false;
|
|
28
|
+
// role Create/Update/Delete is similar current define, only has view and edit(create/delete)
|
|
29
|
+
const { selected_view = 1, selected_edit = 1 } = menuRole;
|
|
30
|
+
if (isExactly) {
|
|
31
|
+
if (EDIT_ROLE.has(action)) {
|
|
32
|
+
isOK = Number(selected_edit) === Number(scope);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
isOK = Number(selected_view) === Number(scope);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// eslint-disable-next-line no-lonely-if
|
|
40
|
+
if (EDIT_ROLE.has(action)) {
|
|
41
|
+
isOK = Number(selected_edit) >= Number(scope);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
isOK = Number(selected_view) >= Number(scope);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return isOK;
|
|
48
|
+
};
|
package/package.json
CHANGED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { generateKey } from '../../utils';
|
|
2
|
-
const getAccessType = public_role => {
|
|
3
|
-
switch (public_role) {
|
|
4
|
-
case 2: // editor
|
|
5
|
-
return {
|
|
6
|
-
label: 'Editor',
|
|
7
|
-
value: 'editor',
|
|
8
|
-
type: 'TYPE_ACCESS',
|
|
9
|
-
};
|
|
10
|
-
case 3: // viewer
|
|
11
|
-
return {
|
|
12
|
-
label: 'Viewer',
|
|
13
|
-
value: 'viewer',
|
|
14
|
-
type: 'TYPE_ACCESS',
|
|
15
|
-
};
|
|
16
|
-
default:
|
|
17
|
-
return {};
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
export function getCurrentUserId() {
|
|
21
|
-
return '';
|
|
22
|
-
// const userId = safeParse(getAppSession('user_id'), 0);
|
|
23
|
-
// if (userId === 0) {
|
|
24
|
-
// // if user_id not set, read 3rd cookie
|
|
25
|
-
// try {
|
|
26
|
-
// const tempt = getCookie(`${PORTAL_CONFIG.INSIGHT_U_OGS}_${getPortalId()}`);
|
|
27
|
-
// // console.log(tempt);
|
|
28
|
-
// if (tempt) {
|
|
29
|
-
// const data = JSON.parse(tempt);
|
|
30
|
-
// return parseInt(window.decodeURIComponent(data.user_id));
|
|
31
|
-
// }
|
|
32
|
-
// } catch (err) {
|
|
33
|
-
// console.error(err);
|
|
34
|
-
// }
|
|
35
|
-
// }
|
|
36
|
-
// return userId;
|
|
37
|
-
}
|
|
38
|
-
const checkAllowEdit = (listAccess = [], isPublic, publicRole) => {
|
|
39
|
-
let isAllowEdit = false;
|
|
40
|
-
const userId = getCurrentUserId();
|
|
41
|
-
const listUserIdAllowEdit = listAccess.map(access => {
|
|
42
|
-
if (+access.role === 1 || +access.role === 2) {
|
|
43
|
-
return +access.user_id;
|
|
44
|
-
}
|
|
45
|
-
return undefined;
|
|
46
|
-
});
|
|
47
|
-
if (isPublic && +publicRole === 2) {
|
|
48
|
-
// dashboard set permission public-edit
|
|
49
|
-
isAllowEdit = true;
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
isAllowEdit = listUserIdAllowEdit.includes(+userId);
|
|
53
|
-
}
|
|
54
|
-
return isAllowEdit;
|
|
55
|
-
};
|
|
56
|
-
export const convertShareAccessToFE = (shareAccess = {}) => {
|
|
57
|
-
const dataConvert = {
|
|
58
|
-
general: {},
|
|
59
|
-
listAccess: [],
|
|
60
|
-
};
|
|
61
|
-
const { is_public, list_access = [], public_role } = shareAccess || {};
|
|
62
|
-
let newGeneral = {};
|
|
63
|
-
let newListAccess = [];
|
|
64
|
-
switch (is_public) {
|
|
65
|
-
case 1: // public
|
|
66
|
-
newGeneral = {
|
|
67
|
-
label: 'Public',
|
|
68
|
-
value: 'public',
|
|
69
|
-
description: 'Anyone on the portal can view this item',
|
|
70
|
-
icon: 'icon-xlab-padlock-open',
|
|
71
|
-
type: 'GENERAL_ACCESS',
|
|
72
|
-
isPublic: 1,
|
|
73
|
-
};
|
|
74
|
-
if (public_role) {
|
|
75
|
-
newGeneral.accessType = getAccessType(+public_role);
|
|
76
|
-
}
|
|
77
|
-
break;
|
|
78
|
-
case 0:
|
|
79
|
-
newGeneral = {
|
|
80
|
-
label: 'Restricted',
|
|
81
|
-
value: 'restricted',
|
|
82
|
-
description: 'Only people with access can open this item',
|
|
83
|
-
icon: 'icon-xlab-padlock-filled',
|
|
84
|
-
type: 'GENERAL_ACCESS',
|
|
85
|
-
isPublic: 0,
|
|
86
|
-
};
|
|
87
|
-
break;
|
|
88
|
-
default:
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
newListAccess = list_access.map(access => {
|
|
92
|
-
const { user_id, full_name, email, role, avatar } = access;
|
|
93
|
-
const data = {
|
|
94
|
-
id: generateKey(),
|
|
95
|
-
userId: +user_id,
|
|
96
|
-
name: full_name,
|
|
97
|
-
email,
|
|
98
|
-
role: +role,
|
|
99
|
-
avatar,
|
|
100
|
-
};
|
|
101
|
-
if (+role === 1) {
|
|
102
|
-
data.accessType = {
|
|
103
|
-
value: 'owner',
|
|
104
|
-
label: 'Owner',
|
|
105
|
-
};
|
|
106
|
-
data.allow_view = 1;
|
|
107
|
-
data.allow_edit = 1;
|
|
108
|
-
}
|
|
109
|
-
else if (+role === 2) {
|
|
110
|
-
data.accessType = {
|
|
111
|
-
value: 'editor',
|
|
112
|
-
label: 'Editor',
|
|
113
|
-
};
|
|
114
|
-
data.allow_view = 1;
|
|
115
|
-
data.allow_edit = 1;
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
data.accessType = {
|
|
119
|
-
value: 'viewer',
|
|
120
|
-
label: 'Viewer',
|
|
121
|
-
};
|
|
122
|
-
data.allow_view = 1;
|
|
123
|
-
data.allow_edit = 0;
|
|
124
|
-
}
|
|
125
|
-
return data;
|
|
126
|
-
});
|
|
127
|
-
const isAllowEdit = checkAllowEdit(list_access, is_public, public_role);
|
|
128
|
-
dataConvert.general = newGeneral;
|
|
129
|
-
dataConvert.listAccess = newListAccess;
|
|
130
|
-
return {
|
|
131
|
-
accessInfo: dataConvert,
|
|
132
|
-
isAllowEdit,
|
|
133
|
-
isPublic: is_public,
|
|
134
|
-
};
|
|
135
|
-
};
|