• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gitify-app / gitify / 13089087317

01 Feb 2025 01:27PM UTC coverage: 87.327% (-0.04%) from 87.364%
13089087317

Pull #1803

github

web-flow
Merge 03177131f into 2e515d06c
Pull Request #1803: fix(deps): update react-router-dom to v7.1.5

639 of 716 branches covered (89.25%)

Branch coverage included in aggregate %.

1697 of 1959 relevant lines covered (86.63%)

25.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.88
/src/renderer/hooks/useNotifications.ts
1
import { useCallback, useState } from 'react';
74✔
2

3
import { logError } from '../../shared/logger';
74✔
4
import type {
5
  Account,
6
  AccountNotifications,
7
  GitifyError,
8
  GitifyState,
9
  Status,
10
} from '../types';
11
import type { Notification } from '../typesGitHub';
12
import {
74✔
13
  ignoreNotificationThreadSubscription,
14
  markNotificationThreadAsDone,
15
  markNotificationThreadAsRead,
16
} from '../utils/api/client';
17
import { updateTrayIcon } from '../utils/comms';
74✔
18
import { isMarkAsDoneFeatureSupported } from '../utils/features';
74✔
19
import { triggerNativeNotifications } from '../utils/notifications/native';
74✔
20
import {
74✔
21
  getAllNotifications,
22
  setTrayIconColor,
23
} from '../utils/notifications/notifications';
24
import { removeNotifications } from '../utils/notifications/remove';
74✔
25

26
interface NotificationsState {
27
  notifications: AccountNotifications[];
28
  removeAccountNotifications: (account: Account) => Promise<void>;
29
  fetchNotifications: (state: GitifyState) => Promise<void>;
30
  markNotificationsAsRead: (
31
    state: GitifyState,
32
    notifications: Notification[],
33
  ) => Promise<void>;
34
  markNotificationsAsDone: (
35
    state: GitifyState,
36
    notifications: Notification[],
37
  ) => Promise<void>;
38
  unsubscribeNotification: (
39
    state: GitifyState,
40
    notification: Notification,
41
  ) => Promise<void>;
42
  status: Status;
43
  globalError: GitifyError;
44
}
45

46
export const useNotifications = (): NotificationsState => {
74✔
47
  const [status, setStatus] = useState<Status>('success');
66✔
48
  const [globalError, setGlobalError] = useState<GitifyError>();
66✔
49

50
  const [notifications, setNotifications] = useState<AccountNotifications[]>(
66✔
51
    [],
52
  );
53

54
  const removeAccountNotifications = useCallback(
66✔
55
    async (account: Account) => {
56
      setStatus('loading');
×
57

58
      const updatedNotifications = notifications.filter(
×
59
        (notification) => notification.account !== account,
×
60
      );
61

62
      setNotifications(updatedNotifications);
×
63
      setTrayIconColor(updatedNotifications);
×
64
      setStatus('success');
×
65
    },
66
    [notifications],
67
  );
68

69
  const fetchNotifications = useCallback(
66✔
70
    async (state: GitifyState) => {
71
      setStatus('loading');
8✔
72
      setGlobalError(null);
8✔
73

74
      const fetchedNotifications = await getAllNotifications(state);
8✔
75

76
      // Set Global Error if all accounts have the same error
77
      const allAccountsHaveErrors =
78
        fetchedNotifications.length > 0 &&
8✔
79
        fetchedNotifications.every((account) => {
80
          return account.error !== null;
12✔
81
        });
82

83
      let accountErrorsAreAllSame = true;
8✔
84
      const accountError = fetchedNotifications[0]?.error;
8✔
85

86
      for (const fetchedNotification of fetchedNotifications) {
8✔
87
        if (accountError !== fetchedNotification.error) {
14✔
88
          accountErrorsAreAllSame = false;
2✔
89
          break;
2✔
90
        }
91
      }
92

93
      if (allAccountsHaveErrors) {
8✔
94
        setStatus('error');
4✔
95
        setGlobalError(accountErrorsAreAllSame ? accountError : null);
4✔
96
        updateTrayIcon(-1);
4✔
97
        return;
4✔
98
      }
99

100
      setNotifications(fetchedNotifications);
4✔
101
      triggerNativeNotifications(notifications, fetchedNotifications, state);
4✔
102
      setStatus('success');
4✔
103
    },
104
    [notifications],
105
  );
106

107
  const markNotificationsAsRead = useCallback(
66✔
108
    async (state: GitifyState, readNotifications: Notification[]) => {
109
      setStatus('loading');
4✔
110

111
      try {
4✔
112
        await Promise.all(
4✔
113
          readNotifications.map((notification) =>
114
            markNotificationThreadAsRead(
4✔
115
              notification.id,
116
              notification.account.hostname,
117
              notification.account.token,
118
            ),
119
          ),
120
        );
121

122
        const updatedNotifications = removeNotifications(
2✔
123
          state.settings,
124
          readNotifications,
125
          notifications,
126
        );
127

128
        setNotifications(updatedNotifications);
2✔
129
        setTrayIconColor(updatedNotifications);
2✔
130
      } catch (err) {
131
        logError(
2✔
132
          'markNotificationsAsRead',
133
          'Error occurred while marking notifications as read',
134
          err,
135
        );
136
      }
137

138
      setStatus('success');
4✔
139
    },
140
    [notifications],
141
  );
142

143
  const markNotificationsAsDone = useCallback(
66✔
144
    async (state: GitifyState, doneNotifications: Notification[]) => {
145
      setStatus('loading');
4✔
146

147
      try {
4✔
148
        if (isMarkAsDoneFeatureSupported(doneNotifications[0].account)) {
4✔
149
          await Promise.all(
4✔
150
            doneNotifications.map((notification) =>
151
              markNotificationThreadAsDone(
4✔
152
                notification.id,
153
                notification.account.hostname,
154
                notification.account.token,
155
              ),
156
            ),
157
          );
158
        }
159

160
        const updatedNotifications = removeNotifications(
2✔
161
          state.settings,
162
          doneNotifications,
163
          notifications,
164
        );
165

166
        setNotifications(updatedNotifications);
2✔
167
        setTrayIconColor(updatedNotifications);
2✔
168
      } catch (err) {
169
        logError(
2✔
170
          'markNotificationsAsDone',
171
          'Error occurred while marking notifications as done',
172
          err,
173
        );
174
      }
175

176
      setStatus('success');
4✔
177
    },
178
    [notifications],
179
  );
180

181
  const unsubscribeNotification = useCallback(
66✔
182
    async (state: GitifyState, notification: Notification) => {
183
      setStatus('loading');
6✔
184

185
      try {
6✔
186
        await ignoreNotificationThreadSubscription(
6✔
187
          notification.id,
188
          notification.account.hostname,
189
          notification.account.token,
190
        );
191

192
        if (state.settings.markAsDoneOnUnsubscribe) {
×
193
          await markNotificationsAsDone(state, [notification]);
×
194
        } else {
195
          await markNotificationsAsRead(state, [notification]);
×
196
        }
197
      } catch (err) {
198
        logError(
6✔
199
          'unsubscribeNotification',
200
          'Error occurred while unsubscribing from notification thread',
201
          err,
202
          notification,
203
        );
204
      }
205

206
      setStatus('success');
6✔
207
    },
208
    [markNotificationsAsRead, markNotificationsAsDone],
209
  );
210

211
  return {
66✔
212
    status,
213
    globalError,
214
    notifications,
215

216
    removeAccountNotifications,
217
    fetchNotifications,
218
    markNotificationsAsRead,
219
    markNotificationsAsDone,
220
    unsubscribeNotification,
221
  };
222
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc