nexus-shared 1.1.19 → 1.1.21

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.
Files changed (53) hide show
  1. package/package.json +1 -1
  2. package/src/api-services/authentication-service.tsx +23 -0
  3. package/src/api-services/system-service.tsx +24 -316
  4. package/src/client.ts +1 -2
  5. package/src/components/documents/button.tsx +9 -16
  6. package/src/components/documents/icon-box.tsx +1 -1
  7. package/src/components/documents/tab-button.tsx +2 -2
  8. package/src/components/documents/tag.tsx +30 -0
  9. package/src/components/inputs/input-element.tsx +1 -1
  10. package/src/components/inputs/input-form.tsx +2 -2
  11. package/src/components/layouts/global-dialogbox.tsx +5 -9
  12. package/src/components/layouts/global-layout.tsx +8 -0
  13. package/src/components/layouts/layout-helpers.tsx +1 -4
  14. package/src/components/layouts/panels/user-panel.tsx +112 -0
  15. package/src/components/layouts/utility-menu.tsx +9 -29
  16. package/src/components/panels/theme-panel.tsx +2 -2
  17. package/src/helpers/browser-helpers.tsx +48 -3
  18. package/src/helpers/element-helpers.tsx +66 -0
  19. package/src/interface.ts +1 -0
  20. package/src/interfaces/auth-token-interfaces.tsx +6 -0
  21. package/src/interfaces/browser-interfaces.tsx +13 -0
  22. package/src/interfaces/http-interfaces.tsx +0 -3
  23. package/src/interfaces/icon-interfaces.tsx +3 -0
  24. package/src/interfaces/menu-interfaces.tsx +18 -1
  25. package/src/interfaces/storage-interfaces.tsx +1 -0
  26. package/src/interfaces/theme-interfaces.tsx +43 -129
  27. package/src/interfaces/user-interfaces.tsx +30 -0
  28. package/src/nexus.environments.tsx +39 -27
  29. package/src/services/http-services.tsx +6 -6
  30. package/src/services/loader-service.tsx +33 -17
  31. package/src/services/localstorage-service.tsx +23 -6
  32. package/src/services/message-services.tsx +1 -1
  33. package/src/services/theme-service.tsx +32 -16
  34. package/src/services/user-services.tsx +10 -0
  35. package/src/sso-config/auth-token-validation.ts +4 -8
  36. package/src/sso-config/callback-route.tsx +3 -2
  37. package/src/sso-config/cookie-helpers.tsx +47 -22
  38. package/src/sso-config/oauth-callback-state.ts +5 -2
  39. package/src/sso-config/pkce-helpers.ts +2 -9
  40. package/src/sso-config/provider-complete-route.tsx +7 -4
  41. package/src/sso-config/redirect-context-actions.tsx +2 -3
  42. package/src/sso-config/redirect-context-helpers.tsx +20 -5
  43. package/src/sso-config/refresh-route.tsx +5 -4
  44. package/src/sso-config/sign-in-route.tsx +9 -4
  45. package/src/sso-config/sign-out-route.tsx +7 -3
  46. package/src/sso-config/sign-up-route.tsx +14 -3
  47. package/src/sso-config/sso-backend-flow.ts +10 -17
  48. package/src/sso-config/sso-complete-route.tsx +7 -3
  49. package/src/sso-config/sso-config.ts +7 -5
  50. package/src/sso-config/sso-interfaces.tsx +34 -3
  51. package/src/styles/nexus.grid-view.css +42 -0
  52. package/src/styles/nexus.icon.css +1 -0
  53. package/src/styles/nexus.logic.css +34 -5
@@ -0,0 +1,112 @@
1
+ import Image from "next/image";
2
+ import React, { JSX, useEffect, useMemo, useState } from "react";
3
+ import { GetProfileDetails } from "../../../api-services/authentication-service";
4
+ import { BuildImageUrl, GetAuthPageURL, GetSignOutPageURL } from "../../../helpers/browser-helpers";
5
+ import { BUTTON_IDENTITY, ClickHandler, EBackgrounds, EButtonTypes, EFileSizes, EIcons, EMenuVisibility, EOpacity, EPositions, ESizes, GetButton, GetUtilityMenuCode, IButton, ICurrentUser, IGlobalLayout, IPanelMenu, IsAdmin_SuperAdmin, UN } from "../../../interface";
6
+ import { FILES } from "../../../nexus.environments";
7
+ import { InputLoader, ShowLoader } from "../../../services/loader-service";
8
+ import { SetCurrentUser } from "../../../services/user-services";
9
+ import { Buttons } from "../../documents/button";
10
+ import { Iconbox } from "../../documents/icon-box";
11
+ import { GetUserRoleTag } from "../../documents/tag";
12
+ import { GlobalDialogbox } from "../global-dialogbox";
13
+
14
+ const USER_PROFILE_ID = GetUtilityMenuCode("user-profile");
15
+ export const DEFAULT_USER_PROFILE_PICTURE_CLASS = "profile-user";
16
+ const USER_PROFILE_BUTTON_ID = "user-profile-menu-tab";
17
+
18
+ export const ProfilePanel = ({ globalLayout, userPanels, boxBackground, hasAccessToken }: Readonly<{ globalLayout: IGlobalLayout; userPanels: IPanelMenu[]; boxBackground?: EBackgrounds; hasAccessToken?: boolean | UN }>): JSX.Element => {
19
+ const [isLoading, setIsLoading] = useState(hasAccessToken === true);
20
+ const [currentUser, setCurrentUser] = useState<ICurrentUser | null>(null);
21
+ const groupPanels = useMemo(() => {
22
+ // TODO: Implement menu visibility logic
23
+ const isAuthenticated = currentUser && currentUser.username && hasAccessToken === true;
24
+ const visibilityFlag = isAuthenticated ? EMenuVisibility.AuthenticatedOnly : EMenuVisibility.GuestOnly;
25
+ const visibleMenus = userPanels.filter((x) => (x.menuVisibilities & visibilityFlag) !== 0);
26
+ return groupByGroupOrder(visibleMenus);
27
+ }, [userPanels, currentUser]);
28
+ const fetchProfileDetails = async () => {
29
+ setIsLoading(true);
30
+ InputLoader(USER_PROFILE_ID, true);
31
+ const response = await GetProfileDetails(true);
32
+ setCurrentUser(response);
33
+ SetCurrentUser(response);
34
+ setIsLoading(false);
35
+ InputLoader(USER_PROFILE_ID, false);
36
+ };
37
+ useEffect(() => {
38
+ if (hasAccessToken) fetchProfileDetails();
39
+ }, [hasAccessToken]);
40
+ return (
41
+ <div id={USER_PROFILE_ID} className={`pr ${ESizes.Small} ib ${boxBackground} h p2 r`}>
42
+ <Image src={FILES.ICONS.USER} alt="logo" width={74} height={74} className="img" />
43
+ {!isLoading && (
44
+ <GlobalDialogbox hoverEffectDelay={false} defaultPadding={0} position={EPositions.Left} buttonIdentity={USER_PROFILE_ID} iggnoreChildClick={false} defaultWidth={25}>
45
+ <React.Fragment>
46
+ <div className="bb h100 oh df ddc pl5">
47
+ <div style={{ display: currentUser ? "flex" : "none" }} className="df ac pr5 pt5">
48
+ <div className="ib xl oh item pr">
49
+ {currentUser && <Iconbox onClicked={() => onEditProfileClicked(currentUser)} iconOpacity={EOpacity.NONE} iconDefaultClass="xl" defaultClass="xl pa ho1 bg950 rr" background={EBackgrounds.None} icon={EIcons.CAMERA} />}
50
+ <img src={BuildImageUrl(currentUser?.profilePicture, EFileSizes.SIZE_128, FILES.ICONS.USER)} alt="profile-picture" className={`${DEFAULT_USER_PROFILE_PICTURE_CLASS} img ba2 rr`} />
51
+ </div>
52
+ <div className="ml5 w100">
53
+ <div className="df ac">
54
+ <h5 className="fw500 bg1 o09">{currentUser?.fullname}</h5>
55
+ </div>
56
+ <div className="df ac mt2">
57
+ <p className="bg1 mr5 o06">{currentUser?.emailAddress ?? `@${currentUser?.username}`}</p>
58
+ {IsAdmin_SuperAdmin(currentUser?.roleName) && GetUserRoleTag(currentUser?.roleName, true, "")}
59
+ </div>
60
+ </div>
61
+ </div>
62
+
63
+ <div className="sb sm h100 mt5 mb5 pr5">
64
+ {groupPanels.map((group, index) => (
65
+ <Buttons key={index} padding={0} pt={index !== 0 ? 5 : 0} buttons={group} />
66
+ ))}
67
+ </div>
68
+ </div>
69
+ </React.Fragment>
70
+ </GlobalDialogbox>
71
+ )}
72
+ </div>
73
+ );
74
+ };
75
+
76
+ const onEditProfileClicked = (currentUser: ICurrentUser) => {
77
+ // TODO: Implement edit profile functionality
78
+ };
79
+
80
+ function groupByGroupOrder(menuArray: IPanelMenu[]): IButton[][] {
81
+ const grouped: Record<number, IButton[]> = {};
82
+ menuArray.forEach((menu) => {
83
+ if (!grouped[menu.groupOrder]) {
84
+ grouped[menu.groupOrder] = [];
85
+ }
86
+ grouped[menu.groupOrder].push(GetButton(menu.menuName, menu.menuCode, menu.menuUrl, menu.menuIcon, onClickedPanelMenu, menu, null, null, menu.displayOrder, null, null, 12, 0, EButtonTypes.BUTTON));
87
+ });
88
+
89
+ const groupedArray = Object.keys(grouped)
90
+ .sort((a, b) => Number(a) - Number(b)) // Sort groups by groupOrder
91
+ .map((groupKey) => grouped[Number(groupKey)].sort((a, b) => (a.displayOrder ?? 0) - (b.displayOrder ?? 0)));
92
+
93
+ return groupedArray;
94
+ }
95
+
96
+ const onClickedPanelMenu: ClickHandler = async (event, element, data: IPanelMenu) => {
97
+ switch (data.menuCode) {
98
+ case BUTTON_IDENTITY(false).SIGN_IN_BUTTON: {
99
+ ShowLoader();
100
+ const url = GetAuthPageURL();
101
+ return (window.location.href = url);
102
+ }
103
+ case BUTTON_IDENTITY(false).SIGN_OUT_BUTTON: {
104
+ ShowLoader();
105
+ SetCurrentUser(null);
106
+ return (window.location.href = GetSignOutPageURL());
107
+ }
108
+ default: {
109
+ break;
110
+ }
111
+ }
112
+ };
@@ -1,56 +1,36 @@
1
- import React, { JSX } from "react";
1
+ import { UN } from "nexus-shared";
2
2
  import { EIconTypes } from "../../interfaces/icon-interfaces";
3
- import { EPositions, ESizes, IGlobalLayout } from "../../interfaces/layout-interfaces";
4
- import { GetUtilityMenuCode, IPanelMenu, IUtilityMenu, UTILITIES_BUTTON_PREFIX } from "../../interfaces/menu-interfaces";
3
+ import { EOpacity, EPositions, ESizes, IGlobalLayout } from "../../interfaces/layout-interfaces";
4
+ import { BUTTON_IDENTITY, GetUtilityMenuCode, IPanelMenu, IUtilityMenu } from "../../interfaces/menu-interfaces";
5
5
  import { EBackgrounds } from "../../interfaces/theme-interfaces";
6
6
  import { Iconbox } from "../documents/icon-box";
7
7
  import { PageTitle } from "../documents/page-title";
8
8
  import { ThemePanel } from "../panels/theme-panel";
9
9
  import { GlobalDialogbox } from "./global-dialogbox";
10
+ import { ProfilePanel } from "./panels/user-panel";
10
11
 
11
- export const BUTTON_IDENTITY = (isneedPrefix: boolean) => {
12
- const _ = isneedPrefix ? UTILITIES_BUTTON_PREFIX : "";
13
- return {
14
- PROFILE_BOX: `${_}profile`,
15
- SEARCH_BOX: `${_}root-search`,
16
- FAVORITE_BOX: `${_}favorite-menu`,
17
- CARD_BOX: `${_}cart-menu`,
18
- THEME_BOX: `${_}switch-theme`,
19
- MEGA_BOX: `${_}mega-menu`,
20
- SIGN_IN_BUTTON: `${_}sign-in`,
21
- SIGN_OUT_BUTTON: `${_}sign-out`,
22
- };
23
- };
24
- export const UtilityMenu = ({ utilityMenus, userPanels, column, paddingRight, globalLayout, iconBoxBackground }: Readonly<{ utilityMenus: IUtilityMenu[]; userPanels: IPanelMenu[]; column?: number; paddingRight?: number; globalLayout: IGlobalLayout; iconBoxBackground: EBackgrounds }>) => {
12
+ export const UtilityMenu = ({ utilityMenus, userPanels, column, paddingRight, globalLayout, iconBoxBackground, hasAccessToken }: Readonly<{ utilityMenus: IUtilityMenu[]; userPanels: IPanelMenu[]; column?: number; paddingRight?: number; globalLayout: IGlobalLayout; iconBoxBackground: EBackgrounds; hasAccessToken?: boolean | UN }>) => {
25
13
  return (
26
- <div style={{ paddingRight: paddingRight ?? 0, zIndex: 3 }} className={`utilities df fr ac jr h100p col-${column ?? 12}`}>
14
+ <div className={`utilities df fr ac jr h100p pr${paddingRight ?? 0} col-${column ?? 12}`}>
27
15
  {utilityMenus.map((utilityMenu, index) => (
28
16
  <UtilityIcon key={index} utilityMenu={utilityMenu} boxBackground={iconBoxBackground} globalLayout={globalLayout} />
29
17
  ))}
30
- <ProfilePanel globalLayout={globalLayout} boxBackground={iconBoxBackground} userPanels={userPanels} />
18
+ <ProfilePanel globalLayout={globalLayout} boxBackground={iconBoxBackground} userPanels={userPanels} hasAccessToken={hasAccessToken} />
31
19
  </div>
32
20
  );
33
21
  };
34
22
 
35
23
  const UtilityIcon = ({ utilityMenu, globalLayout, boxBackground }: Readonly<{ utilityMenu: IUtilityMenu; globalLayout: IGlobalLayout; boxBackground?: EBackgrounds }>) => {
36
24
  return (
37
- <Iconbox id={GetUtilityMenuCode(utilityMenu.menuCode)} icon={utilityMenu.menuIcon} iconType={EIconTypes.FILLED} iconSize={ESizes.Small} boxSize={ESizes.Small} background={boxBackground} defaultClass="mr2">
25
+ <Iconbox id={GetUtilityMenuCode(utilityMenu.menuCode)} icon={utilityMenu.menuIcon} iconType={EIconTypes.FILLED} iconSize={ESizes.Small} boxSize={ESizes.Small} background={boxBackground} iconOpacity={EOpacity.O07} defaultClass="ml2">
38
26
  <UtilityDialogBox utilityMenu={utilityMenu} globalLayout={globalLayout} />
39
27
  </Iconbox>
40
28
  );
41
29
  };
42
30
 
43
- export const ProfilePanel = ({ globalLayout, userPanels, boxBackground }: Readonly<{ globalLayout: IGlobalLayout; userPanels: IPanelMenu[]; boxBackground?: EBackgrounds }>): JSX.Element => {
44
- return (
45
- <div className={`pr ${ESizes.Small} ib ${boxBackground} h p2 r`}>
46
- <h6>BA</h6>
47
- </div>
48
- );
49
- };
50
-
51
31
  const UtilityDialogBox = ({ utilityMenu, globalLayout }: Readonly<{ utilityMenu: IUtilityMenu; globalLayout: IGlobalLayout }>) => {
52
32
  return (
53
- <GlobalDialogbox hoverEffectDelay={true} defaultPadding={5} position={EPositions.Left} buttonIdentity={GetUtilityMenuCode(utilityMenu.menuCode)} defaultWidth={30}>
33
+ <GlobalDialogbox hoverEffectDelay={false} defaultPadding={5} position={EPositions.Left} buttonIdentity={GetUtilityMenuCode(utilityMenu.menuCode)} defaultWidth={30}>
54
34
  <div>
55
35
  <PageTitle marginBottom={5} borderBottom={1} title={utilityMenu.menuName} />
56
36
  <UtilityPanel utilityMenu={utilityMenu} globalLayout={globalLayout} />
@@ -1,4 +1,4 @@
1
- 'use client';
1
+ "use client";
2
2
 
3
3
  import React, { useEffect } from "react";
4
4
  import { GetButton, IButton } from "../../interfaces/button-interfaces";
@@ -30,7 +30,7 @@ const RenderSwitchTheme = (baseElement: HTMLElement) => {
30
30
  baseElement.appendChild(p);
31
31
  return;
32
32
  }
33
- const themeButtons: IButton[] = themes.map((theme, index) => GetButton(theme.displayName, theme.systemName, null, theme.icon, onClicked, theme, null, null, theme.displayOrder, EIconTypes.FILLED, null));
33
+ const themeButtons: IButton[] = themes.map((theme, index) => GetButton(theme.displayName, theme.systemName, null, theme.iconName, onClicked, theme, null, null, theme.displayOrder, EIconTypes.OUTLINED, null));
34
34
  const activeButton = themeButtons.find((button) => button.id === currentTheme);
35
35
  CreateTabButtons(themeButtons, baseElement, activeButton, onClicked);
36
36
 
@@ -1,7 +1,7 @@
1
- import { UN } from "../interface";
1
+ import { BuildProxyApiUrl, EModules, ESigninRequestMode, UN } from "../interface";
2
2
  import { EAnimationClasses } from "../interfaces/layout-interfaces";
3
- import { NEXUS_INFO } from "../nexus.environments";
4
- import { EKeyModifier, EKeys } from "./../interfaces/browser-interfaces";
3
+ import { FILES, NEXUS_INFO, URLS } from "../nexus.environments";
4
+ import { EFileSizes, EKeyModifier, EKeys } from "./../interfaces/browser-interfaces";
5
5
  import { HasFlag } from "./bitwise-helpers";
6
6
  import { Debounce } from "./utility-helpers";
7
7
 
@@ -109,3 +109,48 @@ export const ConvertColorToRGBA = (color: string, alpha: number = 0.1): string =
109
109
 
110
110
  return `rgba(${r}, ${g}, ${b}, ${a})`;
111
111
  };
112
+ export function FindParentElement<ELEMENT extends Element>(element: Element | null | undefined, selector: string): ELEMENT | null {
113
+ if (!element || !selector || !element.matches) return null;
114
+
115
+ if (element.matches(selector)) return element as ELEMENT;
116
+
117
+ return FindParentElement<ELEMENT>(element.parentElement, selector);
118
+ }
119
+ export const GetCurrentFullURL = () => window?.location?.href;
120
+ export const GetCurrentBaseURL = () => window?.location?.origin;
121
+ export const BuildImageUrl = (viewToken?: string | UN, size?: EFileSizes | UN, fallback?: string | UN, isPublic: boolean = false) => {
122
+ if (!viewToken) return fallback ?? FILES.ICONS.NO_IMAGE;
123
+ if (!size) size = EFileSizes.SIZE_256;
124
+ if (isPublic) return BuildProxyApiUrl(EModules.Drive, `Public/Image/${size}/${viewToken}`);
125
+ else return BuildProxyApiUrl(EModules.Drive, `Private/Image/${size}/${viewToken}`);
126
+ };
127
+
128
+ const resolveReturnPath = (redirectURL?: string | UN): string => {
129
+ if (redirectURL) {
130
+ try {
131
+ const url = new URL(redirectURL, GetCurrentBaseURL());
132
+ return url.pathname + url.search || "/";
133
+ } catch {
134
+ /* fall through to current location */
135
+ }
136
+ }
137
+ if (!IsBrowser()) return "/";
138
+ return window.location.pathname + window.location.search || "/";
139
+ };
140
+
141
+ export const GetAuthPageURL = (redirectURL?: string | UN, signinMode?: ESigninRequestMode | UN) => {
142
+ const setupUrl = new URL(URLS.GLOBAL_SIGNIN);
143
+ setupUrl.searchParams.set("redirect_uri", `${GetCurrentBaseURL()}/api/auth/callback`);
144
+ setupUrl.searchParams.set("state", resolveReturnPath(redirectURL));
145
+ setupUrl.searchParams.set("signin_mode", signinMode ?? ESigninRequestMode.DEFAULT);
146
+ return setupUrl.toString();
147
+ };
148
+
149
+ /** Clears the session via /api/auth/sign-out; non-admin apps return to the current page (with query params). */
150
+ export const GetSignOutPageURL = (returnPath?: string | UN) => {
151
+ const signOutUrl = new URL(`${GetCurrentBaseURL()}/api/auth/sign-out`);
152
+ if (!NEXUS_INFO.IS_ADMIN_MODULE) {
153
+ signOutUrl.searchParams.set("returnUrl", resolveReturnPath(returnPath));
154
+ }
155
+ return signOutUrl.toString();
156
+ };
@@ -1,4 +1,70 @@
1
+ import { EBackgroundColors, EBackgrounds, EColorTypes } from "../interfaces/theme-interfaces";
1
2
  import { UN } from "../interfaces/type-interfaces";
3
+ import { GetDynamicColor } from "../services/theme-service";
4
+ import { GetCurrentBaseURL, GetCurrentFullURL, SetDocumentTitleDebounce } from "./browser-helpers";
5
+
6
+ const HOME_PATHS = ["/", "", "/home", "home", "/index", "index"];
7
+
8
+ export interface IMenuDocumentTitle {
9
+ menuUrl?: string;
10
+ menuName: string;
11
+ documentTitle?: string;
12
+ }
13
+
14
+ export interface IFindActiveMenuOptions {
15
+ rootPath?: string;
16
+ defaultMenuUrl?: string;
17
+ }
18
+
19
+ export const SET_BUTTON_ACTIVE_CLASS = (isActive: boolean, element: HTMLElement, overrideBackgroundColor?: EBackgroundColors | UN, overrideBorderColor?: EBackgroundColors | UN, overrideTextColor?: EBackgroundColors | UN, overrideActiveClass?: string | UN) => {
20
+ if (!element) return;
21
+
22
+ if (isActive && overrideBackgroundColor) element.style.setProperty("--ACTIVE_BACKGROUND_COLOR", overrideBackgroundColor);
23
+ if (isActive && overrideBorderColor) element.style.setProperty("--ACTIVE_BORDER_COLOR", overrideBorderColor);
24
+ if (isActive && overrideTextColor) element.style.setProperty("--ACTIVE_TEXT_COLOR", overrideTextColor);
25
+
26
+ if (isActive) element.classList.add(overrideActiveClass ?? "active");
27
+ else element.classList.remove(overrideActiveClass ?? "active");
28
+ };
29
+
30
+ export function FindActiveMenu<T extends IMenuDocumentTitle>(menus: T[], options?: IFindActiveMenuOptions): T | undefined {
31
+ const rootPath = options?.rootPath ?? "";
32
+ const defaultMenuUrl = options?.defaultMenuUrl ?? "/home";
33
+
34
+ const fullUrl = GetCurrentFullURL()?.split("?")[0] ?? "";
35
+ const baseURL = GetCurrentBaseURL() ?? "";
36
+ const url = fullUrl.replace(baseURL, "");
37
+
38
+ const relativePath = rootPath ? (url === rootPath || url === `${rootPath}/` ? "/" : url.startsWith(`${rootPath}/`) ? url.slice(rootPath.length) : url) : url;
39
+ const normalizedRelativePath = relativePath.replace(/^\//, "");
40
+ const isHome = HOME_PATHS.includes(relativePath) || HOME_PATHS.includes(normalizedRelativePath);
41
+
42
+ let activeMenu: T | undefined;
43
+
44
+ if (isHome) {
45
+ activeMenu = rootPath ? menus.find((x) => x.menuUrl === defaultMenuUrl.replace(/^\//, "")) : menus.find((x) => x.menuUrl === defaultMenuUrl);
46
+ } else {
47
+ activeMenu = menus.find((x) => {
48
+ const menuPath = rootPath ? `${rootPath}/${x.menuUrl}` : (x.menuUrl ?? "");
49
+ return url.includes(menuPath) || url.includes(x.menuUrl ?? "");
50
+ });
51
+ }
52
+
53
+ SetDocumentTitleDebounce(activeMenu?.documentTitle ?? activeMenu?.menuName);
54
+ return activeMenu;
55
+ }
56
+
57
+ export const SetSiblingMenuLinkActive = (activeLink: HTMLElement, container: HTMLElement | UN, linkSelector: string, boxBackground: EBackgrounds, activeClass: string = "left-active") => {
58
+ if (!activeLink) return;
59
+
60
+ SET_BUTTON_ACTIVE_CLASS(true, activeLink, GetDynamicColor(boxBackground, EColorTypes.Hover) as EBackgroundColors, null, GetDynamicColor(boxBackground, EColorTypes.Text) as EBackgroundColors, activeClass);
61
+
62
+ const menuContainer = container ?? activeLink.closest("ul");
63
+ const allMenuLinks = menuContainer?.querySelectorAll(linkSelector) ?? [];
64
+ for (const menuLink of allMenuLinks) {
65
+ if (menuLink !== activeLink) SET_BUTTON_ACTIVE_CLASS(false, menuLink as HTMLElement, null, null, null, activeClass);
66
+ }
67
+ };
2
68
 
3
69
  export function RenderChildren<T>(parentContainer: HTMLElement, elementList: HTMLElement[], toggleButton: HTMLElement, activeItem: T | UN, visibleItems: T[], hiddenItems: T[], createItem: (item: T) => HTMLElement, refreshElementClass: (element: HTMLElement, activeItem: T | UN) => void, isInit: boolean, isHiddenItemClicked: boolean, dataUniqueKey: string, dataAttributeKey: string) {
4
70
  if (!isInit) {
package/src/interface.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./interfaces/auth-token-interfaces";
1
2
  export * from "./interfaces/browser-interfaces";
2
3
  export * from "./interfaces/button-interfaces";
3
4
  export * from "./interfaces/datasource-interfaces";
@@ -0,0 +1,6 @@
1
+ /** Token lifetimes from TBAuthentications.ClientApplications (seconds). */
2
+ export interface IClientTokenLifetimes {
3
+ accessTokenLifetimeSeconds: number;
4
+ refreshTokenLifetimeSeconds: number;
5
+ ssoSessionLifetimeSeconds: number;
6
+ }
@@ -1,3 +1,5 @@
1
+ export const DEFAULT_MOBILE_VIEW_WIDTH = 768;
2
+
1
3
  export enum EKeys {
2
4
  TAB = "Tab",
3
5
  DELETE = "Delete",
@@ -21,3 +23,14 @@ export enum EKeyModifier {
21
23
  Ctrl = 1 << 1, // 2
22
24
  Alt = 1 << 2, // 4
23
25
  }
26
+ export enum EFileSizes {
27
+ ORGINAL = 0,
28
+ SIZE_16 = 1,
29
+ SIZE_32 = 2,
30
+ SIZE_64 = 3,
31
+ SIZE_128 = 4,
32
+ SIZE_256 = 5,
33
+ SIZE_512 = 6,
34
+ SIZE_1024 = 7,
35
+ SIZE_2048 = 8,
36
+ }
@@ -77,9 +77,6 @@ export const GetResponse = {
77
77
  message: message,
78
78
  messageCode: messageCode,
79
79
  code: code,
80
- exceptionCategory: EExceptionCategories.Application,
81
- errorCode: EErrorCodes.Unknown,
82
- inputName: undefined,
83
80
  }),
84
81
  };
85
82
 
@@ -1,5 +1,8 @@
1
+ import { ESizes } from "./layout-interfaces";
2
+
1
3
  export const DEFAULT_ICON_ELEMENT_NAME = "ion-icon";
2
4
  export const DEFAULT_SMALL_ICON_BOX_SIZE = 1 / 1.25;
5
+ export const DEFAULT_ICON_SIZE = ESizes.VerySmall;
3
6
  export enum EIconTypes {
4
7
  OUTLINED = "-outline",
5
8
  SHARP = "-sharp",
@@ -1,4 +1,5 @@
1
1
  import { EIcons } from "./icon-interfaces";
2
+ import { UN } from "./type-interfaces";
2
3
 
3
4
  export const UTILITIES_BUTTON_PREFIX = "btn-utility-";
4
5
  export const GetUtilityMenuCode = (utilityCode: string) => `${UTILITIES_BUTTON_PREFIX}${utilityCode}`;
@@ -14,7 +15,7 @@ export enum EMenuVisibility {
14
15
  }
15
16
  export interface IMenuBase {
16
17
  id?: string | number;
17
- menuVisibilities: EMenuVisibility;
18
+ menuVisibilities: EMenuVisibility | UN;
18
19
  menuName: string;
19
20
  menuCode: string;
20
21
  menuIcon: EIcons;
@@ -34,3 +35,19 @@ export interface IClientMenu extends IMenuBase {
34
35
  pageTitle: string;
35
36
  breadcrumbTitle?: string;
36
37
  }
38
+ export interface IAdminMenu extends IClientMenu {
39
+ parentId?: string | number;
40
+ }
41
+ export const BUTTON_IDENTITY = (isneedPrefix: boolean) => {
42
+ const _ = isneedPrefix ? UTILITIES_BUTTON_PREFIX : "";
43
+ return {
44
+ PROFILE_BOX: `${_}profile`,
45
+ SEARCH_BOX: `${_}root-search`,
46
+ FAVORITE_BOX: `${_}favorite-menu`,
47
+ CARD_BOX: `${_}cart-menu`,
48
+ THEME_BOX: `${_}switch-theme`,
49
+ MEGA_BOX: `${_}mega-menu`,
50
+ SIGN_IN_BUTTON: `${_}sign-in`,
51
+ SIGN_OUT_BUTTON: `${_}sign-out`,
52
+ };
53
+ };
@@ -1,4 +1,5 @@
1
1
  export const LOCAL_STORAGE_KEYS = {
2
2
  ACTIVE_THEME: "nexus-themes",
3
+ CURRENT_USER: "nexus-current-user",
3
4
  FORM_BUTTON_POSITION: "nexus-form-button-position",
4
5
  };
@@ -1,4 +1,5 @@
1
1
  import { EIcons } from "./icon-interfaces";
2
+ import { UN } from "./type-interfaces";
2
3
 
3
4
  export const DEFAULT_THEME_NAME = "light";
4
5
 
@@ -43,25 +44,57 @@ export enum EBackgrounds {
43
44
  ThemeColor800 = "bg800",
44
45
  ThemeColor950 = "bg950",
45
46
  }
46
- /** Color divided into 4 parts: background, hover, focus, text */
47
- export interface IThemeColors {
48
- /* Background Color 1 */
47
+ export enum ETextColors {
48
+ TextColor1 = "var(--T1)",
49
+ TextColor2 = "var(--T2)",
50
+ TextColor3 = "var(--T3)",
51
+ TextColor10 = "var(--T10)",
52
+ TextColor11 = "var(--T11)",
53
+ TextColor12 = "var(--T12)",
54
+ TextColor13 = "var(--T13)",
55
+ TextColor20 = "var(--T20)",
56
+ TextColor30 = "var(--T30)",
57
+ TextColor41 = "var(--T41)",
58
+ TextColor51 = "var(--T51)",
59
+ TextColor52 = "var(--T52)",
60
+ TextColor100 = "var(--T100)",
61
+ TextColor200 = "var(--T200)",
62
+ TextColor400 = "var(--T400)",
63
+ TextColor600 = "var(--T600)",
64
+ TextColor800 = "var(--T800)",
65
+ TextColor950 = "var(--T950)",
66
+ }
67
+ export enum EColorTypes {
68
+ Background = "--B",
69
+ Hover = "--H",
70
+ Focus = "--F",
71
+ Text = "--T",
72
+ }
73
+
74
+ export interface IThemeInformation {
75
+ displayName: string;
76
+ systemName: string;
77
+ displayOrder: number;
78
+ iconName: EIcons;
79
+ id?: string | UN;
80
+
81
+ /** Background Color 1 */
49
82
  C1: string;
50
- /* Background Color 2 */
83
+ /** Background Color 2 */
51
84
  C2: string;
52
- /* Background Color 3 */
85
+ /** Background Color 3 */
53
86
  C3: string;
54
87
 
55
- /* Success Color */
88
+ /** Success Color */
56
89
  C10: string;
57
- /* Warning/Reset/Clear Color */
90
+ /** Warning/Reset/Clear Color */
58
91
  C11: string;
59
- /* Info Color */
92
+ /** Info Color */
60
93
  C12: string;
61
- /* Error/Delete/Remove Color */
94
+ /** Error/Delete/Remove Color */
62
95
  C13: string;
63
96
 
64
- /* Primary/Submit/Link Button Color */
97
+ /** Primary/Submit/Link Button Color */
65
98
  C20: string;
66
99
 
67
100
  /** Border Color 1 */
@@ -88,122 +121,3 @@ export interface IThemeColors {
88
121
  /** Theme Color 950 */
89
122
  C950: string;
90
123
  }
91
- export interface IThemeInformation {
92
- displayName: string;
93
- systemName: string;
94
- displayOrder: number;
95
- icon: EIcons;
96
- themeColors: IThemeColors;
97
- isSystemTheme: boolean;
98
- }
99
-
100
- export const DEFAULT_THEME_INFORMATIONS: IThemeInformation[] = [
101
- {
102
- displayName: "Light",
103
- systemName: DEFAULT_THEME_NAME,
104
- displayOrder: 0,
105
- icon: EIcons.SUNNY,
106
- themeColors: {
107
- C1: "rgb(255, 255, 255)|rgb(240, 240, 240)|rgb(225, 225, 225)|rgb(0, 0, 0)",
108
- C2: "rgb(245, 245, 245)|rgb(230, 230, 230)|rgb(215, 215, 215)|rgb(0, 0, 0)",
109
- C3: "rgb(230, 230, 230)|rgb(200, 200, 200)|rgb(185, 185, 185)|rgb(0, 0, 0)",
110
- C10: "rgb(34, 187, 51)|rgb(0, 150, 80)|rgb(20, 120, 40)|rgb(255, 255, 255)",
111
- C11: "rgb(240, 173, 78)|rgb(210, 140, 50)|rgb(180, 110, 20)|rgb(255, 255, 255)",
112
- C12: "rgb(76, 185, 255)|rgb(100, 180, 255)|rgb(80, 160, 220)|rgb(255, 255, 255)",
113
- C13: "rgb(255, 102, 102)|rgb(220, 80, 80)|rgb(190, 60, 60)|rgb(255, 255, 255)",
114
- C20: "rgb(47, 81, 255)|rgb(30, 60, 220)|rgb(20, 40, 180)|rgb(255, 255, 255)",
115
- C30: "rgb(200, 200, 200)|rgb(180, 180, 180)|rgb(160, 160, 160)|rgb(0, 0, 0)",
116
- C41: "rgba(0, 0, 0, 0.4)|rgb(150, 150, 150)|rgb(120, 120, 120)|rgb(0, 0, 0)",
117
- C51: "rgba(0, 0, 0, 0.6)|rgb(0, 0, 0, 0.8)|rgb(0, 0, 0, 0.9)|rgb(255, 255, 255)",
118
- C52: "rgb(60, 60, 60)|rgb(85, 85, 85)|rgb(35, 35, 35)|rgb(255, 255, 255)",
119
- C100: "rgb(213, 228, 255)|rgb(200, 210, 255)|rgb(185, 200, 220)|rgb(0, 0, 0)",
120
- C200: "rgb(179, 205, 255)|rgb(160, 180, 255)|rgb(140, 160, 220)|rgb(0, 0, 0)",
121
- C400: "rgb(86, 126, 255)|rgb(60, 90, 220)|rgb(40, 60, 180)|rgb(255, 255, 255)",
122
- C600: "rgb(12, 33, 255)|rgb(10, 20, 220)|rgb(8, 15, 180)|rgb(255, 255, 255)",
123
- C800: "rgb(6, 22, 205)|rgb(4, 15, 180)|rgb(2, 10, 120)|rgb(255, 255, 255)",
124
- C950: "rgb(10, 17, 92)|rgb(8, 12, 70)|rgb(6, 9, 40)|rgb(255, 255, 255)",
125
- },
126
- isSystemTheme: true,
127
- },
128
- {
129
- displayName: "Dark",
130
- displayOrder: 1,
131
- icon: EIcons.MOON,
132
- systemName: "dark",
133
- themeColors: {
134
- C1: "rgb(50, 50, 50)|rgb(40, 40, 40)|rgb(30, 30, 30)|rgb(220, 220, 220)",
135
- C2: "rgb(65, 65, 65)|rgb(55, 55, 55)|rgb(45, 45, 45)|rgb(220, 220, 220)",
136
- C3: "rgb(70, 70, 70)|rgb(60, 60, 60)|rgb(50, 50, 50)|rgb(220, 220, 220)",
137
- C10: "rgb(34, 187, 51)|rgb(0, 150, 80)|rgb(20, 120, 40)|rgb(255, 255, 255)",
138
- C11: "rgb(240, 173, 78)|rgb(210, 140, 50)|rgb(180, 110, 20)|rgb(255, 255, 255)",
139
- C12: "rgb(76, 185, 255)|rgb(100, 180, 255)|rgb(80, 160, 220)|rgb(255, 255, 255)",
140
- C13: "rgb(255, 102, 102)|rgb(220, 80, 80)|rgb(190, 60, 60)|rgb(255, 255, 255)",
141
- C20: "rgb(47, 81, 255)|rgb(30, 60, 220)|rgb(20, 40, 180)|rgb(255, 255, 255)",
142
- C30: "rgb(100, 100, 100)|rgb(90, 90, 90)|rgb(80, 80, 80)|rgb(220, 220, 220)",
143
- C41: "rgb(100, 100, 100)|rgb(255, 255, 255)|rgb(120, 120, 120)|rgb(0, 0, 0)",
144
- C51: "rgba(0, 0, 0, 0.6)|rgb(0, 0, 0, 0.8)|rgb(0, 0, 0, 0.9)|rgb(255, 255, 255)",
145
- C52: "rgb(60, 60, 60)|rgb(85, 85, 85)|rgb(35, 35, 35)|rgb(255, 255, 255)",
146
- C100: "rgb(213, 228, 255)|rgb(200, 210, 255)|rgb(185, 200, 220)|rgb(0, 0, 0)",
147
- C200: "rgb(179, 205, 255)|rgb(160, 180, 255)|rgb(140, 160, 220)|rgb(0, 0, 0)",
148
- C400: "rgb(86, 126, 255)|rgb(60, 90, 220)|rgb(40, 60, 180)|rgb(255, 255, 255)",
149
- C600: "rgb(12, 33, 255)|rgb(10, 20, 220)|rgb(8, 15, 180)|rgb(255, 255, 255)",
150
- C800: "rgb(6, 22, 205)|rgb(4, 15, 180)|rgb(2, 10, 120)|rgb(255, 255, 255)",
151
- C950: "rgb(10, 17, 92)|rgb(8, 12, 70)|rgb(6, 9, 40)|rgb(255, 255, 255)",
152
- },
153
- isSystemTheme: true,
154
- },
155
- {
156
- displayName: "Light2",
157
- systemName: "light2",
158
- displayOrder: 0,
159
- icon: EIcons.SUNNY,
160
- themeColors: {
161
- C1: "rgb(255, 255, 255)|rgb(240, 240, 240)|rgb(225, 225, 225)|rgb(0, 0, 0)",
162
- C2: "rgb(245, 245, 245)|rgb(230, 230, 230)|rgb(215, 215, 215)|rgb(0, 0, 0)",
163
- C3: "rgb(230, 230, 230)|rgb(200, 200, 200)|rgb(185, 185, 185)|rgb(0, 0, 0)",
164
- C10: "rgb(34, 187, 51)|rgb(0, 150, 80)|rgb(20, 120, 40)|rgb(255, 255, 255)",
165
- C11: "rgb(240, 173, 78)|rgb(210, 140, 50)|rgb(180, 110, 20)|rgb(255, 255, 255)",
166
- C12: "rgb(76, 185, 255)|rgb(100, 180, 255)|rgb(80, 160, 220)|rgb(255, 255, 255)",
167
- C13: "rgb(255, 102, 102)|rgb(220, 80, 80)|rgb(190, 60, 60)|rgb(255, 255, 255)",
168
- C20: "rgb(47, 81, 255)|rgb(30, 60, 220)|rgb(20, 40, 180)|rgb(255, 255, 255)",
169
- C30: "rgb(200, 200, 200)|rgb(180, 180, 180)|rgb(160, 160, 160)|rgb(0, 0, 0)",
170
- C41: "rgba(0, 0, 0, 0.4)|rgb(150, 150, 150)|rgb(120, 120, 120)|rgb(0, 0, 0)",
171
- C51: "rgba(0, 0, 0, 0.6)|rgb(0, 0, 0, 0.8)|rgb(0, 0, 0, 0.9)|rgb(255, 255, 255)",
172
- C52: "rgb(60, 60, 60)|rgb(85, 85, 85)|rgb(35, 35, 35)|rgb(255, 255, 255)",
173
- C100: "rgb(213, 228, 255)|rgb(200, 210, 255)|rgb(185, 200, 220)|rgb(0, 0, 0)",
174
- C200: "rgb(179, 205, 255)|rgb(160, 180, 255)|rgb(140, 160, 220)|rgb(0, 0, 0)",
175
- C400: "rgb(86, 126, 255)|rgb(60, 90, 220)|rgb(40, 60, 180)|rgb(255, 255, 255)",
176
- C600: "rgb(12, 33, 255)|rgb(10, 20, 220)|rgb(8, 15, 180)|rgb(255, 255, 255)",
177
- C800: "rgb(6, 22, 205)|rgb(4, 15, 180)|rgb(2, 10, 120)|rgb(255, 255, 255)",
178
- C950: "rgb(10, 17, 92)|rgb(8, 12, 70)|rgb(6, 9, 40)|rgb(255, 255, 255)",
179
- },
180
- isSystemTheme: true,
181
- },
182
- {
183
- displayName: "Dark2",
184
- displayOrder: 1,
185
- icon: EIcons.MOON,
186
- systemName: "dark2",
187
- themeColors: {
188
- C1: "rgb(50, 50, 50)|rgb(40, 40, 40)|rgb(30, 30, 30)|rgb(220, 220, 220)",
189
- C2: "rgb(65, 65, 65)|rgb(55, 55, 55)|rgb(45, 45, 45)|rgb(220, 220, 220)",
190
- C3: "rgb(70, 70, 70)|rgb(60, 60, 60)|rgb(50, 50, 50)|rgb(220, 220, 220)",
191
- C10: "rgb(34, 187, 51)|rgb(0, 150, 80)|rgb(20, 120, 40)|rgb(255, 255, 255)",
192
- C11: "rgb(240, 173, 78)|rgb(210, 140, 50)|rgb(180, 110, 20)|rgb(255, 255, 255)",
193
- C12: "rgb(76, 185, 255)|rgb(100, 180, 255)|rgb(80, 160, 220)|rgb(255, 255, 255)",
194
- C13: "rgb(255, 102, 102)|rgb(220, 80, 80)|rgb(190, 60, 60)|rgb(255, 255, 255)",
195
- C20: "rgb(47, 81, 255)|rgb(30, 60, 220)|rgb(20, 40, 180)|rgb(255, 255, 255)",
196
- C30: "rgb(100, 100, 100)|rgb(90, 90, 90)|rgb(80, 80, 80)|rgb(220, 220, 220)",
197
- C41: "rgb(100, 100, 100)|rgb(255, 255, 255)|rgb(120, 120, 120)|rgb(0, 0, 0)",
198
- C51: "rgba(0, 0, 0, 0.6)|rgb(0, 0, 0, 0.8)|rgb(0, 0, 0, 0.9)|rgb(255, 255, 255)",
199
- C52: "rgb(60, 60, 60)|rgb(85, 85, 85)|rgb(35, 35, 35)|rgb(255, 255, 255)",
200
- C100: "rgb(213, 228, 255)|rgb(200, 210, 255)|rgb(185, 200, 220)|rgb(0, 0, 0)",
201
- C200: "rgb(179, 205, 255)|rgb(160, 180, 255)|rgb(140, 160, 220)|rgb(0, 0, 0)",
202
- C400: "rgb(86, 126, 255)|rgb(60, 90, 220)|rgb(40, 60, 180)|rgb(255, 255, 255)",
203
- C600: "rgb(12, 33, 255)|rgb(10, 20, 220)|rgb(8, 15, 180)|rgb(255, 255, 255)",
204
- C800: "rgb(6, 22, 205)|rgb(4, 15, 180)|rgb(2, 10, 120)|rgb(255, 255, 255)",
205
- C950: "rgb(10, 17, 92)|rgb(8, 12, 70)|rgb(6, 9, 40)|rgb(255, 255, 255)",
206
- },
207
- isSystemTheme: true,
208
- },
209
- ];