@magicbell/core
Version:
Official MagicBell API wrapper
141 lines (113 loc) • 3.81 kB
text/typescript
import camelize from '../lib/decorators/camelize.js';
import Notification from '../models/Notification/index.js';
import NotificationFactory from '../models/Notification/NotificationFactory.js';
import NotificationRepository from '../models/Notification/NotificationRepository.js';
import RemoteStore from './RemoteStore.js';
export type NotificationStoreAttrs = {
items: Notification[] | any[];
total: number;
totalPages: number;
currentPage: number;
perPage: number;
unseenCount: number;
unreadCount: number;
};
/**
* A synced collection, or store, of notifications.
*
* @example
* const store = new NotificationStore()
*/
export default class NotificationStore extends RemoteStore<Notification> {
unseenCount = 0;
unreadCount = 0;
repo: NotificationRepository;
constructor(attrs = {}) {
super();
this.set(attrs);
this.repo = new NotificationRepository();
}
get notifications() {
return this.items;
}
/**
* Create a notification, store it in the API server and add it to the store.
*
* @param data Data of the notification.
*/
create = async (data): Promise<Notification> => {
const notification = await Notification.create(data);
this.push(notification);
return notification;
};
/**
* Mark all notifications as read. Resets the `unreadCount` attribute.
*
* @param omitRequest Update notifications locally only.
*/
markAllAsRead = async ({ omitRequest = false } = {}) => {
this.unreadCount = 0;
// @TODO Remove the deep observer so the items array changes only after
// the action is completed. In the meantime we clone the items array.
for (const notification of this.items.slice()) notification.isRead = true;
if (!omitRequest) return this.repo.markAllAsRead();
};
/**
* Mark all notifications as seen. Resets the `unseenCount` attribute.
*
* @param omitRequest Update notifications locally only.
* @param updateItems Mark all notifications as seen.
*/
markAllAsSeen = async ({ omitRequest = false, updateItems = true } = {}) => {
this.unseenCount = 0;
if (updateItems) {
// @TODO Remove the deep observer so the items array changes only after
// the action is completed. In the meantime we clone the items array.
for (const notification of this.items.slice()) notification.isSeen = true;
}
if (!omitRequest) this.repo.markAllAsSeen();
};
push(notification: Notification) {
const added = super.push(notification);
if (added && !notification.isRead) this.incrementUnreadCount();
if (added && !notification.isSeen) this.incrementUnseenCount();
return added;
}
remove(notification: Notification) {
const removed = super.remove(notification);
if (removed && !notification.isRead) this.decrementUnreadCount();
if (removed && !notification.isSeen) this.decrementUnseenCount();
return removed;
}
incrementUnreadCount() {
this.unreadCount = this.unreadCount + 1;
}
decrementUnreadCount() {
this.unreadCount = Math.max(0, this.unreadCount - 1);
}
incrementUnseenCount() {
this.unseenCount = this.unseenCount + 1;
}
decrementUnseenCount() {
this.unseenCount = Math.max(0, this.unseenCount - 1);
}
set(json) {
const { notifications, ...metadata } = json;
Object.assign(this, metadata);
if (notifications) this.setItems(notifications);
}
/**
* Append notifications to the store.
*
* @param items Object containing the pagination data
*/
setItems(items) {
const notifications = items.map((notification) => this.createNotification(notification));
this.items.push(...notifications);
return this;
}
private createNotification(data) {
return NotificationFactory.create(data);
}
}