-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
latest working component
<NotificationTray />
- Loading branch information
Temuulen Bayanmunkh
authored and
Temuulen Bayanmunkh
committed
Oct 20, 2023
1 parent
4f83cc5
commit 3af4b90
Showing
11 changed files
with
52,628 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<BasicDropdown @renderInPlace={{true}} @registerAPI={{this.registerAPI}} class="notification-tray" ...attributes as |dd|> | ||
<dd.Trigger class="btn btn-default btn-xs"> | ||
<FaIcon @icon="inbox" /> | ||
{{#if this.notifications.length}} | ||
<div class="notification-tray-unread-notifications-badge">{{this.notifications.length}}</div> | ||
{{/if}} | ||
</dd.Trigger> | ||
<dd.Content class="notification-tray-panel-container"> | ||
<div class="notification-tray-panel"> | ||
<div class="px-4"> | ||
<h1 class="mb-2 text-black dark:text-gray-100 text-base font-semibold pt-2 px-1">Unread Notifications</h1> | ||
<div class="h-48 overflow-y-scroll px-1"> | ||
{{#each this.notifications as |notification|}} | ||
<a href="javascript:;" class="notification-item" {{on "click" (fn this.onClickNotification notification)}}> | ||
<h3 class="font-semibold text-small">{{notification.data.subject}}</h3> | ||
<p class="text-xs mb-1.5">{{notification.data.message}}</p> | ||
<span class="text-xs">Received: {{notification.createdAgo}}</span> | ||
</a> | ||
{{else}} | ||
<div class="flex flex-1 items-center justify-center w-full h-full"> | ||
<span class="text-base text-gray-800 dark:text-gray-300 italic">No unread notifications</span> | ||
</div> | ||
{{/each}} | ||
</div> | ||
</div> | ||
<div class="px-2 py-1.5 border-t border-gray-200 dark:border-gray-700 flex flex-row space-x-4"> | ||
<a href="javascript:;" class="notification-tray-view-all-link" {{on "click" this.onPressViewAllNotifications}}>View all notification</a> | ||
</div> | ||
</div> | ||
|
||
</dd.Content> | ||
</BasicDropdown> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
import Component from '@glimmer/component'; | ||
import { tracked } from '@glimmer/tracking'; | ||
import { inject as service } from '@ember/service'; | ||
import { isArray } from '@ember/array'; | ||
import { action } from '@ember/object'; | ||
|
||
/** | ||
* NotificationTrayComponent is a Glimmer component for handling notifications. | ||
* | ||
* @class NotificationTrayComponent | ||
* @extends Component | ||
*/ | ||
export default class NotificationTrayComponent extends Component { | ||
/** | ||
* Inject the `socket` service. | ||
* | ||
* @memberof NotificationTrayComponent | ||
* @type {SocketService} | ||
*/ | ||
@service socket; | ||
|
||
/** | ||
* Inject the `store` service. | ||
* | ||
* @memberof NotificationTrayComponent | ||
* @type {StoreService} | ||
*/ | ||
@service store; | ||
|
||
/** | ||
* Inject the `fetch` service. | ||
* | ||
* @memberof NotificationTrayComponent | ||
* @type {FetchService} | ||
*/ | ||
@service fetch; | ||
|
||
/** | ||
* Inject the `currentUser` service. | ||
* | ||
* @memberof NotificationTrayComponent | ||
* @type {CurrentUserService} | ||
*/ | ||
@service currentUser; | ||
|
||
/** | ||
* An array to store notifications. | ||
* | ||
* @memberof NotificationTrayComponent | ||
* @type {Array} | ||
*/ | ||
@tracked notifications = []; | ||
|
||
/** | ||
* A boolean to track whether the notification tray is open or closed. | ||
* | ||
* @memberof NotificationTrayComponent | ||
* @type {boolean} | ||
*/ | ||
@tracked isOpen = false; | ||
|
||
/** | ||
* A reference to the notification sound. | ||
* | ||
* @memberof NotificationTrayComponent | ||
* @type {Audio} | ||
*/ | ||
notificationSound = new Audio('/sounds/notification-sound.mp3'); | ||
|
||
/** | ||
* Creates an instance of the NotificationTrayComponent | ||
*/ | ||
constructor() { | ||
super(...arguments); | ||
this.listenForNotificationFrom(`user.${this.currentUser.id}`); | ||
this.listenForNotificationFrom(`company.${this.currentUser.companyId}`); | ||
this.fetchNotificationsFromStore(); | ||
|
||
if (typeof this.args.onInitialize === 'function') { | ||
this.args.onInitialize(this.context); | ||
} | ||
} | ||
|
||
/** | ||
* Listens for notifications from a specific channel. | ||
* | ||
* @param {string} channelId - The channel to listen to. | ||
* @memberof NotificationTrayComponent | ||
*/ | ||
async listenForNotificationFrom(channelId) { | ||
// setup socket | ||
const socket = this.socket.instance(); | ||
|
||
// listen on company channel | ||
const channel = socket.subscribe(channelId); | ||
|
||
// listen to channel for events | ||
await channel.listener('subscribe').once(); | ||
|
||
// get incoming data and console out | ||
(async () => { | ||
for await (let incomingNotification of channel) { | ||
this.onReceivedNotification(incomingNotification); | ||
} | ||
})(); | ||
} | ||
|
||
/** | ||
* Handles a received notification by fetching the notification record and processing it. | ||
* | ||
* @param {Object} notificationData - The received notification data. | ||
* @param {string} notificationData.id - The unique identifier of the notification. | ||
* @returns {Promise} A promise that resolves after processing the notification. | ||
* @memberof NotificationTrayComponent | ||
*/ | ||
onReceivedNotification({ id }) { | ||
return this.getNotificationRecordUsingId(id).then((notification) => { | ||
// add to notifications array | ||
this.insertNotifications(notification); | ||
|
||
// trigger notification sound | ||
this.ping(); | ||
|
||
// handle callback | ||
if (typeof this.args.onReceivedNotification === 'function') { | ||
this.args.onReceivedNotification(notification); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Inserts one or more notifications into the notifications array, ensuring uniqueness. | ||
* | ||
* @param {Array|Object} notifications - The notification(s) to insert into the array. | ||
* @memberof NotificationTrayComponent | ||
*/ | ||
insertNotifications(notifications) { | ||
let _notifications = [...this.notifications]; | ||
|
||
if (isArray(notifications)) { | ||
_notifications.pushObjects(notifications); | ||
} else { | ||
_notifications.pushObject(notifications); | ||
} | ||
|
||
this.notifications = _notifications.filter(({ read_at }) => !read_at).uniqBy('id'); | ||
} | ||
|
||
/** | ||
* Fetches a notification record using its unique identifier. | ||
* | ||
* @param {string} id - The unique identifier of the notification. | ||
* @returns {Promise} A promise that resolves with the notification record. | ||
* @memberof NotificationTrayComponent | ||
*/ | ||
getNotificationRecordUsingId(id) { | ||
return this.store.findRecord('notification', id); | ||
} | ||
|
||
/** | ||
* Fetches notifications from the store. | ||
* | ||
* @memberof NotificationTrayComponent | ||
*/ | ||
fetchNotificationsFromStore() { | ||
this.store.query('notification', { sort: '-created_at', limit: 20, unread: true }).then((notifications) => { | ||
this.insertNotifications(notifications); | ||
|
||
if (typeof this.args.onNotificationsLoaded === 'function') { | ||
this.args.onNotificationsLoaded(notifications); | ||
} | ||
}); | ||
} | ||
|
||
/** | ||
* Handles the click event on a notification. | ||
* | ||
* @param {NotificationModel} notification - The clicked notification. | ||
* @returns {Promise} A promise that resolves after marking the notification as read. | ||
* @memberof NotificationTrayComponent | ||
*/ | ||
@action onClickNotification(notification) { | ||
notification.set('read_at', new Date()); | ||
return notification.save().then(() => { | ||
this.notifications.removeObject(notification); | ||
}); | ||
} | ||
|
||
/** | ||
* Registers the dropdown API. | ||
* | ||
* @param {DropdownApi} dropdownApi - The dropdown API instance. | ||
* @memberof NotificationTrayComponent | ||
*/ | ||
@action registerAPI(dropdownApi) { | ||
this.dropdownApi = dropdownApi; | ||
|
||
if (typeof this.args.registerAPI === 'function') { | ||
this.args.registerAPI(...arguments); | ||
} | ||
} | ||
|
||
/** | ||
* Handler for when "View all notifications" link is pressed in footer | ||
* | ||
* @returns {void} | ||
* @memberof NotificationTrayComponent | ||
*/ | ||
@action onPressViewAllNotifications() { | ||
if (typeof this.args.onPressViewAllNotifications === 'function') { | ||
this.args.onPressViewAllNotifications(); | ||
} | ||
} | ||
|
||
/** | ||
* Plays the notification sound. | ||
* | ||
* @memberof NotificationTrayComponent | ||
*/ | ||
ping() { | ||
this.notificationSound.play(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* Default styling for the notification tray container when it's closed */ | ||
.notification-tray { | ||
position: relative; | ||
display: flex; | ||
align-items: center; | ||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | ||
} | ||
|
||
/* Styling for the notification tray container when it's open in the light theme */ | ||
[data-theme='light'] .notification-tray.is-open { | ||
background-color: #ffffff; | ||
color: #000000; | ||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | ||
} | ||
|
||
/* Styling for the notification tray container when it's open in the dark theme */ | ||
[data-theme='dark'] .notification-tray.is-open { | ||
background-color: #333333; | ||
color: #ffffff; | ||
box-shadow: 0 2px 4px rgba(255, 255, 255, 0.1); /* Customize for the dark theme */ | ||
} | ||
|
||
/* Styling for the notification tray badge */ | ||
.notification-tray-unread-notifications-badge { | ||
position: absolute; | ||
top: -6px; | ||
right: -6px; | ||
width: 16px; | ||
height: 16px; | ||
background: red; | ||
color: white; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
border-radius: 50%; | ||
font-size: 10px; | ||
font-weight: bold; | ||
} | ||
|
||
/* Adding a hover effect for the badge */ | ||
.notification-tray-unread-notifications-badge:hover { | ||
background-color: darkred; | ||
cursor: pointer; | ||
} | ||
|
||
.notification-tray-panel { | ||
@apply mt-5 bg-white border border-gray-200 shadow-md rounded-lg dark:bg-gray-900 dark:border-gray-700 space-y-2 truncate; | ||
width: 300px; | ||
} | ||
|
||
.notification-tray-panel .notification-item { | ||
@apply flex flex-col rounded-md px-3 py-1.5 hover:bg-gray-100 dark:hover:bg-gray-800 truncate; | ||
} | ||
|
||
.notification-tray-view-all-link { | ||
@apply rounded px-2 py-1 text-sm text-gray-800 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-moregray-750; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from '@fleetbase/ember-ui/components/notification-tray'; |
Binary file not shown.
Binary file not shown.
Oops, something went wrong.