diff --git a/helpers/notifications.js b/helpers/notifications.js index d4a9b0287..e0656d0fd 100644 --- a/helpers/notifications.js +++ b/helpers/notifications.js @@ -6,174 +6,143 @@ async function getBulk(type, ids, apiVersion = 2) { } const url = `${type}?ids=${encodeURIComponent(JSON.stringify([...new Set(ids)]))}` - const { data: bulkFetch } = await useAsyncData(url, () => useBaseFetch(url, { apiVersion })) - return bulkFetch.value + return await useBaseFetch(url, { apiVersion }) } -export async function fetchNotifications() { - try { - const auth = (await useAuth()).value - const { data: notifications } = await useAsyncData(`user/${auth.user.id}/notifications`, () => - useBaseFetch(`user/${auth.user.id}/notifications`) - ) - - const projectIds = [] - const reportIds = [] - const threadIds = [] - const userIds = [] - const versionIds = [] - const organizationIds = [] - - for (const notification of notifications.value) { - if (notification.body) { - if (notification.body.project_id) { - projectIds.push(notification.body.project_id) - } - if (notification.body.version_id) { - versionIds.push(notification.body.version_id) - } - if (notification.body.report_id) { - reportIds.push(notification.body.report_id) - } - if (notification.body.thread_id) { - threadIds.push(notification.body.thread_id) - } - if (notification.body.invited_by) { - userIds.push(notification.body.invited_by) - } - if (notification.body.organization_id) { - organizationIds.push(notification.body.organization_id) - } - } - } - - const reports = await getBulk('reports', reportIds) - - for (const report of reports) { - if (report.item_type === 'project') { - projectIds.push(report.item_id) - } else if (report.item_type === 'user') { - userIds.push(report.item_id) - } else if (report.item_type === 'version') { - versionIds.push(report.item_id) - } - } - - const versions = await getBulk('versions', versionIds) - - for (const version of versions) { - projectIds.push(version.project_id) - } - - const [projects, threads, users, organizations] = await Promise.all([ - getBulk('projects', projectIds), - getBulk('threads', threadIds), - getBulk('users', userIds), - getBulk('organizations', organizationIds, 3), - ]) - - for (const notification of notifications.value) { - notification.extra_data = {} - if (notification.body) { - if (notification.body.project_id) { - notification.extra_data.project = projects.find( - (x) => x.id === notification.body.project_id - ) - } - if (notification.body.organization_id) { - notification.extra_data.organization = organizations.find( - (x) => x.id === notification.body.organization_id - ) - } - if (notification.body.report_id) { - notification.extra_data.report = reports.find((x) => x.id === notification.body.report_id) - - const type = notification.extra_data.report.item_type - if (type === 'project') { - notification.extra_data.project = projects.find( - (x) => x.id === notification.extra_data.report.item_id - ) - } else if (type === 'user') { - notification.extra_data.user = users.find( - (x) => x.id === notification.extra_data.report.item_id - ) - } else if (type === 'version') { - notification.extra_data.version = versions.find( - (x) => x.id === notification.extra_data.report.item_id - ) - notification.extra_data.project = projects.find( - (x) => x.id === notification.extra_data.version.project_id - ) - } - } - if (notification.body.thread_id) { - notification.extra_data.thread = threads.find((x) => x.id === notification.body.thread_id) - } - if (notification.body.invited_by) { - notification.extra_data.invited_by = users.find( - (x) => x.id === notification.body.invited_by - ) - } - if (notification.body.version_id) { - notification.extra_data.version = versions.find( - (x) => x.id === notification.body.version_id - ) - } - } - } - - return notifications.value - } catch (error) { - const app = useNuxtApp() - app.$notify({ - group: 'main', - title: 'Error loading notifications', - text: error.data ? error.data.description : error, - type: 'error', - }) +export async function fetchExtraNotificationData(notifications) { + const bulk = { + projects: [], + reports: [], + threads: [], + users: [], + versions: [], + organizations: [], } - return null -} - -export function groupNotifications(notifications, includeRead = false) { - const grouped = [] for (const notification of notifications) { - notification.grouped_notifs = [] + if (notification.body) { + if (notification.body.project_id) { + bulk.projects.push(notification.body.project_id) + } + if (notification.body.version_id) { + bulk.versions.push(notification.body.version_id) + } + if (notification.body.report_id) { + bulk.reports.push(notification.body.report_id) + } + if (notification.body.thread_id) { + bulk.threads.push(notification.body.thread_id) + } + if (notification.body.invited_by) { + bulk.users.push(notification.body.invited_by) + } + if (notification.body.organization_id) { + bulk.organizations.push(notification.body.organization_id) + } + } } - for (const notification of notifications.filter((notif) => includeRead || !notif.read)) { - // Group notifications of the same thread or project id + const reports = await getBulk('reports', bulk.reports) + for (const report of reports) { + if (report.item_type === 'project') { + bulk.projects.push(report.item_id) + } else if (report.item_type === 'user') { + bulk.users.push(report.item_id) + } else if (report.item_type === 'version') { + bulk.versions.push(report.item_id) + } + } + const versions = await getBulk('versions', bulk.versions) + for (const version of versions) { + bulk.projects.push(version.project_id) + } + const [projects, threads, users, organizations] = await Promise.all([ + getBulk('projects', bulk.projects), + getBulk('threads', bulk.threads), + getBulk('users', bulk.users), + getBulk('organizations', bulk.organizations, 3), + ]) + for (const notification of notifications) { + notification.extra_data = {} if (notification.body) { - const index = grouped.findIndex( - (notif) => - ((notif.body.thread_id === notification.body.thread_id && !!notif.body.thread_id) || - (notif.body.project_id === notification.body.project_id && !!notif.body.project_id)) && - notification.read === notif.read - ) - const notif = grouped[index] - if ( - notif && - (notification.body.type === 'moderator_message' || - notification.body.type === 'project_update') - ) { - let groupedNotifs = notif.grouped_notifs - if (!groupedNotifs) { - groupedNotifs = [] - } - groupedNotifs.push(notification) - grouped[index].grouped_notifs = groupedNotifs - } else { - grouped.push(notification) + if (notification.body.project_id) { + notification.extra_data.project = projects.find( + (x) => x.id === notification.body.project_id + ) } + if (notification.body.organization_id) { + notification.extra_data.organization = organizations.find( + (x) => x.id === notification.body.organization_id + ) + } + if (notification.body.report_id) { + notification.extra_data.report = reports.find((x) => x.id === notification.body.report_id) + + const type = notification.extra_data.report.item_type + if (type === 'project') { + notification.extra_data.project = projects.find( + (x) => x.id === notification.extra_data.report.item_id + ) + } else if (type === 'user') { + notification.extra_data.user = users.find( + (x) => x.id === notification.extra_data.report.item_id + ) + } else if (type === 'version') { + notification.extra_data.version = versions.find( + (x) => x.id === notification.extra_data.report.item_id + ) + notification.extra_data.project = projects.find( + (x) => x.id === notification.extra_data.version.project_id + ) + } + } + if (notification.body.thread_id) { + notification.extra_data.thread = threads.find((x) => x.id === notification.body.thread_id) + } + if (notification.body.invited_by) { + notification.extra_data.invited_by = users.find( + (x) => x.id === notification.body.invited_by + ) + } + if (notification.body.version_id) { + notification.extra_data.version = versions.find( + (x) => x.id === notification.body.version_id + ) + } + } + } + return notifications +} + +export function groupNotifications(notifications) { + const grouped = [] + + for (let i = 0; i < notifications.length; i++) { + const current = notifications[i] + const next = notifications[i + 1] + if (current.body && i < notifications.length - 1 && isSimilar(current, next)) { + current.grouped_notifs = [next] + + let j = i + 2 + while (j < notifications.length && isSimilar(current, notifications[j])) { + current.grouped_notifs.push(notifications[j]) + j++ + } + + grouped.push(current) + i = j - 1 // skip i to the last ungrouped } else { - grouped.push(notification) + grouped.push(current) } } return grouped } +function isSimilar(notifA, notifB) { + return !!notifA.body.project_id && notifA.body.project_id === notifB.body.project_id +} + export async function markAsRead(ids) { try { await useBaseFetch(`notifications?ids=${JSON.stringify([...new Set(ids)])}`, { diff --git a/pages/dashboard/index.vue b/pages/dashboard/index.vue index d4be50214..a0d59d708 100644 --- a/pages/dashboard/index.vue +++ b/pages/dashboard/index.vue @@ -28,12 +28,13 @@ projects.value.filter((project) => project.followers > 0).length ) -const allNotifs = groupNotifications(await fetchNotifications()) +const { data, refresh } = await useAsyncData(async () => { + const notifications = await useBaseFetch(`user/${auth.value.user.id}/notifications`) -const notifications = computed(() => allNotifs.slice(0, 3)) -const extraNotifs = computed(() => allNotifs.length - notifications.value.length) + const filteredNotifications = notifications.filter((notif) => !notif.read) + const slice = filteredNotifications.slice(0, 30) // send first 30 notifs to be grouped before trimming to 3 + + return fetchExtraNotificationData(slice).then((notifications) => { + notifications = groupNotifications(notifications).slice(0, 3) + return { notifications, extraNotifs: filteredNotifications.length - slice.length } + }) +}) + +const notifications = computed(() => { + if (data.value === null) { + return [] + } + return data.value.notifications +}) + +const extraNotifs = computed(() => (data.value ? data.value.extraNotifs : 0))