Skip to content

Commit c5b9232

Browse files
authored
Merge pull request #3754 from IntersectMBO/3682-adjust-top-menu-layout-when-wallet-is-not-connected-storybook-fixes
fix(#3682): adjust top menu - fixes to storybook + tests
2 parents d1e4940 + 4e6ceef commit c5b9232

File tree

3 files changed

+86
-27
lines changed

3 files changed

+86
-27
lines changed

govtool/frontend/src/components/atoms/Link.tsx

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@ import { NavLink } from "react-router-dom";
33
import { Typography } from "@mui/material";
44
import { useCardano } from "@context";
55

6+
const FONT_SIZE = {
7+
small: 14,
8+
big: 22,
9+
};
10+
611
type LinkProps = {
712
dataTestId?: string;
813
isConnectWallet?: boolean;
914
label: React.ReactNode;
1015
navTo: string;
11-
onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
16+
onClick?: (event: MouseEvent<HTMLElement>) => void;
1217
size?: "small" | "big";
1318
};
1419

@@ -24,10 +29,7 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
2429
} = props;
2530
const { disconnectWallet } = useCardano();
2631

27-
const fontSize = {
28-
small: 14,
29-
big: 22,
30-
}[size];
32+
const fontSize = FONT_SIZE[size];
3133

3234
return (
3335
<NavLink
@@ -57,3 +59,40 @@ export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
5759
);
5860
},
5961
);
62+
63+
// This component is used as a placeholder for links that do not navigate anywhere,
64+
// but with the same styling as the Link component.
65+
export const FakeLink = forwardRef<HTMLElement, Omit<LinkProps, "navTo">>(
66+
(props, ref) => {
67+
const {
68+
dataTestId,
69+
isConnectWallet,
70+
label,
71+
size = "small",
72+
onClick,
73+
} = props;
74+
const { disconnectWallet } = useCardano();
75+
76+
const fontSize = FONT_SIZE[size];
77+
78+
return (
79+
<Typography
80+
data-testid={dataTestId}
81+
onClick={(e) => {
82+
e.preventDefault();
83+
if (!isConnectWallet) disconnectWallet();
84+
if (onClick) onClick(e);
85+
}}
86+
ref={ref}
87+
sx={{
88+
cursor: "pointer",
89+
fontSize,
90+
fontWeight: 500,
91+
color: "textBlack",
92+
}}
93+
>
94+
{label}
95+
</Typography>
96+
);
97+
},
98+
);

govtool/frontend/src/components/organisms/TopNav.tsx

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState, FC } from "react";
22
import { NavLink, useNavigate } from "react-router-dom";
33
import { AppBar, Box, Grid, IconButton, Menu, MenuItem } from "@mui/material";
44
import MenuIcon from "@mui/icons-material/Menu";
5-
import { Button, Link } from "@atoms";
5+
import { Button, Link, FakeLink } from "@atoms";
66
import { ICONS, IMAGES, PATHS, NAV_ITEMS, NavMenuItem } from "@consts";
77
import { useCardano, useFeatureFlag, useModal } from "@context";
88
import { useScreenDimension, useTranslation } from "@hooks";
@@ -48,6 +48,10 @@ export const TopNav = ({ isConnectButton = true }) => {
4848
openModal({ type: "chooseWallet" });
4949
};
5050

51+
const closeDrawer = () => {
52+
setIsDrawerOpen(false);
53+
};
54+
5155
const renderDesktopNav = () => (
5256
<nav
5357
style={{ display: "flex", alignItems: "center", justifyContent: "end" }}
@@ -62,10 +66,7 @@ export const TopNav = ({ isConnectButton = true }) => {
6266
if (isNavMenuItem(navItem)) {
6367
return (
6468
<Grid item key={navItem.label}>
65-
<MenuNavItem
66-
navItem={navItem}
67-
closeDrawer={() => setIsDrawerOpen(false)}
68-
/>
69+
<MenuNavItem navItem={navItem} closeDrawer={closeDrawer} />
6970
</Grid>
7071
);
7172
}
@@ -75,7 +76,8 @@ export const TopNav = ({ isConnectButton = true }) => {
7576
{...navItem}
7677
isConnectWallet={isConnectButton}
7778
onClick={() => {
78-
setIsDrawerOpen(false);
79+
if (navItem.newTabLink) openInNewTab(navItem.newTabLink);
80+
closeDrawer();
7981
}}
8082
/>
8183
</Grid>
@@ -197,17 +199,17 @@ const MenuNavItem: FC<{
197199
navItem: NavMenuItem;
198200
closeDrawer: () => void;
199201
}> = ({ closeDrawer, navItem }) => {
200-
const [anchorEl, setAnchorEl] = useState<HTMLAnchorElement | null>(null);
202+
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
201203
const {
202204
isProposalDiscussionForumEnabled,
203205
isGovernanceOutcomesPillarEnabled,
204206
} = useFeatureFlag();
205207

206208
// Create a ref array for child links to manage cliking within MenuItem but outside of Link
207-
const linkRefs = useRef<Array<HTMLAnchorElement | null>>([]);
209+
const linkRefs = useRef<Array<HTMLElement | null>>([]);
208210

209211
const open = Boolean(anchorEl);
210-
const handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
212+
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
211213
setAnchorEl(event.currentTarget);
212214
};
213215
const handleClose = () => {
@@ -234,12 +236,8 @@ const MenuNavItem: FC<{
234236
};
235237
return (
236238
<>
237-
<Link
238-
navTo=""
239-
data-testid={navItem.dataTestId}
240-
aria-controls={open ? "basic-menu" : undefined}
241-
aria-haspopup="true"
242-
aria-expanded={open ? "true" : undefined}
239+
<FakeLink
240+
dataTestId={navItem.dataTestId}
243241
onClick={handleClick}
244242
label={
245243
<span
@@ -286,14 +284,14 @@ const MenuNavItem: FC<{
286284
{filterChildNavItems()?.map((childNavItem, idx) => (
287285
<MenuItem
288286
key={childNavItem.label}
289-
data-testid={childNavItem.dataTestId}
290287
sx={{ minWidth: 160 }}
291288
onClick={() => {
292289
linkRefs.current[idx]?.click();
293290
}}
294291
>
295292
<Link
296-
{...childNavItem}
293+
dataTestId={childNavItem.dataTestId}
294+
navTo={childNavItem.navTo}
297295
ref={(el) => {
298296
linkRefs.current[idx] = el;
299297
}}

govtool/frontend/src/stories/TopNav.stories.ts

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,34 @@ type Story = StoryObj<typeof meta>;
1515
const performCommonActions = async (canvas: ReturnType<typeof within>) => {
1616
window.open = fn();
1717

18-
await userEvent.click(canvas.getByTestId("logo-button"));
19-
const governanceActionsLink = canvas.getByTestId("governance-actions-link");
20-
await userEvent.click(canvas.getByTestId("governance-actions-link"));
18+
const logoButton = canvas.getByTestId("logo-button");
19+
await userEvent.click(logoButton);
20+
21+
const governanceActions = canvas.getByTestId("governance-actions");
22+
await userEvent.click(governanceActions);
23+
24+
// governance actions link is injected outside the TopNav component, so we use querySelector
25+
const governanceActionsLink = document.querySelector(
26+
'[data-testid="governance-actions-link"]',
27+
);
28+
if (!governanceActionsLink)
29+
throw new Error("governance-actions-link not found");
30+
await expect(governanceActionsLink).not.toHaveClass("active");
31+
await userEvent.click(governanceActionsLink);
32+
await expect(governanceActions).not.toHaveClass("active");
2133
await expect(governanceActionsLink).toHaveClass("active");
22-
await userEvent.click(canvas.getByTestId("guides-link"));
23-
await userEvent.click(canvas.getByTestId("faqs-link"));
34+
35+
const drepDirectoryLink = canvas.getByTestId("drep-directory-link");
36+
await expect(drepDirectoryLink).not.toHaveClass("active");
37+
await userEvent.click(drepDirectoryLink);
38+
await expect(drepDirectoryLink).toHaveClass("active");
39+
40+
const guidesLink = canvas.getByTestId("guides-link");
41+
await userEvent.click(guidesLink);
42+
43+
const faqsLink = canvas.getByTestId("faqs-link");
44+
await userEvent.click(faqsLink);
45+
2446
await expect(window.open).toHaveBeenCalledTimes(2);
2547
};
2648

0 commit comments

Comments
 (0)