Skip to content

Commit 3730a5d

Browse files
authored
refactor: extract sidebar button component (#1270)
* feat: my quick links * refactor: extract sidebar button into component * refactor: extract sidebar button into component * refactor: extract sidebar button into component * refactor: extract sidebar button into component
1 parent 471f159 commit 3730a5d

File tree

7 files changed

+313
-60
lines changed

7 files changed

+313
-60
lines changed

src/components/Sidebar.tsx

Lines changed: 28 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ import { type FC, useContext, useMemo } from 'react';
88
import { useLocation, useNavigate } from 'react-router-dom';
99
import { Logo } from '../components/Logo';
1010
import { AppContext } from '../context/App';
11-
import { BUTTON_SIDEBAR_CLASS_NAME } from '../styles/gitify';
12-
import { cn } from '../utils/cn';
1311
import { quitApp } from '../utils/comms';
1412
import { openGitHubNotifications, openGitifyRepository } from '../utils/links';
1513
import { getNotificationCount } from '../utils/notifications';
14+
import { SidebarButton } from './buttons/SidebarButton';
1615

1716
export const Sidebar: FC = () => {
1817
const navigate = useNavigate();
@@ -29,6 +28,11 @@ export const Sidebar: FC = () => {
2928
}
3029
};
3130

31+
const refreshNotifications = () => {
32+
navigate('/', { replace: true });
33+
fetchNotifications();
34+
};
35+
3236
const notificationsCount = useMemo(() => {
3337
return getNotificationCount(notifications);
3438
}, [notifications]);
@@ -46,63 +50,42 @@ export const Sidebar: FC = () => {
4650
<Logo aria-label="Open Gitify" />
4751
</button>
4852

49-
<button
50-
type="button"
51-
className={cn(
52-
'my-1 flex cursor-pointer items-center justify-around self-stretch px-2 py-1 text-xs font-extrabold',
53-
notificationsCount > 0 ? 'text-green-500' : 'text-white',
54-
)}
55-
onClick={() => openGitHubNotifications()}
53+
<SidebarButton
5654
title={`${notificationsCount} Unread Notifications`}
57-
>
58-
<BellIcon
59-
size={12}
60-
aria-label={`${notificationsCount} Unread Notifications`}
61-
/>
62-
{notificationsCount > 0 && notificationsCount}
63-
</button>
55+
metric={notificationsCount}
56+
icon={BellIcon}
57+
onClick={() => openGitHubNotifications()}
58+
/>
6459
</div>
6560

6661
<div className="px-3 py-4">
6762
{isLoggedIn && (
6863
<>
69-
<button
70-
type="button"
71-
className={BUTTON_SIDEBAR_CLASS_NAME}
64+
<SidebarButton
7265
title="Refresh Notifications"
73-
onClick={() => {
74-
navigate('/', { replace: true });
75-
fetchNotifications();
76-
}}
66+
icon={SyncIcon}
67+
size={16}
68+
loading={status === 'loading'}
7769
disabled={status === 'loading'}
78-
>
79-
<SyncIcon
80-
size={16}
81-
aria-label="Refresh Notifications"
82-
className={status === 'loading' ? 'animate-spin' : undefined}
83-
/>
84-
</button>
85-
<button
86-
type="button"
87-
className={BUTTON_SIDEBAR_CLASS_NAME}
70+
onClick={() => refreshNotifications()}
71+
/>
72+
73+
<SidebarButton
8874
title="Settings"
89-
onClick={toggleSettings}
90-
>
91-
<GearIcon size={16} aria-label="Settings" />
92-
</button>
75+
icon={GearIcon}
76+
size={16}
77+
onClick={() => toggleSettings()}
78+
/>
9379
</>
9480
)}
9581

9682
{!isLoggedIn && (
97-
<button
98-
type="button"
99-
className={BUTTON_SIDEBAR_CLASS_NAME}
83+
<SidebarButton
10084
title="Quit Gitify"
101-
aria-label="Quit Gitify"
102-
onClick={quitApp}
103-
>
104-
<XCircleIcon size={16} aria-label="Quit Gitify" />
105-
</button>
85+
icon={XCircleIcon}
86+
size={16}
87+
onClick={() => quitApp()}
88+
/>
10689
)}
10790
</div>
10891
</div>

src/components/__snapshots__/Sidebar.test.tsx.snap

Lines changed: 8 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { MarkGithubIcon } from '@primer/octicons-react';
2+
import { render } from '@testing-library/react';
3+
import { type ISidebarButton, SidebarButton } from './SidebarButton';
4+
5+
describe('components/buttons/SidebarButton.tsx', () => {
6+
it('should render with metric', () => {
7+
const props: ISidebarButton = {
8+
title: 'Mock Sidebar Button',
9+
metric: 1,
10+
icon: MarkGithubIcon,
11+
};
12+
const tree = render(<SidebarButton {...props} />);
13+
expect(tree).toMatchSnapshot();
14+
});
15+
16+
it('should render without metric', () => {
17+
const props: ISidebarButton = {
18+
title: 'Mock Sidebar Button',
19+
metric: 0,
20+
icon: MarkGithubIcon,
21+
};
22+
const tree = render(<SidebarButton {...props} />);
23+
expect(tree).toMatchSnapshot();
24+
});
25+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { Icon } from '@primer/octicons-react';
2+
import type { FC } from 'react';
3+
import { IconColor } from '../../types';
4+
import { cn } from '../../utils/cn';
5+
6+
export interface ISidebarButton {
7+
title: string;
8+
metric?: number;
9+
icon: Icon;
10+
onClick?: () => void;
11+
size?: number;
12+
loading?: boolean;
13+
disabled?: boolean;
14+
}
15+
16+
export const SidebarButton: FC<ISidebarButton> = (props: ISidebarButton) => {
17+
const hasMetric = props?.metric > 0;
18+
19+
return (
20+
<button
21+
type="button"
22+
className={cn(
23+
'flex justify-evenly items-center w-full my-1 cursor-pointer text-xs font-extrabold focus:outline-none disabled:text-gray-500 disabled:cursor-default',
24+
hasMetric
25+
? `${IconColor.GREEN} hover:text-green-700`
26+
: `${IconColor.WHITE} hover:text-gray-500`,
27+
props.loading ? 'animate-spin' : undefined,
28+
props.size ? 'py-2' : 'py-1',
29+
)}
30+
onClick={() => props.onClick()}
31+
title={props.title}
32+
disabled={props.disabled}
33+
>
34+
<props.icon size={props.size ?? 12} aria-label={props.title} />
35+
{hasMetric && props.metric}
36+
</button>
37+
);
38+
};

0 commit comments

Comments
 (0)