FEATURE: Add a radial ping when user's first notification has not been read.

This commit is contained in:
Guo Xiang Tan 2016-11-08 16:12:40 +08:00
parent ac2c035856
commit a8b7599d4a
7 changed files with 71 additions and 2 deletions

View File

@ -41,6 +41,7 @@ export default {
user.set('unread_notifications', data.unread_notifications); user.set('unread_notifications', data.unread_notifications);
user.set('unread_private_messages', data.unread_private_messages); user.set('unread_private_messages', data.unread_private_messages);
user.set('read_first_notification', data.read_first_notification);
if (oldUnread !== data.unread_notifications || oldPM !== data.unread_private_messages) { if (oldUnread !== data.unread_notifications || oldPM !== data.unread_private_messages) {
appEvents.trigger('notifications:changed'); appEvents.trigger('notifications:changed');

View File

@ -42,6 +42,8 @@ createWidget('header-notifications', {
const unreadPMs = currentUser.get('unread_private_messages'); const unreadPMs = currentUser.get('unread_private_messages');
if (!!unreadPMs) { if (!!unreadPMs) {
if (!currentUser.get('read_first_notification')) contents.push(h('span.ring'));
contents.push(this.attach('link', { action: attrs.action, contents.push(this.attach('link', { action: attrs.action,
className: 'badge-notification unread-private-messages', className: 'badge-notification unread-private-messages',
rawLabel: unreadPMs })); rawLabel: unreadPMs }));

View File

@ -166,6 +166,43 @@ body {
&.badge-notification[href] {color: $secondary;} &.badge-notification[href] {color: $secondary;}
} }
.ring {
top: -13.4px !important;
right: 22.4px !important;
border-radius: 15px;
width: 20px;
height: 20px;
border: solid #FF0000 1px;
-moz-animation-iteration-count: infinite;
-webkit-animation-iteration-count: infinite;
-webkit-transform-origin: center;
-moz-animation-duration: 3s;
-webkit-animation-duration: 3s;
-moz-animation-name: ping;
-webkit-animation-name: ping;
}
@-webkit-keyframes ping {
from {
$scale: 0.25;
transform: scale($scale);
-ms-transform: scale($scale);
-webkit-transform: scale($scale);
-o-transform: scale($scale);
-moz-transform: scale($scale);
opacity: 1;
}
to {
$scale: 2.5;
transform: scale($scale);
-ms-transform: scale($scale);
-webkit-transform: scale($scale);
-o-transform: scale($scale);
-moz-transform: scale($scale);
opacity: 0;
}
}
.fade { .fade {
opacity: 0; opacity: 0;
transition: opacity 0.15s linear; transition: opacity 0.15s linear;

View File

@ -123,7 +123,7 @@
.notifications { .notifications {
position: relative; position: relative;
} }
.badge-notification { .badge-notification, .ring {
position: absolute; position: absolute;
top: -9px; top: -9px;
z-index: 1; z-index: 1;
@ -133,7 +133,7 @@
right: 0; right: 0;
background-color: scale-color($tertiary, $lightness: 50%); background-color: scale-color($tertiary, $lightness: 50%);
} }
.unread-private-messages { .unread-private-messages, .ring {
right: 25px; right: 25px;
} }
.flagged-posts { .flagged-posts {

View File

@ -343,6 +343,10 @@ class User < ActiveRecord::Base
end end
end end
def read_first_notification?
notifications.order(created_at: :asc).first.read
end
def publish_notifications_state def publish_notifications_state
# publish last notification json with the message so we # publish last notification json with the message so we
# can apply an update # can apply an update
@ -384,6 +388,7 @@ class User < ActiveRecord::Base
{unread_notifications: unread_notifications, {unread_notifications: unread_notifications,
unread_private_messages: unread_private_messages, unread_private_messages: unread_private_messages,
total_unread_notifications: total_unread_notifications, total_unread_notifications: total_unread_notifications,
read_first_notification: read_first_notification?,
last_notification: json, last_notification: json,
recent: recent, recent: recent,
seen_notification_id: seen_notification_id seen_notification_id: seen_notification_id

View File

@ -6,6 +6,7 @@ class CurrentUserSerializer < BasicUserSerializer
:total_unread_notifications, :total_unread_notifications,
:unread_notifications, :unread_notifications,
:unread_private_messages, :unread_private_messages,
:read_first_notification?,
:admin?, :admin?,
:notification_channel_position, :notification_channel_position,
:site_flagged_posts_count, :site_flagged_posts_count,

View File

@ -1314,4 +1314,27 @@ describe User do
end end
end end
describe '#read_first_notification?' do
let(:user) { Fabricate(:user) }
let(:notification) { Fabricate(:private_message_notification, user: user) }
let(:other_notification) { Fabricate(:private_message_notification, user: user) }
describe 'when first notification has not been read' do
it 'should return the right value' do
notification.update_attributes!(read: false)
other_notification.update_attributes!(read: true)
expect(user.read_first_notification?).to eq(false)
end
end
describe 'when first notification has been read' do
it 'should return the right value' do
notification.update_attributes!(read: true)
other_notification.update_attributes!(read: false)
expect(user.read_first_notification?).to eq(true)
end
end
end
end end