Skip to content

Commit

Permalink
feat: mark repository as done (#788)
Browse files Browse the repository at this point in the history
  • Loading branch information
adufr committed Feb 19, 2024
1 parent 7efe0d9 commit 1bffe84
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 6 deletions.
20 changes: 18 additions & 2 deletions src/components/Repository.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jest.mock('./NotificationRow', () => ({

describe('components/Repository.tsx', () => {
const markRepoNotifications = jest.fn();
const markRepoNotificationsDone = jest.fn();

const props = {
hostname: 'github.com',
Expand Down Expand Up @@ -52,17 +53,32 @@ describe('components/Repository.tsx', () => {
});

it('should mark a repo as read', function () {
const { getByRole } = render(
const { getByTitle } = render(
<AppContext.Provider value={{ markRepoNotifications }}>
<RepositoryNotifications {...props} />
</AppContext.Provider>,
);

fireEvent.click(getByRole('button'));
fireEvent.click(getByTitle('Mark Repository as Read'));

expect(markRepoNotifications).toHaveBeenCalledWith(
'manosim/notifications-test',
'github.com',
);
});

it('should mark a repo as done', function () {
const { getByTitle } = render(
<AppContext.Provider value={{ markRepoNotificationsDone }}>
<RepositoryNotifications {...props} />
</AppContext.Provider>,
);

fireEvent.click(getByTitle('Mark Repository as Done'));

expect(markRepoNotificationsDone).toHaveBeenCalledWith(
'manosim/notifications-test',
'github.com',
);
});
});
22 changes: 19 additions & 3 deletions src/components/Repository.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback, useContext } from 'react';
import { ReadIcon } from '@primer/octicons-react';
import { ReadIcon, CheckIcon } from '@primer/octicons-react';
import { CSSTransition, TransitionGroup } from 'react-transition-group';

import { AppContext } from '../context/App';
Expand All @@ -18,7 +18,8 @@ export const RepositoryNotifications: React.FC<IProps> = ({
repoNotifications,
hostname,
}) => {
const { markRepoNotifications } = useContext(AppContext);
const { markRepoNotifications, markRepoNotificationsDone } =
useContext(AppContext);

const openBrowser = useCallback(() => {
const url = repoNotifications[0].repository.html_url;
Expand All @@ -30,6 +31,11 @@ export const RepositoryNotifications: React.FC<IProps> = ({
markRepoNotifications(repoSlug, hostname);
}, [repoNotifications, hostname]);

const markRepoAsDone = useCallback(() => {
const repoSlug = repoNotifications[0].repository.full_name;
markRepoNotificationsDone(repoSlug, hostname);
}, [repoNotifications, hostname]);

const avatarUrl = repoNotifications[0].repository.owner.avatar_url;

return (
Expand All @@ -40,7 +46,17 @@ export const RepositoryNotifications: React.FC<IProps> = ({
<span onClick={openBrowser}>{repoName}</span>
</div>

<div className="flex justify-center items-center">
<div className="flex justify-center items-center gap-2">
<button
className="focus:outline-none h-full hover:text-green-500"
title="Mark Repository as Done"
onClick={markRepoAsDone}
>
<CheckIcon size={16} aria-label="Mark Repository as Done" />
</button>

<div className="w-[14px]" />

<button
className="focus:outline-none h-full hover:text-green-500"
title="Mark Repository as Read"
Expand Down
34 changes: 33 additions & 1 deletion src/components/__snapshots__/Repository.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,40 @@ exports[`components/Repository.tsx should render itself & its children 1`] = `
</span>
</div>
<div
className="flex justify-center items-center"
className="flex justify-center items-center gap-2"
>
<button
className="focus:outline-none h-full hover:text-green-500"
onClick={[Function]}
title="Mark Repository as Done"
>
<svg
aria-hidden="false"
aria-label="Mark Repository as Done"
className="octicon octicon-check"
fill="currentColor"
focusable="false"
height={16}
role="img"
style={
{
"display": "inline-block",
"overflow": "visible",
"userSelect": "none",
"verticalAlign": "text-bottom",
}
}
viewBox="0 0 16 16"
width={16}
>
<path
d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
/>
</svg>
</button>
<div
className="w-[14px]"
/>
<button
className="focus:outline-none h-full hover:text-green-500"
onClick={[Function]}
Expand Down
9 changes: 9 additions & 0 deletions src/context/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ interface AppContextState {
markNotificationDone: (id: string, hostname: string) => Promise<void>;
unsubscribeNotification: (id: string, hostname: string) => Promise<void>;
markRepoNotifications: (id: string, hostname: string) => Promise<void>;
markRepoNotificationsDone: (id: string, hostname: string) => Promise<void>;

settings: SettingsState;
updateSetting: (name: keyof SettingsState, value: any) => void;
Expand All @@ -77,6 +78,7 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
markNotificationDone,
unsubscribeNotification,
markRepoNotifications,
markRepoNotificationsDone,
} = useNotifications(settings.colors);

useEffect(() => {
Expand Down Expand Up @@ -199,6 +201,12 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
[accounts, notifications],
);

const markRepoNotificationsDoneWithAccounts = useCallback(
async (repoSlug: string, hostname: string) =>
await markRepoNotificationsDone(accounts, repoSlug, hostname),
[accounts, notifications],
);

return (
<AppContext.Provider
value={{
Expand All @@ -218,6 +226,7 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => {
markNotificationDone: markNotificationDoneWithAccounts,
unsubscribeNotification: unsubscribeNotificationWithAccounts,
markRepoNotifications: markRepoNotificationsWithAccounts,
markRepoNotificationsDone: markRepoNotificationsDoneWithAccounts,

settings,
updateSetting,
Expand Down
103 changes: 103 additions & 0 deletions src/hooks/useNotifications.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -672,4 +672,107 @@ describe('hooks/useNotifications.ts', () => {
});
});
});

describe('markRepoNotificationsDone', () => {
const repoSlug = 'manosim/gitify';
const id = 'notification-123';

describe('github.com', () => {
const accounts = { ...mockAccounts, enterpriseAccounts: [] };
const hostname = 'github.com';

it("should mark a repository's notifications as done with success - github.com", async () => {
nock('https://api.github.com/')
.delete(`/notifications/threads/${id}`)
.reply(200);

const { result } = renderHook(() => useNotifications(false));

act(() => {
result.current.markRepoNotificationsDone(
accounts,
repoSlug,
hostname,
);
});

await waitFor(() => {
expect(result.current.isFetching).toBe(false);
});

expect(result.current.notifications.length).toBe(0);
});

it("should mark a repository's notifications as done with failure - github.com", async () => {
nock('https://api.github.com/')
.delete(`/notifications/threads/${id}`)
.reply(400);

const { result } = renderHook(() => useNotifications(false));

act(() => {
result.current.markRepoNotificationsDone(
accounts,
repoSlug,
hostname,
);
});

await waitFor(() => {
expect(result.current.isFetching).toBe(false);
});

expect(result.current.notifications.length).toBe(0);
});
});

describe('enterprise', () => {
const accounts = { ...mockAccounts, token: null };
const hostname = 'github.gitify.io';

it("should mark a repository's notifications as done with success - enterprise", async () => {
nock('https://api.github.com/')
.delete(`/notifications/threads/${id}`)
.reply(200);

const { result } = renderHook(() => useNotifications(false));

act(() => {
result.current.markRepoNotificationsDone(
accounts,
repoSlug,
hostname,
);
});

await waitFor(() => {
expect(result.current.isFetching).toBe(false);
});

expect(result.current.notifications.length).toBe(0);
});

it("should mark a repository's notifications as done with failure - enterprise", async () => {
nock('https://api.github.com/')
.delete(`/notifications/threads/${id}`)
.reply(400);

const { result } = renderHook(() => useNotifications(false));

act(() => {
result.current.markRepoNotificationsDone(
accounts,
repoSlug,
hostname,
);
});

await waitFor(() => {
expect(result.current.isFetching).toBe(false);
});

expect(result.current.notifications.length).toBe(0);
});
});
});
});
49 changes: 49 additions & 0 deletions src/hooks/useNotifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ interface NotificationsState {
repoSlug: string,
hostname: string,
) => Promise<void>;
markRepoNotificationsDone: (
accounts: AuthState,
repoSlug: string,
hostname: string,
) => Promise<void>;
isFetching: boolean;
requestFailed: boolean;
}
Expand Down Expand Up @@ -314,6 +319,49 @@ export const useNotifications = (colors: boolean): NotificationsState => {
[notifications],
);

const markRepoNotificationsDone = useCallback(
async (accounts, repoSlug, hostname) => {
setIsFetching(true);

try {
const accountIndex = notifications.findIndex(
(accountNotifications) => accountNotifications.hostname === hostname,
);

if (accountIndex !== -1) {
const notificationsToRemove = notifications[
accountIndex
].notifications.filter(
(notification) => notification.repository.full_name === repoSlug,
);

await Promise.all(
notificationsToRemove.map((notification) =>
markNotificationDone(
accounts,
notification.id,
notifications[accountIndex].hostname,
),
),
);
}

const updatedNotifications = removeNotifications(
repoSlug,
notifications,
hostname,
);

setNotifications(updatedNotifications);
setTrayIconColor(updatedNotifications);
setIsFetching(false);
} catch (err) {
setIsFetching(false);
}
},
[notifications],
);

const removeNotificationFromState = useCallback(
(id, hostname) => {
const updatedNotifications = removeNotification(
Expand All @@ -339,5 +387,6 @@ export const useNotifications = (colors: boolean): NotificationsState => {
markNotificationDone,
unsubscribeNotification,
markRepoNotifications,
markRepoNotificationsDone,
};
};

0 comments on commit 1bffe84

Please sign in to comment.