From 43612ed3484a9ac7bfcf66596ab852a64740fe28 Mon Sep 17 00:00:00 2001 From: Alex Jin <57976479+Silver-IT@users.noreply.github.com> Date: Fri, 26 Jul 2024 13:15:46 -0700 Subject: [PATCH] Allow users to force notifications to be marked as read (#2248) * feat: allow users to force notifications to be marked as read * fix: load identity KV store after login complete * fix: error handler * chore: Cypress retry * chore: Cypress retry * chore: Cypress retry * feat: load identity KV store after the connection is re-established * chore: add message after rejoining * chore: tiny updates * Reverted changes to group-chat.spec.js + updated group-proposals.spec.js + improvements + Reverted changes to group-chat.spec.js because they weren't fixing anything and the tests are passing locally on my machine + Updated group-proposals.spec.js to fix a weird possible Heisenbug by enabling a bypassUI (because that test was failing on my machine) + Updated main.js to emit ONLINE for online event handler as well + added related console.info logging * attempt to 'fix' heisenbug * update news and add comment * fix linter errors --------- Co-authored-by: Greg Slepak --- frontend/controller/actions/identity-kv.js | 24 ++++++++++++++----- frontend/controller/actions/identity.js | 2 -- frontend/main.js | 10 +++++++- frontend/utils/events.js | 1 + .../global-dashboard/NewsAndUpdates.vue | 10 +++++--- test/cypress/integration/group-chat.spec.js | 3 ++- .../integration/group-proposals.spec.js | 2 +- test/cypress/support/commands.js | 6 ++--- 8 files changed, 41 insertions(+), 17 deletions(-) diff --git a/frontend/controller/actions/identity-kv.js b/frontend/controller/actions/identity-kv.js index e973863a3..4776e87d0 100644 --- a/frontend/controller/actions/identity-kv.js +++ b/frontend/controller/actions/identity-kv.js @@ -1,16 +1,24 @@ 'use strict' import sbp from '@sbp/sbp' import { KV_KEYS } from '~/frontend/utils/constants.js' -import { KV_QUEUE } from '~/frontend/utils/events.js' +import { KV_QUEUE, ONLINE } from '~/frontend/utils/events.js' import { isExpired } from '@model/notifications/utils.js' const initNotificationStatus = (data = {}) => ({ ...data, read: false }) +sbp('okTurtles.events/on', ONLINE, () => { + sbp('gi.actions/identity/kv/load').catch(e => { + console.error("Error from 'gi.actions/identity/kv/load' after reestablished connection:", e) + }) +}) + export default (sbp('sbp/selectors/register', { 'gi.actions/identity/kv/load': async () => { + console.info('loading data from identity key-value store...') await sbp('gi.actions/identity/kv/loadChatRoomUnreadMessages') await sbp('gi.actions/identity/kv/loadPreferences') await sbp('gi.actions/identity/kv/loadNotificationStatus') + console.info('identity key-value store data loaded!') }, // Unread Messages 'gi.actions/identity/kv/fetchChatRoomUnreadMessages': async () => { @@ -279,13 +287,17 @@ export default (sbp('sbp/selectors/register', { const currentData = await sbp('gi.actions/identity/kv/fetchNotificationStatus') let isUpdated = false for (const hash of hashes) { + const existing = notifications.find(n => n.hash === hash) if (!currentData[hash]) { - const existing = notifications.find(n => n.hash === hash) - if (existing) { - currentData[hash] = initNotificationStatus({ timestamp: existing.timestamp }) - } + currentData[hash] = initNotificationStatus({ timestamp: existing.timestamp }) } - if (currentData[hash].read === false) { + + const isUnRead = currentData[hash].read === false + // NOTE: sometimes the value from KV store could be different from the one + // from client Vuex store when the device is offline or on bad network + // in this case, we need to allow users to force the notifications to be marked as read + const isDifferent = currentData[hash].read !== existing.read + if (isUnRead || isDifferent) { currentData[hash].read = true isUpdated = true } diff --git a/frontend/controller/actions/identity.js b/frontend/controller/actions/identity.js index 135a39597..0e19c7ca1 100644 --- a/frontend/controller/actions/identity.js +++ b/frontend/controller/actions/identity.js @@ -254,8 +254,6 @@ export default (sbp('sbp/selectors/register', { await sbp('gi.db/settings/save', SETTING_CURRENT_USER, identityContractID) sbp('okTurtles.events/emit', LOGIN, { identityContractID, encryptionParams, state }) - await sbp('gi.actions/identity/kv/load') - const contractIDs = groupContractsByType(cheloniaState?.contracts) await syncContractsInOrder(identityContractID, contractIDs) diff --git a/frontend/main.js b/frontend/main.js index 0c7377b64..89f038e29 100644 --- a/frontend/main.js +++ b/frontend/main.js @@ -27,7 +27,7 @@ import './controller/service-worker.js' import manifests from './model/contracts/manifests.json' import { SETTING_CURRENT_USER } from './model/database.js' import store from './model/state.js' -import { CHATROOM_USER_STOP_TYPING, CHATROOM_USER_TYPING, LOGIN_COMPLETE, LOGIN_ERROR, LOGOUT, SWITCH_GROUP, THEME_CHANGE } from './utils/events.js' +import { CHATROOM_USER_STOP_TYPING, CHATROOM_USER_TYPING, LOGIN_COMPLETE, LOGIN_ERROR, LOGOUT, ONLINE, SWITCH_GROUP, THEME_CHANGE } from './utils/events.js' import AppStyles from './views/components/AppStyles.vue' import BannerGeneral from './views/components/banners/BannerGeneral.vue' import Modal from './views/components/modal/Modal.vue' @@ -434,6 +434,10 @@ async function startApp () { } this.ephemeral.finishedLogin = 'yes' + sbp('gi.actions/identity/kv/load').catch(e => { + console.error("Error from 'gi.actions/identity/kv/load' during login:", e) + }) + if (this.$store.state.currentGroupId) { this.initOrResetPeriodicNotifications() this.checkAndEmitOneTimeNotifications() @@ -479,6 +483,8 @@ async function startApp () { }, online () { sbp('gi.ui/clearBanner') + sbp('okTurtles.events/emit', ONLINE) + console.info('back online!') }, 'reconnection-attempt' () { sbp('gi.ui/showBanner', L('Trying to reconnect...'), 'wifi') @@ -488,6 +494,8 @@ async function startApp () { }, 'reconnection-succeeded' () { sbp('gi.ui/clearBanner') + sbp('okTurtles.events/emit', ONLINE) + console.info('reconnected to pubsub!') }, 'subscription-succeeded' (event) { const { channelID } = event.detail diff --git a/frontend/utils/events.js b/frontend/utils/events.js index 90bfa1420..e36a7ef20 100644 --- a/frontend/utils/events.js +++ b/frontend/utils/events.js @@ -9,6 +9,7 @@ export const LOGIN = 'login' export const LOGIN_ERROR = 'login-error' export const LOGIN_COMPLETE = 'login-complete' export const LOGOUT = 'logout' +export const ONLINE = 'online' export const ACCEPTED_GROUP = 'accepted-group' export const SWITCH_GROUP = 'switch-group' diff --git a/frontend/views/containers/global-dashboard/NewsAndUpdates.vue b/frontend/views/containers/global-dashboard/NewsAndUpdates.vue index 2211388ee..d9f50dec6 100644 --- a/frontend/views/containers/global-dashboard/NewsAndUpdates.vue +++ b/frontend/views/containers/global-dashboard/NewsAndUpdates.vue @@ -1,6 +1,6 @@