Skip to content

Commit

Permalink
feat: show all notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
setchy committed Apr 20, 2024
1 parent 7aa8200 commit c3cbcef
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 75 deletions.
2 changes: 1 addition & 1 deletion src/__mocks__/mock-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ export const mockSettings: SettingsState = {
detailedNotifications: false,
markAsDoneOnOpen: false,
showAccountHostname: false,
showReadNotifications: false,
showAllNotifications: false,
};
50 changes: 18 additions & 32 deletions src/components/NotificationRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,13 @@ export const NotificationRow: FC<IProps> = ({ notification, hostname }) => {
notifications,
} = useContext(AppContext);

const setNotificationAsOpaque = () => {
if (notification.unread) {
const notificationRow = document.getElementById(notification.id);
notificationRow.className += Constants.READ_CLASS_NAME;
}
notification.unread = false;
};

const openNotification = useCallback(() => {
openInBrowser(notification, accounts);

if (settings.markAsDoneOnOpen) {
markNotificationDone(notification.id, hostname);
}

if (!settings.showReadNotifications) {
removeNotificationFromState(notification.id, hostname);
} else {
setNotificationAsOpaque();
}
handleNotificationState();
}, [notifications, notification, accounts, settings]); // notifications required here to prevent weird state issues

const unsubscribe = (event: MouseEvent<HTMLElement>) => {
Expand All @@ -68,32 +55,17 @@ export const NotificationRow: FC<IProps> = ({ notification, hostname }) => {

unsubscribeNotification(notification.id, hostname);
markNotificationRead(notification.id, hostname);

if (!settings.showReadNotifications) {
removeNotificationFromState(notification.id, hostname);
} else {
setNotificationAsOpaque();
}
handleNotificationState();
};

const markAsRead = () => {
markNotificationRead(notification.id, hostname);

if (!settings.showReadNotifications) {
removeNotificationFromState(notification.id, hostname);
} else {
setNotificationAsOpaque();
}
handleNotificationState();
};

const markAsDone = () => {
markNotificationDone(notification.id, hostname);

if (!settings.showReadNotifications) {
removeNotificationFromState(notification.id, hostname);
} else {
setNotificationAsOpaque();
}
handleNotificationState();
};

const openUserProfile = (
Expand All @@ -105,6 +77,20 @@ export const NotificationRow: FC<IProps> = ({ notification, hostname }) => {
openExternalLink(notification.subject.user.html_url);
};

const handleNotificationState = useCallback(() => {
if (!settings.showAllNotifications) {
removeNotificationFromState(notification.id, hostname);
}

if (notification.unread) {
const notificationRow = document.getElementById(notification.id);
notificationRow.className += Constants.READ_CLASS_NAME;
}

// TODO FIXME - this is not updating the notification count
notification.unread = false;
}, [notification, notifications]);

const reason = formatReason(notification.reason);
const NotificationIcon = getNotificationTypeIcon(notification.subject);
const iconColor = getNotificationTypeIconColor(notification.subject);
Expand Down
41 changes: 21 additions & 20 deletions src/components/Repository.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,6 @@ export const RepositoryNotifications: FC<IProps> = ({
removeNotificationsFromState,
} = useContext(AppContext);

const setNotificationsAsOpaque = (repoNotifications: Notification[]) => {
for (const notification of repoNotifications) {
if (notification.unread) {
const notificationRow = document.getElementById(notification.id);
notificationRow.className += Constants.READ_CLASS_NAME;
}
notification.unread = false;
}
};

const openBrowser = useCallback(() => {
const url = repoNotifications[0].repository.html_url;
openExternalLink(url);
Expand All @@ -46,23 +36,34 @@ export const RepositoryNotifications: FC<IProps> = ({
const markRepoAsRead = useCallback(() => {
const repoSlug = repoNotifications[0].repository.full_name;
markRepoNotificationsRead(repoSlug, hostname);
if (!settings.showReadNotifications) {
removeNotificationsFromState(repoSlug, notifications, hostname);
} else {
setNotificationsAsOpaque(repoNotifications);
}
handleNotificationState(repoSlug);
}, [repoNotifications, hostname]);

const markRepoAsDone = useCallback(() => {
const repoSlug = repoNotifications[0].repository.full_name;
markRepoNotificationsDone(repoSlug, hostname);
if (!settings.showReadNotifications) {
removeNotificationsFromState(repoSlug, notifications, hostname);
} else {
setNotificationsAsOpaque(repoNotifications);
}
handleNotificationState(repoSlug);
}, [repoNotifications, hostname]);

const handleNotificationState = useCallback(
(repoSlug: string) => {
if (!settings.showAllNotifications) {
removeNotificationsFromState(repoSlug, notifications, hostname);
}

for (const notification of repoNotifications) {
if (notification.unread) {
const notificationRow = document.getElementById(notification.id);
notificationRow.className += Constants.READ_CLASS_NAME;
}

// TODO FIXME - this is not updating the notification count
notification.unread = false;
}
},
[repoNotifications, hostname, notifications],
);

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

Expand Down
4 changes: 2 additions & 2 deletions src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Logo } from '../components/Logo';
import { AppContext } from '../context/App';
import { openExternalLink } from '../utils/comms';
import { Constants } from '../utils/constants';
import { getNotificationCount } from '../utils/notifications';
import { getUnreadNotificationCount } from '../utils/notifications';

export const Sidebar: FC = () => {
const navigate = useNavigate();
Expand All @@ -35,7 +35,7 @@ export const Sidebar: FC = () => {
}, []);

const notificationsCount = useMemo(() => {
return getNotificationCount(notifications);
return getUnreadNotificationCount(notifications);
}, [notifications]);

const sidebarButtonClasses =
Expand Down
6 changes: 3 additions & 3 deletions src/context/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ describe('context/App.tsx', () => {

describe('api methods', () => {
const apiRequestAuthMock = jest.spyOn(apiRequests, 'apiRequestAuth');
const getNotificationCountMock = jest.spyOn(
const getUnreadNotificationCountMock = jest.spyOn(
notifications,
'getNotificationCount',
'getUnreadNotificationCount',
);
getNotificationCountMock.mockReturnValue(1);
getUnreadNotificationCountMock.mockReturnValue(1);

const fetchNotificationsMock = jest.fn();
const markNotificationReadMock = jest.fn();
Expand Down
8 changes: 4 additions & 4 deletions src/context/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { addAccount, authGitHub, getToken, getUserData } from '../utils/auth';
import { setAutoLaunch, updateTrayTitle } from '../utils/comms';
import Constants from '../utils/constants';
import { generateGitHubAPIUrl } from '../utils/helpers';
import { getNotificationCount } from '../utils/notifications';
import { getUnreadNotificationCount } from '../utils/notifications';
import { clearState, loadState, saveState } from '../utils/storage';
import { setTheme } from '../utils/theme';

Expand All @@ -44,7 +44,7 @@ export const defaultSettings: SettingsState = {
detailedNotifications: false,
markAsDoneOnOpen: false,
showAccountHostname: false,
showReadNotifications: false,
showAllNotifications: false,
};

interface AppContextState {
Expand Down Expand Up @@ -114,7 +114,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
settings.participating,
settings.showBots,
settings.detailedNotifications,
settings.showReadNotifications,
settings.showAllNotifications,
accounts.token,
accounts.enterpriseAccounts.length,
]);
Expand All @@ -125,7 +125,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {

// biome-ignore lint/correctness/useExhaustiveDependencies: We need to update tray title when settings or notifications changes.
useEffect(() => {
const count = getNotificationCount(notifications);
const count = getUnreadNotificationCount(notifications);

if (settings.showNotificationsCountInTray && count > 0) {
updateTrayTitle(count.toString());
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useNotifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export const useNotifications = (): NotificationsState => {
const fetchNotifications = useCallback(
async (accounts: AuthState, settings: SettingsState) => {
function getNotifications(hostname: string, token: string): AxiosPromise {
const endpointSuffix = `notifications?all=${settings.showReadNotifications}&participating=${settings.participating}`;
const endpointSuffix = `notifications?all=${settings.showAllNotifications}&participating=${settings.participating}`;
const url = `${generateGitHubAPIUrl(hostname)}${endpointSuffix}`;
return apiRequestAuth(url, 'GET', token);
}
Expand Down
6 changes: 3 additions & 3 deletions src/routes/Notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { AllRead } from '../components/AllRead';
import { Oops } from '../components/Oops';
import { AppContext } from '../context/App';
import { Errors } from '../utils/constants';
import { getNotificationCount } from '../utils/notifications';
import { getUnreadNotificationCount } from '../utils/notifications';

export const NotificationsRoute: FC = () => {
const { notifications, requestFailed, errorDetails, settings } =
Expand All @@ -16,7 +16,7 @@ export const NotificationsRoute: FC = () => {
[notifications],
);
const notificationsCount = useMemo(() => {
return getNotificationCount(notifications);
return getUnreadNotificationCount(notifications);
}, [notifications]);

const hasNotifications = useMemo(
Expand All @@ -28,7 +28,7 @@ export const NotificationsRoute: FC = () => {
return <Oops error={errorDetails ?? Errors.UNKNOWN} />;
}

if (!hasNotifications) {
if (!hasNotifications && !settings.showAllNotifications) {
return <AllRead />;
}

Expand Down
20 changes: 16 additions & 4 deletions src/routes/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,23 @@ export const SettingsRoute: FC = () => {
Notifications
</legend>
<Checkbox
name="showReadNotifications"
label="Show read notifications"
checked={settings.showReadNotifications}
name="showAllNotifications"
label="Show all notifications"
checked={settings.showAllNotifications}
onChange={(evt) =>
updateSetting('showReadNotifications', evt.target.checked)
updateSetting('showAllNotifications', evt.target.checked)
}
tooltip={
<div>
<div className="pb-3">
Will show up to 50 latest notifications regardless of status
(read, unread, done).
</div>
<div className="text-orange-600">
⚠️ Users <i>may</i> experience rate limiting under certain
circumstances. Disable this setting if you experience this.
</div>
</div>
}
/>
<Checkbox
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ interface NotificationSettingsState {
showNotifications: boolean;
showBots: boolean;
markAsDoneOnOpen: boolean;
showReadNotifications: boolean;
showAllNotifications: boolean;
}

interface SystemSettingsState {
Expand Down
12 changes: 8 additions & 4 deletions src/utils/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ import { updateTrayIcon } from './comms';
import type { AccountNotifications, AuthState, SettingsState } from '../types';

export const setTrayIconColor = (notifications: AccountNotifications[]) => {
const allNotificationsCount = getNotificationCount(notifications);
const notificationCount = getUnreadNotificationCount(notifications);

updateTrayIcon(allNotificationsCount);
updateTrayIcon(notificationCount);
};

export function getNotificationCount(notifications: AccountNotifications[]) {
export function getUnreadNotificationCount(
notifications: AccountNotifications[],
) {
return notifications.reduce(
(memo, acc) => memo + acc.notifications.length,
(memo, acc) =>
memo +
acc.notifications.filter((notification) => notification.unread).length,
0,
);
}
Expand Down

0 comments on commit c3cbcef

Please sign in to comment.