this repo has no description
1// This is like very lame "type-checking" lol
2const notificationTypeKeys = {
3 mention: ['account', 'status'],
4 status: ['account', 'status'],
5 reblog: ['account', 'status'],
6 follow: ['account'],
7 follow_request: ['account'],
8 favourite: ['account', 'status'],
9 poll: ['status'],
10 update: ['status'],
11};
12function fixNotifications(notifications) {
13 return notifications.filter((notification) => {
14 const { type, id, createdAt } = notification;
15 if (!type) {
16 console.warn('Notification missing type', notification);
17 return false;
18 }
19 if (!id || !createdAt) {
20 console.warn('Notification missing id or createdAt', notification);
21 // Continue processing this despite missing id or createdAt
22 }
23 const keys = notificationTypeKeys[type];
24 if (keys?.length) {
25 return keys.every((key) => !!notification[key]);
26 }
27 return true; // skip other types
28 });
29}
30
31function groupNotifications(notifications) {
32 // Filter out invalid notifications
33 notifications = fixNotifications(notifications);
34
35 // Create new flat list of notifications
36 // Combine sibling notifications based on type and status id
37 // Concat all notification.account into an array of _accounts
38 const notificationsMap = {};
39 const cleanNotifications = [];
40 for (let i = 0, j = 0; i < notifications.length; i++) {
41 const notification = notifications[i];
42 const { id, status, account, type, createdAt } = notification;
43 const date = createdAt ? new Date(createdAt).toLocaleDateString() : '';
44 let virtualType = type;
45 if (type === 'favourite' || type === 'reblog') {
46 virtualType = 'favourite+reblog';
47 }
48 const key = `${status?.id}-${virtualType}-${date}`;
49 const mappedNotification = notificationsMap[key];
50 if (virtualType === 'follow_request') {
51 cleanNotifications[j++] = notification;
52 } else if (mappedNotification?.account) {
53 const mappedAccount = mappedNotification._accounts.find(
54 (a) => a.id === account.id,
55 );
56 if (mappedAccount) {
57 mappedAccount._types.push(type);
58 mappedAccount._types.sort().reverse();
59 mappedNotification.id += `-${id}`;
60 } else {
61 account._types = [type];
62 mappedNotification._accounts.push(account);
63 mappedNotification.id += `-${id}`;
64 }
65 } else {
66 account._types = [type];
67 let n = (notificationsMap[key] = {
68 ...notification,
69 type: virtualType,
70 _accounts: [account],
71 });
72 cleanNotifications[j++] = n;
73 }
74 }
75
76 // 2nd pass to group "favourite+reblog"-type notifications by account if _accounts.length <= 1
77 // This means one acount has favourited and reblogged the multiple statuses
78 // The grouped notification
79 // - type: "favourite+reblog+account"
80 // - _statuses: [status, status, ...]
81 const notificationsMap2 = {};
82 const cleanNotifications2 = [];
83 for (let i = 0, j = 0; i < cleanNotifications.length; i++) {
84 const notification = cleanNotifications[i];
85 const { id, account, _accounts, type, createdAt } = notification;
86 const date = createdAt ? new Date(createdAt).toLocaleDateString() : '';
87 if (type === 'favourite+reblog' && account && _accounts.length === 1) {
88 const key = `${account?.id}-${type}-${date}`;
89 const mappedNotification = notificationsMap2[key];
90 if (mappedNotification) {
91 mappedNotification._statuses.push(notification.status);
92 mappedNotification.id += `-${id}`;
93 } else {
94 let n = (notificationsMap2[key] = {
95 ...notification,
96 type,
97 _statuses: [notification.status],
98 });
99 cleanNotifications2[j++] = n;
100 }
101 } else {
102 cleanNotifications2[j++] = notification;
103 }
104 }
105
106 console.log({ notifications, cleanNotifications, cleanNotifications2 });
107
108 // return cleanNotifications;
109 return cleanNotifications2;
110}
111
112export default groupNotifications;