Skip to content

Commit bb0f5aa

Browse files
committed
refactored Nav avoiding repetition, routes defined in NavConfig
1 parent c21fd98 commit bb0f5aa

File tree

3 files changed

+155
-175
lines changed

3 files changed

+155
-175
lines changed

components/NavButton.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React from "react";
2+
import { Button, Body1, tokens } from "@fluentui/react-components";
3+
import { DividerTallFilled } from "@fluentui/react-icons";
4+
import { useRouter, usePathname } from "next/navigation";
5+
6+
interface NavButtonProps {
7+
label: string;
8+
route: string;
9+
showActiveIcon?: boolean;
10+
icon?: React.ReactNode;
11+
}
12+
13+
const activeStyle = {
14+
backgroundColor: tokens.colorNeutralBackground2,
15+
color: tokens.colorNeutralForeground2BrandSelected,
16+
};
17+
18+
export function NavButton({
19+
label,
20+
route,
21+
icon,
22+
showActiveIcon = false,
23+
}: NavButtonProps) {
24+
const router = useRouter();
25+
const pathname = usePathname();
26+
27+
const isActive = pathname === route;
28+
29+
return (
30+
<Button
31+
shape="square"
32+
appearance="subtle"
33+
icon={
34+
isActive && showActiveIcon ? (
35+
<DividerTallFilled style={{ transform: "scaleX(2)" }} />
36+
) : undefined
37+
}
38+
onClick={() => router.push(route)}
39+
style={{
40+
width: "100%",
41+
justifyContent: "flex-start",
42+
display: "flex",
43+
...(isActive ? activeStyle : {}),
44+
}}
45+
>
46+
{icon}
47+
<Body1 style={{ marginLeft: icon ? 8 : 0 }}>{label}</Body1>
48+
</Button>
49+
);
50+
}

components/NavConfig.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
2+
import { HomeRegular } from "@fluentui/react-icons";
3+
import IconAppRegistrations from "./styling/icons/IconAppRegistrations";
4+
import IconEnterpriseApps from "./styling/icons/IconEnterpriseApps";
5+
6+
interface NavItem {
7+
label: string;
8+
route: string;
9+
icon?: React.ReactNode; // Icon for the header or button
10+
showActiveIcon?: boolean; // Whether to show the active divider icon
11+
children?: NavItem[]; // Sub-items if this item has an accordion
12+
}
13+
14+
export const navConfig: NavItem[] = [
15+
{
16+
label: "Home",
17+
route: "/",
18+
icon: <HomeRegular />,
19+
showActiveIcon: false,
20+
},
21+
{
22+
label: "App Registrations",
23+
route: "/app-registrations",
24+
icon: <IconAppRegistrations />,
25+
showActiveIcon: false,
26+
children: [
27+
{
28+
label: "Analytics",
29+
route: "/app-registrations/analytics",
30+
showActiveIcon: true,
31+
},
32+
{
33+
label: "Certificates & secrets",
34+
route: "/app-registrations/certificates-and-secrets",
35+
showActiveIcon: true,
36+
},
37+
],
38+
},
39+
{
40+
label: "Enterprise Applications",
41+
route: "/enterprise-applications",
42+
icon: <IconEnterpriseApps />,
43+
showActiveIcon: false,
44+
children: [
45+
{
46+
label: "App role permissions",
47+
route: "/enterprise-applications/app-role-permissions",
48+
showActiveIcon: true,
49+
},
50+
{
51+
label: "SAML certificate status",
52+
route: "/enterprise-applications/saml-certificate-expiry-status",
53+
showActiveIcon: true,
54+
},
55+
],
56+
},
57+
];

components/NavMenu.tsx

Lines changed: 48 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -1,190 +1,63 @@
11
import {
2+
Toolbar,
3+
ToolbarGroup,
24
Accordion,
3-
AccordionHeader,
45
AccordionItem,
6+
AccordionHeader,
57
AccordionPanel,
6-
Body1,
7-
Body1Strong,
8-
Button,
98
Divider,
10-
tokens,
11-
Toolbar,
12-
ToolbarGroup,
9+
Body1Strong,
1310
} from "@fluentui/react-components";
14-
import { DividerTallFilled, HomeRegular } from "@fluentui/react-icons";
15-
import { usePathname, useRouter } from "next/navigation";
16-
import IconAppRegistrations from "./styling/icons/IconAppRegistrations";
17-
import IconEnterpriseApps from "./styling/icons/IconEnterpriseApps";
18-
19-
export default function NavMenu() {
20-
const router = useRouter();
21-
22-
const pathname = usePathname(); // Get the current route
2311

24-
const activeStyle = {
25-
backgroundColor: tokens.colorNeutralBackground2,
26-
color: tokens.colorNeutralForeground2BrandSelected,
27-
};
12+
import { NavButton } from "./NavButton";
13+
import { navConfig } from "./NavConfig";
2814

15+
export default function NavMenu() {
2916
return (
30-
<Toolbar aria-label="with Separeted Groups">
17+
<Toolbar aria-label="Navigation Menu">
3118
<ToolbarGroup role="presentation" style={{ width: "100%" }}>
32-
<Button
33-
onClick={() => {
34-
router.push("/");
35-
}}
36-
shape="square"
37-
appearance="subtle"
38-
icon={<HomeRegular />}
39-
style={{
40-
width: "100%",
41-
justifyContent: "flex-start", // This aligns the button content to the left
42-
display: "flex", // Ensures flexbox layout for content alignment,
43-
...(pathname === "/" ? activeStyle : {}),
44-
}}
45-
>
46-
<Body1Strong> Home</Body1Strong>
47-
</Button>
48-
<Divider />
19+
{navConfig.map((item, index) => {
20+
if (item.children && item.children.length > 0) {
21+
return (
22+
<Accordion key={index} defaultOpenItems="1">
23+
<AccordionItem value="1">
24+
<AccordionHeader
25+
icon={{
26+
as: "div",
27+
children: item.icon,
28+
}}
29+
expandIconPosition="end"
30+
>
31+
<Body1Strong>{item.label}</Body1Strong>
32+
</AccordionHeader>
33+
<AccordionPanel>
34+
{item.children.map((child, childIndex) => (
35+
<NavButton
36+
key={childIndex}
37+
label={child.label}
38+
route={child.route}
39+
showActiveIcon={child.showActiveIcon}
40+
/>
41+
))}
42+
</AccordionPanel>
43+
</AccordionItem>
44+
</Accordion>
45+
);
46+
}
4947

50-
{/* <AuthenticatedTemplate> */}
51-
<Accordion defaultOpenItems="1">
52-
<AccordionItem value="1">
53-
<AccordionHeader
54-
icon={<IconAppRegistrations />}
55-
expandIconPosition="end"
56-
>
57-
<Body1Strong>App Registrations</Body1Strong>
58-
</AccordionHeader>
59-
<AccordionPanel>
60-
<Button
61-
icon={
62-
pathname === "/app-registrations/analytics" ? (
63-
<DividerTallFilled
64-
style={{
65-
transform: "scaleX(2)",
66-
}}
67-
/>
68-
) : undefined
69-
}
70-
onClick={() =>
71-
router.push("/app-registrations/analytics")
72-
}
73-
shape="square"
74-
appearance="subtle"
75-
style={{
76-
width: "100%",
77-
justifyContent: "flex-start",
78-
display: "flex",
79-
...(pathname === "/app-registrations/analytics"
80-
? activeStyle
81-
: {}),
82-
}}
83-
>
84-
<Body1>Analytics</Body1>
85-
</Button>
86-
<Button
87-
icon={
88-
pathname === "/app-registrations/certificates-and-secrets" ? (
89-
<DividerTallFilled
90-
style={{
91-
transform: "scaleX(2)",
92-
}}
93-
/>
94-
) : undefined
95-
}
96-
onClick={() =>
97-
router.push("/app-registrations/certificates-and-secrets")
98-
}
99-
shape="square"
100-
appearance="subtle"
101-
style={{
102-
width: "100%",
103-
justifyContent: "flex-start",
104-
display: "flex",
105-
...(pathname === "/app-registrations/certificates-and-secrets"
106-
? activeStyle
107-
: {}),
108-
}}
109-
>
110-
<Body1>Certificates & secrets</Body1>
111-
</Button>
112-
</AccordionPanel>
113-
</AccordionItem>
114-
</Accordion>
115-
{/* </AuthenticatedTemplate> */}
116-
<Accordion defaultOpenItems="1">
117-
<AccordionItem value="1">
118-
<AccordionHeader
119-
icon={<IconEnterpriseApps />}
120-
expandIconPosition="end"
121-
>
122-
<Body1Strong>Enterprise Applications</Body1Strong>
123-
</AccordionHeader>
124-
<AccordionPanel>
125-
<Button
126-
icon={
127-
pathname ===
128-
"/enterprise-applications/app-role-permissions" ? (
129-
<DividerTallFilled
130-
style={{
131-
transform: "scaleX(2)",
132-
}}
133-
/>
134-
) : undefined
135-
}
136-
onClick={() =>
137-
router.push("/enterprise-applications/app-role-permissions")
138-
}
139-
shape="square"
140-
appearance="subtle"
141-
style={{
142-
width: "100%",
143-
justifyContent: "flex-start",
144-
display: "flex",
145-
...(pathname ===
146-
"/enterprise-applications/app-role-permissions"
147-
? activeStyle
148-
: {}),
149-
}}
150-
>
151-
<Body1>App role permissions</Body1>
152-
</Button>
153-
<Button
154-
icon={
155-
pathname ===
156-
"/enterprise-applications/saml-certificate-expiry-status" ? (
157-
<DividerTallFilled
158-
style={{
159-
transform: "scaleX(2)",
160-
}}
161-
/>
162-
) : undefined
163-
}
164-
onClick={() =>
165-
router.push(
166-
"/enterprise-applications/saml-certificate-expiry-status"
167-
)
168-
}
169-
shape="square"
170-
appearance="subtle"
171-
style={{
172-
width: "100%",
173-
justifyContent: "flex-start",
174-
display: "flex",
175-
...(pathname ===
176-
"/enterprise-applications/saml-certificate-expiry-status"
177-
? activeStyle
178-
: {}),
179-
}}
180-
>
181-
<Body1>SAML certificate status</Body1>
182-
</Button>
183-
</AccordionPanel>
184-
</AccordionItem>
185-
</Accordion>
48+
return (
49+
<div key={index}>
50+
<NavButton
51+
label={item.label}
52+
route={item.route}
53+
icon={item.icon}
54+
showActiveIcon={item.showActiveIcon}
55+
/>
56+
{index < navConfig.length - 1 && <Divider />}
57+
</div>
58+
);
59+
})}
18660
</ToolbarGroup>
187-
<ToolbarGroup role="presentation"></ToolbarGroup>
18861
</Toolbar>
18962
);
19063
}

0 commit comments

Comments
 (0)