summaryrefslogtreecommitdiffstats
path: root/client/components/notifications
diff options
context:
space:
mode:
Diffstat (limited to 'client/components/notifications')
-rw-r--r--client/components/notifications/notification.jade10
-rw-r--r--client/components/notifications/notification.js28
-rw-r--r--client/components/notifications/notification.styl57
-rw-r--r--client/components/notifications/notificationIcon.jade53
-rw-r--r--client/components/notifications/notifications.jade5
-rw-r--r--client/components/notifications/notifications.js32
-rw-r--r--client/components/notifications/notifications.styl17
-rw-r--r--client/components/notifications/notificationsDrawer.jade20
-rw-r--r--client/components/notifications/notificationsDrawer.js53
-rw-r--r--client/components/notifications/notificationsDrawer.styl69
10 files changed, 344 insertions, 0 deletions
diff --git a/client/components/notifications/notification.jade b/client/components/notifications/notification.jade
new file mode 100644
index 00000000..c98bbdba
--- /dev/null
+++ b/client/components/notifications/notification.jade
@@ -0,0 +1,10 @@
+template(name='notification')
+ li.notification(class="{{#if read}}read{{/if}}")
+ .read-status
+ .materialCheckBox(class="{{#if read}}is-checked{{/if}}")
+ +notificationIcon(activityData)
+ .details
+ +activity(activity=activityData mode='none')
+ if read
+ .remove
+ a.fa.fa-trash
diff --git a/client/components/notifications/notification.js b/client/components/notifications/notification.js
new file mode 100644
index 00000000..89277520
--- /dev/null
+++ b/client/components/notifications/notification.js
@@ -0,0 +1,28 @@
+Template.notification.events({
+ 'click .read-status .materialCheckBox'() {
+ const update = {};
+ update[`profile.notifications.${this.index}.read`] = this.read
+ ? null
+ : Date.now();
+ Users.update(Meteor.userId(), { $set: update });
+ },
+ 'click .remove a'() {
+ Meteor.user().removeNotification(this.activityData._id);
+ },
+});
+
+Template.notification.helpers({
+ mode: 'board',
+ isOfActivityType(activityId, type) {
+ const activity = Activities.findOne(activityId);
+ return activity && activity.activityType === type;
+ },
+ activityType(activityId) {
+ const activity = Activities.findOne(activityId);
+ return activity ? activity.activityType : '';
+ },
+ activityUser(activityId) {
+ const activity = Activities.findOne(activityId);
+ return activity && activity.userId;
+ },
+});
diff --git a/client/components/notifications/notification.styl b/client/components/notifications/notification.styl
new file mode 100644
index 00000000..0cf0cfd5
--- /dev/null
+++ b/client/components/notifications/notification.styl
@@ -0,0 +1,57 @@
+#notifications-drawer
+ &.show-read .notification.read
+ display: flex
+
+ .notification
+ display: flex
+ float: none
+ padding: 12px 8px 8px
+ color: black
+ border-bottom: 1px solid #dbdbdb
+
+ &.read
+ display: none
+
+ .read-status
+ width: 30px
+
+ input
+ width: 24px
+ height: 24px
+
+ .activity-type
+ margin: 16px 0 0
+ width: 17px
+ height: 17px
+ font-size: 17px
+ display: block
+ color: #bbb
+
+ .details
+ width: calc(100% - 30px)
+
+ .activity
+ display: flex
+
+ .activity-desc
+ width: 100%;
+
+ .activity-comment
+ display: block
+ width: 100%
+ border-radius: 3px
+ background: #fff
+ text-decoration: none
+ box-shadow: 0 1px 2px rgba(0,0,0,0.2)
+ margin-top: 5px
+ padding: 5px
+
+ .activity-meta
+ display: block
+ font-size: 0.8em
+ color: #999
+ font-style: italic
+
+ .remove
+ a:hover
+ color #eb4646 !important
diff --git a/client/components/notifications/notificationIcon.jade b/client/components/notifications/notificationIcon.jade
new file mode 100644
index 00000000..04377606
--- /dev/null
+++ b/client/components/notifications/notificationIcon.jade
@@ -0,0 +1,53 @@
+template(name='notificationIcon')
+ if($in activityType 'deleteAttachment' 'addAttachment')
+ i.fa.fa-paperclip.activity-type(title="attachment")
+ else if($in activityType 'createBoard' 'importBoard')
+ i.fa.fa-chalkboard.activity-type(title="board")
+
+ else if($in activityType 'createCard' 'importCard' 'moveCard')
+ +cardNotificationIcon
+ else if($in activityType 'moveCardBoard' 'archivedCard' 'restoredCard')
+ +cardNotificationIcon
+ //- $in can only handle up to 3 cases so we have to break this case over 2 cases... use a simple template to keep it
+ //- DRY and consistant
+
+ else if($in activityType 'addChecklist' 'removedChecklist' 'completeChecklist')
+ +checklistNotificationIcon
+ else if($in activityType 'uncompleteChecklist')
+ +checklistNotificationIcon
+ //- $in can only handle up to 3 cases so we have to break this case over 2 cases... use a simple template to keep it
+ //- DRY and consistant
+
+ else if($in activityType 'checkedItem' 'uncheckedItem' 'addChecklistItem' 'removedChecklistItem')
+ i.fa.fa-check-square.activity-type(title="checklist item")
+ else if($in activityType 'addComment')
+ i.fa.fa-comment-o.activity-type(title="comment")
+ else if($in activityType 'createCustomField' 'setCustomField' 'unsetCustomField')
+ i.fa.fa-code.activity-type(title="custom field")
+ else if($in activityType 'addedLabel' 'removedLabel')
+ i.fa.fa-tag.activity-type(title="label")
+
+ else if($in activityType 'createList' 'removeList' 'archivedList')
+ +listNotificationIcon
+ else if($in activityType 'importList')
+ +listNotificationIcon
+ //- $in can only handle up to 3 cases so we have to break this case over 2 cases... use a simple template to keep it
+ //- DRY and consistant
+
+ //- elswhere in the app we use fa-trello to indicate lists...
+ //- i personally like fa-columns a bit better
+ else if($in activityType 'unjoinMember' 'addBoardMember' 'joinMember' 'removeBoardMember')
+ i.fa.fa-user.activity-type(title="member")
+ else if($in activityType 'createSwimlane' 'archivedSwimlane')
+ i.fa.fa-th-large.activity-type(title="swimlane")
+ else
+ i.fa.fa-bug.activity-type(title="can't find icon for #{activityType}")
+
+template(name='cardNotificationIcon')
+ i.fa.fa-clone.activity-type(title="card")
+
+template(name='checklistNotificationIcon')
+ i.fa.fa-list.activity-type(title="checklist")
+
+template(name='listNotificationIcon')
+ i.fa.fa-columns.activity-type(title="list")
diff --git a/client/components/notifications/notifications.jade b/client/components/notifications/notifications.jade
new file mode 100644
index 00000000..bf8acbbf
--- /dev/null
+++ b/client/components/notifications/notifications.jade
@@ -0,0 +1,5 @@
+template(name='notifications')
+ #notifications.board-header-btns.right
+ a.notifications-drawer-toggle.fa.fa-bell(class="{{#if $gt unreadNotifications 0}}alert{{/if}}")
+ if $.Session.get 'showNotificationsDrawer'
+ +notificationsDrawer(unreadNotifications=unreadNotifications)
diff --git a/client/components/notifications/notifications.js b/client/components/notifications/notifications.js
new file mode 100644
index 00000000..c0aa6cb5
--- /dev/null
+++ b/client/components/notifications/notifications.js
@@ -0,0 +1,32 @@
+// this hides the notifications drawer if anyone clicks off of the panel
+Template.body.events({
+ click(event) {
+ if (
+ !$(event.target).is('#notifications *') &&
+ Session.get('showNotificationsDrawer')
+ ) {
+ toggleNotificationsDrawer();
+ }
+ },
+});
+
+Template.notifications.helpers({
+ unreadNotifications() {
+ const notifications = Users.findOne(Meteor.userId()).notifications();
+ const unreadNotifications = _.filter(notifications, v => !v.read);
+ return unreadNotifications.length;
+ },
+});
+
+Template.notifications.events({
+ 'click .notifications-drawer-toggle'() {
+ toggleNotificationsDrawer();
+ },
+});
+
+export function toggleNotificationsDrawer() {
+ Session.set(
+ 'showNotificationsDrawer',
+ !Session.get('showNotificationsDrawer'),
+ );
+}
diff --git a/client/components/notifications/notifications.styl b/client/components/notifications/notifications.styl
new file mode 100644
index 00000000..710cd3f9
--- /dev/null
+++ b/client/components/notifications/notifications.styl
@@ -0,0 +1,17 @@
+#notifications
+ position: relative
+
+ .notifications-drawer-toggle
+ display: block
+ line-height: 28px
+ color: #f2f2f2
+ margin: 0 10px
+ width: 28px
+ height: 28px
+ text-align: center
+ border: 0
+ padding: 0
+
+ &.alert
+ background-color: #eb4646;
+
diff --git a/client/components/notifications/notificationsDrawer.jade b/client/components/notifications/notificationsDrawer.jade
new file mode 100644
index 00000000..fee6aef6
--- /dev/null
+++ b/client/components/notifications/notificationsDrawer.jade
@@ -0,0 +1,20 @@
+template(name='notificationsDrawer')
+ section#notifications-drawer(class="{{#if $.Session.get 'showReadNotifications'}}show-read{{/if}}")
+ .header
+ if $.Session.get 'showReadNotifications'
+ a.toggle-read {{_ 'filter-by-unread'}}
+ else
+ a.toggle-read {{_ 'view-all'}}
+ h5 {{_ 'notifications'}}
+ if($gt unreadNotifications 0)
+ |(#{unreadNotifications})
+ a.fa.fa-times-thin.close
+ ul.notifications
+ each transformedProfile.notifications
+ +notification(activityData=activity index=dbIndex read=read)
+ if($gt unreadNotifications 0)
+ a.all-read {{_ 'mark-all-as-read'}}
+ if ($and ($.Session.get 'showReadNotifications') ($gt readNotifications 0))
+ a.remove-read
+ i.fa.fa-trash
+ | {{_ 'remove-all-read'}}
diff --git a/client/components/notifications/notificationsDrawer.js b/client/components/notifications/notificationsDrawer.js
new file mode 100644
index 00000000..76abeea7
--- /dev/null
+++ b/client/components/notifications/notificationsDrawer.js
@@ -0,0 +1,53 @@
+import { toggleNotificationsDrawer } from './notifications.js';
+
+Template.notificationsDrawer.onCreated(function() {
+ Meteor.subscribe('notificationActivities');
+ Meteor.subscribe('notificationCards');
+ Meteor.subscribe('notificationUsers');
+ Meteor.subscribe('notificationsAttachments');
+ Meteor.subscribe('notificationChecklistItems');
+ Meteor.subscribe('notificationChecklists');
+ Meteor.subscribe('notificationComments');
+ Meteor.subscribe('notificationLists');
+ Meteor.subscribe('notificationSwimlanes');
+});
+
+Template.notificationsDrawer.helpers({
+ transformedProfile() {
+ return Users.findOne(Meteor.userId());
+ },
+ readNotifications() {
+ const readNotifications = _.filter(
+ Meteor.user().profile.notifications,
+ v => !!v.read,
+ );
+ return readNotifications.length;
+ },
+});
+
+Template.notificationsDrawer.events({
+ 'click .all-read'() {
+ const notifications = Meteor.user().profile.notifications;
+ for (const index in notifications) {
+ if (notifications.hasOwnProperty(index) && !notifications[index].read) {
+ const update = {};
+ update[`profile.notifications.${index}.read`] = Date.now();
+ Users.update(Meteor.userId(), { $set: update });
+ }
+ }
+ },
+ 'click .close'() {
+ toggleNotificationsDrawer();
+ },
+ 'click .toggle-read'() {
+ Session.set('showReadNotifications', !Session.get('showReadNotifications'));
+ },
+ 'click .remove-read'() {
+ const user = Meteor.user();
+ for (const notification of user.profile.notifications) {
+ if (notification.read) {
+ user.removeNotification(notification.activity);
+ }
+ }
+ },
+});
diff --git a/client/components/notifications/notificationsDrawer.styl b/client/components/notifications/notificationsDrawer.styl
new file mode 100644
index 00000000..f99e1299
--- /dev/null
+++ b/client/components/notifications/notificationsDrawer.styl
@@ -0,0 +1,69 @@
+belize = #2980b9
+
+section#notifications-drawer
+ position: fixed
+ top: 28px
+ right: 0
+ width: 400px
+ background-color: #fafafa
+ box-shadow: 0 1px 2px rgba(0,0,0,0.15)
+ border-radius: 2px
+ max-height: calc(100vh - 28px - 36px)
+ color: black
+ padding-top 36px
+
+ a:hover
+ color: belize !important
+
+ .header
+ position: fixed
+ top 28px
+ right 0
+ width calc(400px - 32px)
+ padding: 8px 16px
+ background: #ededed
+ border-bottom: 1px solid #dbdbdb
+ z-index 2
+
+ .toggle-read
+ position absolute
+ left 16px
+ top calc(50% - 8px)
+ color belize
+
+ h5
+ text-align: center
+ margin: 0
+
+ .close
+ position: absolute
+ top: calc(50% - 12px)
+ right: 12px
+ font-size: 24px
+ height: 24px
+ line-height: 24px
+ opacity 1
+
+ .all-read,
+ .remove-read
+ color belize
+ background-color: #fafafa
+ margin 8px 16px 12px
+ display inline-block
+
+ .remove-read
+ float right
+
+ &:hover
+ color #eb4646 !important
+
+ i.fa
+ color inherit
+
+
+ ul.notifications
+ display: block
+ padding: 0px 16px
+ margin: 0
+ height: calc(100vh - 102px)
+ overflow-y: scroll