diff --git a/src/api/notification.js b/src/api/notification.js index 161868fb..3707318e 100644 --- a/src/api/notification.js +++ b/src/api/notification.js @@ -1,4 +1,5 @@ import { useGalleryStore, useNotificationStore } from '../stores'; +import { notificationRequest } from '.'; import { request } from '../service/request'; /** @@ -8,6 +9,10 @@ function getGalleryStore() { return useGalleryStore(); } +function getNotificationStore() { + return useNotificationStore(); +} + const notificationReq = { /** @typedef {{ * n: number, @@ -201,14 +206,20 @@ const notificationReq = { json, params }; - useNotificationStore().handleNotificationAccept(args); + getNotificationStore().handleNotificationAccept(args); return args; }) .catch((err) => { // if friend request could not be found, delete it if (err && err.message && err.message.includes('404')) { - useNotificationStore().handleNotificationHide({ params }); + getNotificationStore().handleNotificationHide( + params.notificationId + ); } + return { + json: null, + params + }; }); }, @@ -227,7 +238,41 @@ const notificationReq = { json, params }; - useNotificationStore().handleNotificationHide(args); + getNotificationStore().handleNotificationHide( + params.notificationId + ); + return args; + }); + }, + + /** + * @param {{ notificationId: string }} params + * @return { Promise<{json: any, params}> } + */ + seeNotification(params) { + return request(`auth/user/notifications/${params.notificationId}/see`, { + method: 'PUT' + }).then((json) => { + const args = { + json, + params + }; + return args; + }); + }, + + /** + * @param {{ notificationId: string }} params + * @return { Promise<{json: any, params}> } + */ + seeNotificationV2(params) { + return request(`notifications/${params.notificationId}/see`, { + method: 'POST' + }).then((json) => { + const args = { + json, + params + }; return args; }); }, @@ -244,7 +289,24 @@ const notificationReq = { return request(`notifications/${params.notificationId}/respond`, { method: 'POST', params - }); + }) + .then((json) => { + const args = { + json, + params + }; + return args; + }) + .catch(() => { + getNotificationStore().handleNotificationV2Hide( + params.notificationId + ); + notificationRequest.hideNotificationV2(params.notificationId); + return { + json: null, + params + }; + }); }, hideNotificationV2(notificationId) { diff --git a/src/components/dialogs/AvatarDialog/ChangeAvatarImageDialog.vue b/src/components/dialogs/AvatarDialog/ChangeAvatarImageDialog.vue index c0559200..401f471b 100644 --- a/src/components/dialogs/AvatarDialog/ChangeAvatarImageDialog.vue +++ b/src/components/dialogs/AvatarDialog/ChangeAvatarImageDialog.vue @@ -1,43 +1,45 @@ diff --git a/src/localization/en.json b/src/localization/en.json index 00adad3e..e1c58304 100644 --- a/src/localization/en.json +++ b/src/localization/en.json @@ -103,7 +103,7 @@ "tab_group": "Group", "tab_other": "Other", "past_notifications": "Past", - "no_notifications": "No notifications" + "no_new_notifications": "No new notifications" } }, "view": { @@ -334,7 +334,8 @@ }, "report": { "closed": "Moderation Report Closed" - } + }, + "contentrestriction": "Moderation Content Restriction" }, "instance": { "closed": "Instance Closed" diff --git a/src/service/database.js b/src/service/database.js index 4e6ce59d..afee3958 100644 --- a/src/service/database.js +++ b/src/service/database.js @@ -77,6 +77,9 @@ const database = { await sqliteService.executeNonQuery( `CREATE TABLE IF NOT EXISTS ${dbVars.userPrefix}_notifications (id TEXT PRIMARY KEY, created_at TEXT, type TEXT, sender_user_id TEXT, sender_username TEXT, receiver_user_id TEXT, message TEXT, world_id TEXT, world_name TEXT, image_url TEXT, invite_message TEXT, request_message TEXT, response_message TEXT, expired INTEGER)` ); + await sqliteService.executeNonQuery( + `CREATE TABLE IF NOT EXISTS ${dbVars.userPrefix}_notifications_v2 (id TEXT PRIMARY KEY, created_at TEXT, updated_at TEXT, expires_at TEXT, type TEXT, link TEXT, link_text TEXT, message TEXT, title TEXT, image_url TEXT, seen INTEGER, sender_user_id TEXT, sender_username TEXT, data TEXT, responses TEXT, details TEXT)` + ); await sqliteService.executeNonQuery( `CREATE TABLE IF NOT EXISTS ${dbVars.userPrefix}_moderation (user_id TEXT PRIMARY KEY, updated_at TEXT, display_name TEXT, block INTEGER, mute INTEGER)` ); diff --git a/src/service/database/notifications.js b/src/service/database/notifications.js index d7aecd28..23d484bb 100644 --- a/src/service/database/notifications.js +++ b/src/service/database/notifications.js @@ -151,6 +151,89 @@ const notifications = { '@expired': expired } ); + }, + + // notifications v2 + + async getNotificationsV2() { + const notifications = []; + await sqliteService.execute((dbRow) => { + const row = { + id: dbRow[0], + createdAt: dbRow[1], + updatedAt: dbRow[2], + expiresAt: dbRow[3], + type: dbRow[4], + link: dbRow[5], + linkText: dbRow[6], + message: dbRow[7], + title: dbRow[8], + imageUrl: dbRow[9], + seen: dbRow[10] === 1, + senderUserId: dbRow[11], + senderUsername: dbRow[12], + data: JSON.parse(dbRow[13] || '{}'), + responses: JSON.parse(dbRow[14] || '[]'), + details: JSON.parse(dbRow[15] || '{}') + }; + // for UI table + row.created_at = row.createdAt; + row.version = 2; + notifications.unshift(row); + }, `SELECT * FROM ${dbVars.userPrefix}_notifications_v2 ORDER BY created_at DESC LIMIT ${dbVars.maxTableSize}`); + return notifications; + }, + + addNotificationV2ToDatabase(entry) { + sqliteService.executeNonQuery( + `INSERT OR REPLACE INTO ${dbVars.userPrefix}_notifications_v2 (id, created_at, updated_at, expires_at, type, link, link_text, message, title, image_url, seen, sender_user_id, sender_username, data, responses, details) VALUES (@id, @created_at, @updated_at, @expires_at, @type, @link, @link_text, @message, @title, @image_url, @seen, @sender_user_id, @sender_username, @data, @responses, @details)`, + { + '@id': entry.id, + '@created_at': entry.createdAt, + '@updated_at': entry.updatedAt, + '@expires_at': entry.expiresAt, + '@type': entry.type, + '@link': entry.link, + '@link_text': entry.linkText, + '@message': entry.message, + '@title': entry.title, + '@image_url': entry.imageUrl, + '@seen': entry.seen ? 1 : 0, + '@sender_user_id': entry.senderUserId, + '@sender_username': entry.senderUsername, + '@data': JSON.stringify(entry.data || {}), + '@responses': JSON.stringify(entry.responses || []), + '@details': JSON.stringify(entry.details || {}) + } + ); + }, + + expireNotificationV2(id) { + sqliteService.executeNonQuery( + `UPDATE ${dbVars.userPrefix}_notifications_v2 SET expires_at = @expires_at, seen = 1 WHERE id = @id`, + { + '@id': id, + '@expires_at': new Date().toJSON() + } + ); + }, + + seenNotificationV2(id) { + sqliteService.executeNonQuery( + `UPDATE ${dbVars.userPrefix}_notifications_v2 SET seen = 1 WHERE id = @id`, + { + '@id': id + } + ); + }, + + deleteNotificationV2(id) { + sqliteService.executeNonQuery( + `DELETE FROM ${dbVars.userPrefix}_notifications_v2 WHERE id = @id`, + { + '@id': id + } + ); } }; diff --git a/src/service/request.js b/src/service/request.js index 4fc18ebf..e08aec8e 100644 --- a/src/service/request.js +++ b/src/service/request.js @@ -121,6 +121,13 @@ export function request(endpoint, options) { if (AppDebug.debugWebRequests) { console.log(init, 'parsed data', response.data); } + if (response.data.error) { + $throw( + response.data.error.status_code || 0, + response.data.error.message, + endpoint + ); + } return response; } catch (e) { console.error(e); diff --git a/src/service/websocket.js b/src/service/websocket.js index 3fafed1c..e4ba4c36 100644 --- a/src/service/websocket.js +++ b/src/service/websocket.js @@ -215,16 +215,8 @@ function handlePipeline(args) { case 'notification-v2-delete': console.log('notification-v2-delete', content); for (var id of content.ids) { - notificationStore.handleNotificationHide({ - params: { - notificationId: id - } - }); - notificationStore.handleNotificationSee({ - params: { - notificationId: id - } - }); + notificationStore.handleNotificationV2Hide(id); + notificationStore.handleNotificationSee(id); } break; @@ -239,37 +231,17 @@ function handlePipeline(args) { break; case 'see-notification': - notificationStore.handleNotificationSee({ - params: { - notificationId: content - } - }); + notificationStore.handleNotificationSee(content); break; case 'hide-notification': - notificationStore.handleNotificationHide({ - params: { - notificationId: content - } - }); - notificationStore.handleNotificationSee({ - params: { - notificationId: content - } - }); + notificationStore.handleNotificationHide(content); + notificationStore.handleNotificationSee(content); break; case 'response-notification': - notificationStore.handleNotificationHide({ - params: { - notificationId: content.notificationId - } - }); - notificationStore.handleNotificationSee({ - params: { - notificationId: content.notificationId - } - }); + notificationStore.handleNotificationHide(content.notificationId); + notificationStore.handleNotificationSee(content.notificationId); break; case 'friend-add': diff --git a/src/stores/notification.js b/src/stores/notification.js index 9a547c34..bab70441 100644 --- a/src/stores/notification.js +++ b/src/stores/notification.js @@ -4,6 +4,7 @@ import { toast } from 'vue-sonner'; import { useI18n } from 'vue-i18n'; import Noty from 'noty'; +import dayjs from 'dayjs'; import { checkCanInvite, @@ -23,8 +24,8 @@ import { userRequest, worldRequest } from '../api'; +import { database, dbVars } from '../service/database'; import { AppDebug } from '../service/appConfig'; -import { database } from '../service/database'; import { useAdvancedSettingsStore } from './settings/advanced'; import { useAppearanceSettingsStore } from './settings/appearance'; import { useFavoriteStore } from './favorite'; @@ -155,6 +156,11 @@ export const useNotificationStore = defineStore('Notification', () => { const { ref } = args; const array = notificationTable.value.data; const { length } = array; + if (ref.seen) { + removeFromArray(unseenNotifications.value, ref.id); + } else if (!unseenNotifications.value.includes(ref.id)) { + unseenNotifications.value.push(ref.id); + } for (let i = 0; i < length; ++i) { if (array[i].id === ref.id) { array[i] = ref; @@ -189,7 +195,6 @@ export const useNotificationStore = defineStore('Notification', () => { ) { uiStore.notifyMenu('notification'); } - unseenNotifications.value.push(ref.id); queueNotificationNoty(ref); sharedFeedStore.addEntry(ref); } @@ -206,30 +211,19 @@ export const useNotificationStore = defineStore('Notification', () => { D.incomingRequest = true; } - function handleNotificationHide(args) { - let ref; - const array = notificationTable.value.data; - for (let i = array.length - 1; i >= 0; i--) { - if (array[i].id === args.params.notificationId) { - ref = array[i]; - break; - } - } + function handleNotificationHide(notificationId) { + const ref = notificationTable.value.data.find( + (n) => n.id === notificationId + ); if (typeof ref === 'undefined') { return; } - args.ref = ref; if ( ref.type === 'friendRequest' || ref.type === 'ignoredFriendRequest' || ref.type.includes('.') ) { - for (let i = array.length - 1; i >= 0; i--) { - if (array[i].id === ref.id) { - array.splice(i, 1); - break; - } - } + removeFromArray(notificationTable.value.data, ref); } else { ref.$isExpired = true; database.updateNotificationExpired(ref); @@ -242,28 +236,6 @@ export const useNotificationStore = defineStore('Notification', () => { }); } - function handleNotificationV2Update(args) { - const notificationId = args.params.notificationId; - const json = args.json; - if (!json) { - return; - } - json.id = notificationId; - handleNotification({ - json, - params: { - notificationId - } - }); - if (json.seen) { - handleNotificationSee({ - params: { - notificationId - } - }); - } - } - function handlePipelineNotification(args) { const ref = args.json; if ( @@ -374,12 +346,18 @@ export const useNotificationStore = defineStore('Notification', () => { }); } - function handleNotificationSee(args) { - const { notificationId } = args.params; + function handleNotificationSee(notificationId) { removeFromArray(unseenNotifications.value, notificationId); if (unseenNotifications.value.length === 0) { uiStore.removeNotify('notification'); } + const ref = notificationTable.value.data.find( + (n) => n.id === notificationId + ); + if (ref) { + ref.seen = true; + } + database.seenNotificationV2(ref); } function handleNotificationAccept(args) { @@ -435,10 +413,11 @@ export const useNotificationStore = defineStore('Notification', () => { /** * - * @param {object} json + * @param {object} data * @returns {object} */ - function applyNotification(json) { + function applyNotification(data) { + const json = { ...data }; if (json.message) { json.message = replaceBioSymbols(json.message); } @@ -489,25 +468,117 @@ export const useNotificationStore = defineStore('Notification', () => { } ref.details = details; } - if (ref.type === 'boop') { + return ref; + } + + function applyNotificationV2(data) { + const json = { ...data }; + // delete any null in json + for (const key in json) { + if (json[key] === null || typeof json[key] === 'undefined') { + delete json[key]; + } + } + let ref = notificationTable.value.data.find((n) => n.id === json.id); + if (typeof ref === 'undefined') { + ref = { + id: '', + createdAt: '', + updatedAt: '', + expiresAt: '', + type: '', + link: '', + linkText: '', + message: '', + title: '', + imageUrl: '', + seen: false, + data: {}, + responses: [], + version: 2, + ...json + }; + } else { + Object.assign(ref, json); + } + ref.created_at = ref.createdAt; // for table + // legacy handling of boops + if (ref.type === 'boop' && ref.title) { ref.message = ref.title; + ref.title = ''; if (ref.details?.emojiId?.startsWith('default_')) { - ref.details.imageUrl = ref.details.emojiId; + ref.imageUrl = ref.details.emojiId; ref.message += ` ${ref.details.emojiId.replace('default_', '')}`; } else { - ref.details.imageUrl = `${AppDebug.endpointDomain}/file/${ref.details.emojiId}/${ref.details.emojiVersion}`; + ref.imageUrl = `${AppDebug.endpointDomain}/file/${ref.details.emojiId}/${ref.details.emojiVersion}`; } } return ref; } + function handleNotificationV2(args) { + const ref = applyNotificationV2(args.json); + if (ref.seen) { + removeFromArray(unseenNotifications.value, ref.id); + } else if (!unseenNotifications.value.includes(ref.id)) { + unseenNotifications.value.push(ref.id); + } + const existingNotification = notificationTable.value.data.find( + (n) => n.id === ref.id + ); + if (existingNotification) { + Object.assign(existingNotification, ref); + database.addNotificationV2ToDatabase(existingNotification); // update + return; + } + + if ( + notificationTable.value.filters[0].value.length === 0 || + notificationTable.value.filters[0].value.includes(ref.type) + ) { + uiStore.notifyMenu('notification'); + } + database.addNotificationV2ToDatabase(ref); + notificationTable.value.data.push(ref); + queueNotificationNoty(ref); + sharedFeedStore.addEntry(ref); + } + + function handleNotificationV2Update(args) { + const notificationId = args.params.notificationId; + const json = { ...args.json }; + if (!json) { + return; + } + json.id = notificationId; + handleNotificationV2({ + json, + params: { + notificationId + } + }); + if (json.seen) { + handleNotificationSee(notificationId); + } + } + + function handleNotificationV2Hide(notificationId) { + database.expireNotificationV2(notificationId); + const ref = notificationTable.value.data.find( + (n) => n.id === notificationId + ); + if (ref) { + ref.expiresAt = new Date().toJSON(); + ref.seen = true; + } + } + function expireFriendRequestNotifications() { const array = notificationTable.value.data; for (let i = array.length - 1; i >= 0; i--) { if ( array[i].type === 'friendRequest' || - array[i].type === 'ignoredFriendRequest' || - array[i].type.includes('.') + array[i].type === 'ignoredFriendRequest' ) { array.splice(i, 1); } @@ -540,22 +611,6 @@ export const useNotificationStore = defineStore('Notification', () => { }); } - function handleNotificationV2(args) { - const json = args.json; - json.created_at = json.createdAt; - if (json.title && json.message) { - json.message = `${json.title}, ${json.message}`; - } else if (json.title) { - json.message = json.title; - } - handleNotification({ - json, - params: { - notificationId: json.id - } - }); - } - /** * * @returns {Promise} @@ -581,7 +636,6 @@ export const useNotificationStore = defineStore('Notification', () => { } }); } - unseenNotifications.value = []; params.offset += 100; if (args.json.length < 100) { break; @@ -595,23 +649,14 @@ export const useNotificationStore = defineStore('Notification', () => { for (let i = 0; i < count; i++) { const args = await notificationRequest.getNotificationsV2(params); - for (const json of args.json) { - json.created_at = json.createdAt; - if (json.title && json.message) { - json.message = `${json.title}, ${json.message}`; - } else if (json.title) { - json.message = json.title; - } - handleNotification({ + handleNotificationV2({ json, params: { notificationId: json.id } }); } - - unseenNotifications.value = []; params.offset += 100; if (args.json.length < 100) { break; @@ -634,7 +679,6 @@ export const useNotificationStore = defineStore('Notification', () => { } }); } - unseenNotifications.value = []; params.offset += 100; if (args.json.length < 100) { break; @@ -2412,7 +2456,16 @@ export const useNotificationStore = defineStore('Notification', () => { async function initNotifications() { notificationInitStatus.value = false; - notificationTable.value.data = await database.getNotifications(); + let tableData = await database.getNotificationsV2(); + let notifications = await database.getNotifications(); + tableData = tableData.concat( + notifications.filter((n) => !tableData.some((t) => t.id === n.id)) + ); + tableData.sort( + (a, b) => Date.parse(b.created_at) - Date.parse(a.created_at) + ); + tableData.splice(dbVars.maxTableSize); + notificationTable.value.data = tableData; refreshNotifications(); } @@ -2441,11 +2494,11 @@ export const useNotificationStore = defineStore('Notification', () => { async function hideNotification(row) { if (row.type === 'ignoredFriendRequest') { - const args = await friendRequest.deleteHiddenFriendRequest( + await friendRequest.deleteHiddenFriendRequest( { notificationId: row.id }, row.senderUserId ); - handleNotificationHide(args); + handleNotificationHide(row.id); } else { notificationRequest.hideNotification({ notificationId: row.id @@ -2516,23 +2569,15 @@ export const useNotificationStore = defineStore('Notification', () => { } } const params = { notificationId, responseType, responseData }; - notificationRequest - .sendNotificationResponse(params) - .then((json) => { - if (!json) return; - const args = { json, params }; - handleNotificationHide(args); - new Noty({ - type: 'success', - text: escapeTag(args.json) - }).show(); - }) - .catch((err) => { - handleNotificationHide({ params }); - notificationRequest.hideNotificationV2(params.notificationId); - console.error('Notification response failed', err); - toast.error(t('message.error')); - }); + notificationRequest.sendNotificationResponse(params).then((args) => { + console.log('Notification response', args); + if (!args.json) return; + handleNotificationV2Hide(notificationId); + new Noty({ + type: 'success', + text: escapeTag(args.json) + }).show(); + }); } function deleteNotificationLog(row) { @@ -2546,7 +2591,11 @@ export const useNotificationStore = defineStore('Notification', () => { row.type !== 'friendRequest' && row.type !== 'ignoredFriendRequest' ) { - database.deleteNotification(row.id); + if (!row.version || row.version < 2) { + database.deleteNotification(row.id); + } else { + database.deleteNotificationV2(row.id); + } } } @@ -2562,6 +2611,49 @@ export const useNotificationStore = defineStore('Notification', () => { .catch(() => {}); } + function isNotificationExpired(notification) { + if (notification.$isExpired !== undefined) { + return notification.$isExpired; + } + if (!notification.expiresAt) { + return false; + } + const expiresAt = dayjs(notification.expiresAt); + return expiresAt.isValid() && dayjs().isSameOrAfter(expiresAt); + } + + function openNotificationLink(link) { + if (!link) { + return; + } + const data = link.split(':'); + if (!data.length) { + return; + } + switch (data[0]) { + case 'group': + groupStore.showGroupDialog(data[1]); + break; + case 'user': + userStore.showUserDialog(data[1]); + break; + case 'event': + const ids = data[1].split(','); + if (ids.length < 2) { + console.error('Invalid event notification link:', data[1]); + return; + } + + groupStore.showGroupDialog(ids[0]); + // ids[1] cal_ is the event id + break; + case 'openNotificationLink': + default: + toast.error('Unsupported notification link type'); + break; + } + } + return { notificationInitStatus, notificationTable, @@ -2582,6 +2674,7 @@ export const useNotificationStore = defineStore('Notification', () => { handlePipelineNotification, handleNotificationV2Update, handleNotificationHide, + handleNotificationV2Hide, handleNotification, handleNotificationV2, testNotification, @@ -2600,6 +2693,8 @@ export const useNotificationStore = defineStore('Notification', () => { groupNotifications, otherNotifications, hasUnseenNotifications, - getNotificationCategory + getNotificationCategory, + isNotificationExpired, + openNotificationLink }; }); diff --git a/src/stores/sharedFeed.js b/src/stores/sharedFeed.js index 3cbd1c38..13763877 100644 --- a/src/stores/sharedFeed.js +++ b/src/stores/sharedFeed.js @@ -93,9 +93,9 @@ export const useSharedFeedStore = defineStore('SharedFeed', () => { ); watch( - () => watchState.isLoggedIn, - (isLoggedIn) => { - if (isLoggedIn) { + () => [watchState.isFriendsLoaded, watchState.isFavoritesLoaded], + ([isFriendsLoaded, isFavoritesLoaded]) => { + if (isFriendsLoaded && isFavoritesLoaded) { sharedFeedData.value = []; loadSharedFeed(); } diff --git a/src/views/Notifications/Notification.vue b/src/views/Notifications/Notification.vue index 4e67efa7..7f1db298 100644 --- a/src/views/Notifications/Notification.vue +++ b/src/views/Notifications/Notification.vue @@ -42,7 +42,9 @@ 'group.queueReady', 'moderation.warning.group', 'moderation.report.closed', - 'instance.closed' + 'moderation.contentrestriction', + 'instance.closed', + 'economy.alert' ]" :key="type" :value="type"> @@ -89,7 +91,6 @@ import { RefreshCw } from 'lucide-vue-next'; import { Spinner } from '@/components/ui/spinner'; import { storeToRefs } from 'pinia'; - import { toast } from 'vue-sonner'; import { useI18n } from 'vue-i18n'; import dayjs from 'dayjs'; @@ -97,10 +98,8 @@ import { useAppearanceSettingsStore, useGalleryStore, - useGroupStore, useInviteStore, useNotificationStore, - useUserStore, useVrcxStore } from '../../stores'; import { DataTableLayout } from '../../components/ui/data-table'; @@ -113,8 +112,6 @@ import SendInviteResponseDialog from './dialogs/SendInviteResponseDialog.vue'; import configRepository from '../../service/config'; - const { showUserDialog } = useUserStore(); - const { showGroupDialog } = useGroupStore(); const { refreshInviteMessageTableData } = useInviteStore(); const { clearInviteImageUpload } = useGalleryStore(); const { notificationTable, isNotificationsLoading } = storeToRefs(useNotificationStore()); @@ -126,7 +123,8 @@ acceptRequestInvite, sendNotificationResponse, deleteNotificationLog, - deleteNotificationLogPrompt + deleteNotificationLogPrompt, + openNotificationLink } = useNotificationStore(); const { showFullscreenImageDialog } = useGalleryStore(); const appearanceSettingsStore = useAppearanceSettingsStore(); @@ -294,38 +292,6 @@ saveTableFilters(); } - function openNotificationLink(link) { - if (!link) { - return; - } - const data = link.split(':'); - if (!data.length) { - return; - } - switch (data[0]) { - case 'group': - showGroupDialog(data[1]); - break; - case 'user': - showUserDialog(data[1]); - break; - case 'event': - const ids = data[1].split(','); - if (ids.length < 2) { - console.error('Invalid event notification link:', data[1]); - return; - } - - showGroupDialog(ids[0]); - // ids[1] cal_ is the event id - break; - case 'openNotificationLink': - default: - toast.error('Unsupported notification link type'); - break; - } - } - function getSmallThumbnailUrl(url) { return convertFileUrlToImageUrl(url); } diff --git a/src/views/Notifications/columns.jsx b/src/views/Notifications/columns.jsx index 2c92e3e3..133890bc 100644 --- a/src/views/Notifications/columns.jsx +++ b/src/views/Notifications/columns.jsx @@ -29,7 +29,8 @@ import { useLocationStore, useUiStore, useUserStore, - useWorldStore + useWorldStore, + useNotificationStore } from '../../stores'; import Emoji from '../../components/Emoji.vue'; @@ -61,6 +62,7 @@ export const createColumns = ({ const { currentUser } = storeToRefs(useUserStore()); const { lastLocation } = storeToRefs(useLocationStore()); const { isGameRunning } = storeToRefs(useGameStore()); + const { isNotificationExpired } = useNotificationStore(); const canInvite = () => { const location = lastLocation.value?.location; @@ -385,7 +387,8 @@ export const createColumns = ({ cell: ({ row }) => { const original = row.original; if (original.type === 'boop') { - const imageUrl = original.details?.imageUrl; + const imageUrl = + original.details?.imageUrl || original.imageUrl; if (!imageUrl || imageUrl.startsWith('default_')) { return null; } @@ -455,7 +458,28 @@ export const createColumns = ({ /> ) : null} + {original.message && original.title ? ( + + + {`${original.title}, ${original.message}`} + + + ) : null} + {!original.message && original.title ? ( + + + {original.title} + + + ) : null} {original.message && + !original.title && original.message !== `This is a generated invite to ${original.details?.worldName}` ? ( {original.senderUserId !== currentUser.value?.id && - !original.$isExpired ? ( + !isNotificationExpired(original) ? ( {original.type === 'friendRequest' ? ( diff --git a/src/views/Sidebar/components/NotificationCenterSheet.vue b/src/views/Sidebar/components/NotificationCenterSheet.vue index ec8b43ec..1000bdb4 100644 --- a/src/views/Sidebar/components/NotificationCenterSheet.vue +++ b/src/views/Sidebar/components/NotificationCenterSheet.vue @@ -92,9 +92,9 @@ const activeTab = ref('friend'); const activeCount = computed(() => ({ - friend: friendNotifications.value.filter((n) => !n.$isExpired).length, - group: groupNotifications.value.filter((n) => !n.$isExpired).length, - other: otherNotifications.value.filter((n) => !n.$isExpired).length + friend: friendNotifications.value.length, + group: groupNotifications.value.length, + other: otherNotifications.value.length })); // Dialog state diff --git a/src/views/Sidebar/components/NotificationItem.vue b/src/views/Sidebar/components/NotificationItem.vue index a8b797f2..ddeab284 100644 --- a/src/views/Sidebar/components/NotificationItem.vue +++ b/src/views/Sidebar/components/NotificationItem.vue @@ -1,8 +1,5 @@