diff --git a/src/api/common/notify.ts b/src/api/common/notify.ts index e7ec37d4e4..4b3e6a5d54 100644 --- a/src/api/common/notify.ts +++ b/src/api/common/notify.ts @@ -27,4 +27,12 @@ export default ( // Publish notification event event(notifiee, 'notification', await serialize(notification)); + + // 3秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する + setTimeout(async () => { + const fresh = await Notification.findOne({ _id: notification._id }, { is_read: true }); + if (!fresh.is_read) { + event(notifiee, 'unread_notification', await serialize(notification)); + } + }, 3000); }); diff --git a/src/web/app/desktop/tags/ui.tag b/src/web/app/desktop/tags/ui.tag index f7e1bf7463..908257620e 100644 --- a/src/web/app/desktop/tags/ui.tag +++ b/src/web/app/desktop/tags/ui.tag @@ -214,7 +214,9 @@ </mk-ui-header-post-button> <mk-ui-header-notifications> - <button class="header" data-active={ isOpen } onclick={ toggle } title="%i18n:desktop.tags.mk-ui-header-notifications.title%"><i class="fa fa-bell-o"></i></button> + <button data-active={ isOpen } onclick={ toggle } title="%i18n:desktop.tags.mk-ui-header-notifications.title%"> + <i class="fa fa-bell-o icon"></i><i class="fa fa-circle badge" if={ hasUnreadNotifications }></i> + </button> <div class="notifications" if={ isOpen }> <mk-notifications/> </div> @@ -223,7 +225,7 @@ display block float left - > .header + > button display block margin 0 padding 0 @@ -243,10 +245,16 @@ &:active color darken(#9eaba8, 30%) - > i + > .icon font-size 1.2em line-height 48px + > .badge + margin-left -5px + vertical-align super + font-size 10px + color $theme-color + > .notifications display block position absolute @@ -290,8 +298,53 @@ <script> import contains from '../../common/scripts/contains'; + this.mixin('i'); + this.mixin('api'); + + if (this.SIGNIN) { + this.mixin('stream'); + this.connection = this.stream.getConnection(); + this.connectionId = this.stream.use(); + } + this.isOpen = false; + this.on('mount', () => { + if (this.SIGNIN) { + this.connection.on('read_all_notifications', this.onReadAllNotifications); + this.connection.on('unread_notification', this.onUnreadNotification); + + // Fetch count of unread notifications + this.api('notifications/get_unread_count').then(res => { + if (res.count > 0) { + this.update({ + hasUnreadNotifications: true + }); + } + }); + } + }); + + this.on('unmount', () => { + if (this.SIGNIN) { + this.connection.off('read_all_notifications', this.onReadAllNotifications); + this.connection.off('unread_notification', this.onUnreadNotification); + this.stream.dispose(this.connectionId); + } + }); + + this.onReadAllNotifications = () => { + this.update({ + hasUnreadNotifications: false + }); + }; + + this.onUnreadNotification = () => { + this.update({ + hasUnreadNotifications: true + }); + }; + this.toggle = () => { this.isOpen ? this.close() : this.open(); }; @@ -424,9 +477,11 @@ this.mixin('i'); this.mixin('api'); - this.mixin('stream'); - this.connection = this.stream.getConnection(); - this.connectionId = this.stream.use(); + if (this.SIGNIN) { + this.mixin('stream'); + this.connection = this.stream.getConnection(); + this.connectionId = this.stream.use(); + } this.page = this.opts.page;