this repo has no description
at hotfix/infinite-loop-intersection-observer 112 lines 3.9 kB view raw
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;