Skip to content

Commit 6e88c8e

Browse files
authored
Merge pull request #825 from rintumerin-aot/feature/FWF-5271-ui-sidebar-updations
FWF-5346[feature] - Navbar changes for v8
2 parents 8c8da26 + cee3b6e commit 6e88c8e

File tree

7 files changed

+424
-208
lines changed

7 files changed

+424
-208
lines changed

forms-flow-components/src/components/SvgIcons/index.tsx

Lines changed: 190 additions & 90 deletions
Large diffs are not rendered by default.

forms-flow-nav/src/sidenav/MenuComponent.jsx

Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from "react";
22
import Accordion from "react-bootstrap/Accordion";
33
import "./Sidebar.scss";
44
import { Link, useLocation, useHistory } from "react-router-dom";
5-
import { ChevronIcon ,ShowPremiumIcons, NavbarTaskIcon, NavbarSubmitIcon } from "@formsflow/components";
5+
import { ChevronIcon ,ShowPremiumIcons, NavbarTaskIcon, NavbarSubmitIcon, NavbarBuildIcon, NavbarAnalyzeIcon, NavbarManageIcon } from "@formsflow/components";
66
import { useTranslation } from "react-i18next";
77
import { StorageService } from "@formsflow/service";
88
import PropTypes from "prop-types";
@@ -14,6 +14,7 @@ const MenuComponent = ({
1414
optionsCount,
1515
subscribe,
1616
baseUrl,
17+
collapsed
1718
}) => {
1819
const [tenant, setTenant] = React.useState({});
1920
const [activeMenu, setActiveMenu] = React.useState(null);
@@ -79,49 +80,70 @@ const MenuComponent = ({
7980
: getComputedStyle(document.documentElement).getPropertyValue("--ff-primary");
8081
};
8182

82-
const chevronColor =
83-
getComputedStyle(document.documentElement).getPropertyValue(
84-
"--navbar-main-menu-active-font-color"
85-
)?.trim();
86-
87-
const defaultStroke =
88-
getComputedStyle(document.documentElement).getPropertyValue(
89-
"--navbar-bg-color"
90-
)?.trim();
91-
9283
const renderMenuIcon = () => {
9384
const lowerMainMenu = mainMenu.toLowerCase();
9485
let iconFillColor, strokeColor;
95-
9686
if (isMainMenuActive()) {
9787
iconFillColor = getComputedStyle(document.documentElement)
98-
.getPropertyValue("--navbar-active-submenu-font-color")?.trim();
88+
.getPropertyValue("--navbar-menu-font-color")?.trim();
9989

10090
strokeColor = getComputedStyle(document.documentElement)
101-
.getPropertyValue("--navbar-active-submenu-bg-color")?.trim();
91+
.getPropertyValue("--navbar-menu-font-color")?.trim();
10292
} else {
103-
iconFillColor = chevronColor;
104-
strokeColor = defaultStroke;
93+
iconFillColor = getComputedStyle(document.documentElement)
94+
.getPropertyValue("--navbar-submenu-font-color")?.trim();
95+
96+
strokeColor = getComputedStyle(document.documentElement)
97+
.getPropertyValue("--navbar-submenu-font-color")?.trim();
10598
}
106-
switch (lowerMainMenu) {
107-
case "tasks":
108-
return <NavbarTaskIcon fillColor={iconFillColor} strokeColor={strokeColor}/>;
10999

110-
case "submit":
100+
if(collapsed){
101+
switch (lowerMainMenu) {
102+
case "tasks":
103+
return <NavbarTaskIcon fillColor={iconFillColor} strokeColor={strokeColor}/>;
104+
105+
case "submit":
111106
return <NavbarSubmitIcon fillColor={iconFillColor} strokeColor={strokeColor}/>;
112-
113-
default:
114-
if (!noOptionsMenu) {
115-
return (
116-
<ChevronIcon
117-
// width="10"
118-
// height="5"
119-
className="svgIcon-dark custom-chevron"
120-
color={iconFillColor}
121-
/>
122-
);
123-
}
124-
return null;
107+
108+
case "build":
109+
return <NavbarBuildIcon fillColor={iconFillColor} strokeColor={strokeColor}/>;
110+
111+
case "analyze":
112+
return <NavbarAnalyzeIcon fillColor={iconFillColor} strokeColor={strokeColor}/>;
113+
114+
case "manage":
115+
return <NavbarManageIcon fillColor={iconFillColor} strokeColor={strokeColor}/>;
116+
117+
default:
118+
if (!noOptionsMenu) {
119+
return (
120+
<ChevronIcon
121+
className="custom-chevron"
122+
color={iconFillColor}
123+
/>
124+
);
125+
}
126+
return null;
127+
}
128+
}else{
129+
switch (lowerMainMenu) {
130+
case "tasks":
131+
return <NavbarTaskIcon fillColor={iconFillColor} strokeColor={strokeColor}/>;
132+
133+
case "submit":
134+
return <NavbarSubmitIcon fillColor={iconFillColor} strokeColor={strokeColor}/>;
135+
136+
default:
137+
if (!noOptionsMenu) {
138+
return (
139+
<ChevronIcon
140+
className="custom-chevron"
141+
color={iconFillColor}
142+
/>
143+
);
144+
}
145+
return null;
146+
}
125147
}
126148
};
127149

@@ -137,10 +159,10 @@ const renderMenuIcon = () => {
137159
onClick={noOptionsMenu ? handleHeaderClick : undefined}
138160
>
139161
{renderMenuIcon()}
140-
<span>{t(mainMenu)}</span>
162+
<span hidden ={collapsed}>{t(mainMenu)}</span>
141163
</Accordion.Header>
142164
{!noOptionsMenu && (
143-
<Accordion.Body>
165+
<Accordion.Body hidden={collapsed}>
144166
{subMenu?.map((menu, index) => (
145167
<Link
146168
key={index}
@@ -177,6 +199,7 @@ MenuComponent.propTypes = {
177199
optionsCount: PropTypes.string.isRequired,
178200
subscribe: PropTypes.func.isRequired,
179201
baseUrl: PropTypes.string.isRequired,
202+
collapsed:PropTypes.string.isRequired
180203
};
181204

182205
export default MenuComponent;

forms-flow-nav/src/sidenav/Sidebar.jsx

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import "./Sidebar.scss";
22
import Accordion from "react-bootstrap/Accordion";
3-
import React, { useEffect, useMemo, useState } from "react";
4-
import { useHistory ,useLocation } from "react-router-dom";
3+
import React, { useEffect, useMemo, useState, useRef } from "react";
4+
import { useHistory, useLocation } from "react-router-dom";
55
import { useTranslation } from "react-i18next";
66
import {
77
APPLICATION_NAME,
@@ -23,30 +23,32 @@ import { LANGUAGE } from "../constants/constants";
2323
import { checkIntegrationEnabled } from "../services/integration";
2424
import MenuComponent from "./MenuComponent";
2525
// import Appname from "./formsflow.svg";
26-
import { ApplicationLogo } from "@formsflow/components";
26+
import { ApplicationLogo, LogoutIcon } from "@formsflow/components";
2727
import { ProfileSettingsModal } from "./ProfileSettingsModal";
2828
import PropTypes from 'prop-types';
2929

30-
const UserProfile = ({ userDetail, initials, handleProfileModal, logout, t }) => (
31-
<div className="user-container">
30+
const UserProfile = ({ userDetail, initials, handleProfileModal, logout, t, collapsed }) => (
31+
<div className={`user-container${collapsed ? " collapsed" : ""}`}>
3232
<button onClick={handleProfileModal}>
3333
<div className="user-icon cursor-pointer" data-testid="user-icon">
3434
{initials}
3535
</div>
36-
<div className="user-info">
37-
<div>
38-
<p className="user-name" data-testid="user-name">{userDetail?.name}</p>
39-
</div>
40-
41-
<div>
36+
{!collapsed && (
37+
<div className="user-info">
38+
<div>
39+
<p className="user-name" data-testid="user-name">{userDetail?.name}sss</p>
40+
</div>
41+
{/* <div>
4242
<p className="user-email" data-testid="user-email">
4343
{userDetail?.email || userDetail?.preferred_username}
4444
</p>
45+
</div> */}
4546
</div>
46-
</div>
47+
)}
4748
</button>
4849
<button className="sign-out-button" onClick={logout} data-testid="sign-out-button">
49-
<p className="m-0">{t("Logout")}</p>
50+
<LogoutIcon />
51+
{!collapsed && <p className="m-0">{t("Logout")}</p>}
5052
</button>
5153
</div>
5254
);
@@ -61,14 +63,16 @@ UserProfile.propTypes = {
6163
initials: PropTypes.string.isRequired,
6264
handleProfileModal: PropTypes.func.isRequired,
6365
logout: PropTypes.func.isRequired,
64-
t: PropTypes.func.isRequired,
66+
t: PropTypes.func.isRequired,
67+
collapsed: PropTypes.bool
6568
};
6669

67-
const renderLogo = (hideLogo) => {
70+
const renderLogo = (hideLogo, collapsed) => {
71+
6872
if (hideLogo === "true") return null;
69-
73+
7074
return (
71-
<div className="logo-container">
75+
<div className={`logo-container${collapsed ? " collapsed" : ""}`}>
7276
<ApplicationLogo data-testid="application-logo" />
7377
</div>
7478
);
@@ -132,8 +136,16 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
132136

133137
const isAuthenticated = instance?.isAuthenticated();
134138
const showApplications = setShowApplications(userDetail?.groups);
135-
const [activeKey,setActiveKey] = useState(0);
136-
const hideLogo = StyleServices?.getCSSVariable("--hide-formsflow-logo")?.toLowerCase();
139+
const [activeKey, setActiveKey] = useState(0);
140+
const hideLogo = StyleServices?.getCSSVariable("--hide-formsflow-logo")?.toLowerCase();
141+
142+
// Collapsible sidebar state
143+
const [collapsed, setCollapsed] = useState(true);
144+
const sidebarRef = useRef(null);
145+
146+
// Expand on hover handlers
147+
const handleMouseEnter = () => setCollapsed(false);
148+
const handleMouseLeave = () => setCollapsed(true);
137149

138150
const getInitials = (name) => {
139151
if (!name) return "";
@@ -226,8 +238,8 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
226238

227239

228240
const SectionKeys = {
229-
DESIGN: {
230-
value: "design",
241+
BUILD: {
242+
value: "build",
231243
supportedRoutes: ["formflow", "bundleflow", "subflow", "decision-table","integration/recipes","integration/connected-apps","integration/library"],
232244
},
233245
SUBMIT: {
@@ -250,7 +262,7 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
250262

251263
useEffect((()=>{
252264
const sections = [
253-
{ key: SectionKeys.DESIGN.value, supportedRoutes: SectionKeys.DESIGN.supportedRoutes },
265+
{ key: SectionKeys.BUILD.value, supportedRoutes: SectionKeys.BUILD.supportedRoutes },
254266
{ key: SectionKeys.SUBMIT.value, supportedRoutes: SectionKeys.SUBMIT.supportedRoutes },
255267
{ key: SectionKeys.TASK.value, supportedRoutes: SectionKeys.TASK.supportedRoutes },
256268
{ key: SectionKeys.ANALYZE.value, supportedRoutes: SectionKeys.ANALYZE.supportedRoutes },
@@ -336,14 +348,28 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
336348
return options;
337349
}
338350

351+
// Collapsible sidebar class
352+
const sidebarClass = `sidenav${collapsed ? " collapsed" : ""}`;
353+
354+
useEffect(() => {
355+
document.documentElement.style.setProperty(
356+
"--navbar-width",
357+
collapsed ? "3rem" : "10rem"
358+
);
359+
}, [collapsed]);
360+
339361
return (
340362
<div
341-
className="sidenav"
363+
className={sidebarClass}
342364
style={{ height: sidenavHeight }}
343365
data-testid="sidenav"
366+
ref={sidebarRef}
367+
onMouseEnter={handleMouseEnter}
368+
onMouseLeave={handleMouseLeave}
369+
role="button"
344370
>
345-
{renderLogo(hideLogo)}
346-
<div className="options-container" data-testid="options-container">
371+
{renderLogo(hideLogo, collapsed)}
372+
<div className={`options-container${collapsed ? " collapsed" : ""}`} data-testid="options-container">
347373
<Accordion activeKey={activeKey} onSelect={(key) => setActiveKey(key)}>
348374
{(isViewTask || isManageTask) && ENABLE_TASKS_MODULE && (
349375
<MenuComponent
@@ -358,6 +384,7 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
358384
},
359385
]}
360386
subscribe={props.subscribe}
387+
collapsed={collapsed}
361388
/>
362389
)}
363390

@@ -384,16 +411,17 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
384411
},
385412
]}
386413
subscribe={props.subscribe}
414+
collapsed={collapsed}
387415
/>
388416
)}
389417

390418
{ENABLE_FORMS_MODULE &&
391419
(isCreateDesigns || isViewDesigns || isManageIntegrations) && (
392420
<MenuComponent
393421
baseUrl={baseUrl}
394-
eventKey={SectionKeys.DESIGN.value}
422+
eventKey={SectionKeys.BUILD.value}
395423
optionsCount="5"
396-
mainMenu={t("Design")}
424+
mainMenu={t("Build")}
397425
subMenu={
398426
// If only isManageIntegrations is true → show only Integrations
399427
isManageIntegrations && !isCreateDesigns && !isViewDesigns
@@ -411,7 +439,7 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
411439
]
412440
: [
413441
{
414-
name: "Forms & Flows",
442+
name: "Forms",
415443
path: "formflow",
416444
},
417445
...(IS_ENTERPRISE && isManageBundles
@@ -465,6 +493,7 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
465493
]
466494
}
467495
subscribe={props.subscribe}
496+
collapsed={collapsed}
468497
/>
469498
)}
470499

@@ -474,9 +503,9 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
474503
ENABLE_PROCESSES_MODULE && (
475504
<MenuComponent
476505
baseUrl={baseUrl}
477-
eventKey={SectionKeys.DESIGN.value}
506+
eventKey={SectionKeys.BUILD.value}
478507
optionsCount="2"
479-
mainMenu="Design"
508+
mainMenu="Build"
480509
subMenu={[
481510
{
482511
name: "Subflows",
@@ -488,6 +517,7 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
488517
},
489518
]}
490519
subscribe={props.subscribe}
520+
collapsed={collapsed}
491521
/>
492522
)}
493523
{isAnalyzeManager && ENABLE_DASHBOARDS_MODULE && (
@@ -498,6 +528,7 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
498528
mainMenu="Analyze"
499529
subMenu={manageAnalyseOptions()}
500530
subscribe={props.subscribe}
531+
collapsed={collapsed}
501532
/>
502533
)}
503534
{isAdmin && (
@@ -508,6 +539,7 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
508539
mainMenu="Manage"
509540
subMenu={manageOptions()}
510541
subscribe={props.subscribe}
542+
collapsed={collapsed}
511543
/>
512544
)}
513545
</Accordion>
@@ -519,6 +551,7 @@ const Sidebar = React.memo(({ props, sidenavHeight="100%" }) => {
519551
handleProfileModal={handleProfileModal}
520552
logout={logout}
521553
t={t}
554+
collapsed={collapsed}
522555
/>
523556
)}
524557
{showProfile && (

0 commit comments

Comments
 (0)