Skip to content

Commit

Permalink
refactor: extract sidebar button component (#1270)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
setchy authored Jun 18, 2024
1 parent 471f159 commit 3730a5d
Show file tree
Hide file tree
Showing 7 changed files with 313 additions and 60 deletions.
73 changes: 28 additions & 45 deletions src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ import { type FC, useContext, useMemo } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { Logo } from '../components/Logo';
import { AppContext } from '../context/App';
import { BUTTON_SIDEBAR_CLASS_NAME } from '../styles/gitify';
import { cn } from '../utils/cn';
import { quitApp } from '../utils/comms';
import { openGitHubNotifications, openGitifyRepository } from '../utils/links';
import { getNotificationCount } from '../utils/notifications';
import { SidebarButton } from './buttons/SidebarButton';

export const Sidebar: FC = () => {
const navigate = useNavigate();
Expand All @@ -29,6 +28,11 @@ export const Sidebar: FC = () => {
}
};

const refreshNotifications = () => {
navigate('/', { replace: true });
fetchNotifications();
};

const notificationsCount = useMemo(() => {
return getNotificationCount(notifications);
}, [notifications]);
Expand All @@ -46,63 +50,42 @@ export const Sidebar: FC = () => {
<Logo aria-label="Open Gitify" />
</button>

<button
type="button"
className={cn(
'my-1 flex cursor-pointer items-center justify-around self-stretch px-2 py-1 text-xs font-extrabold',
notificationsCount > 0 ? 'text-green-500' : 'text-white',
)}
onClick={() => openGitHubNotifications()}
<SidebarButton
title={`${notificationsCount} Unread Notifications`}
>
<BellIcon
size={12}
aria-label={`${notificationsCount} Unread Notifications`}
/>
{notificationsCount > 0 && notificationsCount}
</button>
metric={notificationsCount}
icon={BellIcon}
onClick={() => openGitHubNotifications()}
/>
</div>

<div className="px-3 py-4">
{isLoggedIn && (
<>
<button
type="button"
className={BUTTON_SIDEBAR_CLASS_NAME}
<SidebarButton
title="Refresh Notifications"
onClick={() => {
navigate('/', { replace: true });
fetchNotifications();
}}
icon={SyncIcon}
size={16}
loading={status === 'loading'}
disabled={status === 'loading'}
>
<SyncIcon
size={16}
aria-label="Refresh Notifications"
className={status === 'loading' ? 'animate-spin' : undefined}
/>
</button>
<button
type="button"
className={BUTTON_SIDEBAR_CLASS_NAME}
onClick={() => refreshNotifications()}
/>

<SidebarButton
title="Settings"
onClick={toggleSettings}
>
<GearIcon size={16} aria-label="Settings" />
</button>
icon={GearIcon}
size={16}
onClick={() => toggleSettings()}
/>
</>
)}

{!isLoggedIn && (
<button
type="button"
className={BUTTON_SIDEBAR_CLASS_NAME}
<SidebarButton
title="Quit Gitify"
aria-label="Quit Gitify"
onClick={quitApp}
>
<XCircleIcon size={16} aria-label="Quit Gitify" />
</button>
icon={XCircleIcon}
size={16}
onClick={() => quitApp()}
/>
)}
</div>
</div>
Expand Down
20 changes: 8 additions & 12 deletions src/components/__snapshots__/Sidebar.test.tsx.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions src/components/buttons/SidebarButton.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { MarkGithubIcon } from '@primer/octicons-react';
import { render } from '@testing-library/react';
import { type ISidebarButton, SidebarButton } from './SidebarButton';

describe('components/buttons/SidebarButton.tsx', () => {
it('should render with metric', () => {
const props: ISidebarButton = {
title: 'Mock Sidebar Button',
metric: 1,
icon: MarkGithubIcon,
};
const tree = render(<SidebarButton {...props} />);
expect(tree).toMatchSnapshot();
});

it('should render without metric', () => {
const props: ISidebarButton = {
title: 'Mock Sidebar Button',
metric: 0,
icon: MarkGithubIcon,
};
const tree = render(<SidebarButton {...props} />);
expect(tree).toMatchSnapshot();
});
});
38 changes: 38 additions & 0 deletions src/components/buttons/SidebarButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { Icon } from '@primer/octicons-react';
import type { FC } from 'react';
import { IconColor } from '../../types';
import { cn } from '../../utils/cn';

export interface ISidebarButton {
title: string;
metric?: number;
icon: Icon;
onClick?: () => void;
size?: number;
loading?: boolean;
disabled?: boolean;
}

export const SidebarButton: FC<ISidebarButton> = (props: ISidebarButton) => {
const hasMetric = props?.metric > 0;

return (
<button
type="button"
className={cn(
'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',
hasMetric
? `${IconColor.GREEN} hover:text-green-700`
: `${IconColor.WHITE} hover:text-gray-500`,
props.loading ? 'animate-spin' : undefined,
props.size ? 'py-2' : 'py-1',
)}
onClick={() => props.onClick()}
title={props.title}
disabled={props.disabled}
>
<props.icon size={props.size ?? 12} aria-label={props.title} />
{hasMetric && props.metric}
</button>
);
};
Loading

0 comments on commit 3730a5d

Please sign in to comment.