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_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) {
appEvents.trigger('notifications:changed');

View File

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

View File

@ -166,6 +166,43 @@ body {
&.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 {
opacity: 0;
transition: opacity 0.15s linear;

View File

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

View File

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

View File

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

View File

@ -1314,4 +1314,27 @@ describe User do
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