app/models/Notification.ts
Rama main · réplica de lectura del repositorio original.
import type { TFunction } from "i18next";
import { action, computed, observable } from "mobx";
import type { NotificationData } from "@shared/types";
import { NotificationEventType } from "@shared/types";
import {
collectionPath,
commentPath,
documentPath,
settingsPath,
} from "~/utils/routeHelpers";
import Collection from "./Collection";
import Comment from "./Comment";
import Document from "./Document";
import Group from "./Group";
import User from "./User";
import Model from "./base/Model";
import Field from "./decorators/Field";
import Relation from "./decorators/Relation";
export type NotificationFilter =
| "all"
| "mentions"
| "comments"
| "reactions"
| "documents"
| "collections"
| "system";
class Notification extends Model {
static modelName = "Notification";
constructor(fields: Record<string, unknown>, store: Model["store"]) {
super(fields, store);
this.initialize(fields);
}
static filterCategories: Record<NotificationFilter, NotificationEventType[]> =
{
all: [],
mentions: [
NotificationEventType.MentionedInDocument,
NotificationEventType.MentionedInComment,
NotificationEventType.GroupMentionedInDocument,
NotificationEventType.GroupMentionedInComment,
],
comments: [
NotificationEventType.CreateComment,
NotificationEventType.ResolveComment,
NotificationEventType.ReactionsCreate,
],
reactions: [NotificationEventType.ReactionsCreate],
documents: [
NotificationEventType.PublishDocument,
NotificationEventType.UpdateDocument,
NotificationEventType.CreateRevision,
NotificationEventType.AddUserToDocument,
NotificationEventType.RequestDocumentAccess,
],
collections: [
NotificationEventType.CreateCollection,
NotificationEventType.AddUserToCollection,
],
system: [
NotificationEventType.InviteAccepted,
NotificationEventType.Onboarding,
NotificationEventType.Features,
NotificationEventType.ExportCompleted,
NotificationEventType.AddUserToGroup,
NotificationEventType.RemoveUserFromGroup,
],
};
/**
* The date the notification was marked as read.
*/
@Field
@observable
viewedAt: Date | null;
/**
* The date the notification was archived.
*/
@Field
@observable
archivedAt: Date | null;
/**
* Request ID on notifications for access requests.
*/
@Field
@observable
accessRequestId?: string = undefined;
/**
* Status of the associated access request.
*/
@Field
@observable
accessRequestStatus?: string = undefined;
/**
* The user that triggered the notification.
*/
@Relation(() => User)
actor?: User;
/**
* The document ID that the notification is associated with.
*/
documentId?: string;
/**
* The document that the notification is associated with.
*/
@Relation(() => Document, { onDelete: "cascade" })
document?: Document;
/**
* The collection ID that the notification is associated with.
*/
collectionId?: string;
/**
* The collection that the notification is associated with.
*/
@Relation(() => Collection, { onDelete: "cascade" })
collection?: Collection;
/**
* The group ID that the notification is associated with.
*/
groupId?: string;
/**
* The group that the notification is associated with.
*/
@Relation(() => Group, { onDelete: "cascade" })
group?: Group;
commentId?: string;
/**
* The comment that the notification is associated with.
*/
@Relation(() => Comment, { onDelete: "cascade" })
comment?: Comment;
/**
* The type of notification.
*/
event: NotificationEventType;
/**
* Additional data associated with the notification.
*/
data: NotificationData;
/**
* Mark the notification as read or unread
*
* @returns A promise that resolves when the notification has been saved.
*/
@action
toggleRead() {
this.viewedAt = this.viewedAt ? null : new Date();
return this.save();
}
/**
* Mark the notification as read
*
* @returns A promise that resolves when the notification has been saved.
*/
@action
markAsRead() {
if (this.viewedAt) {
return;
}
this.viewedAt = new Date();
return this.save();
}
/**
* Archive the notification
*
* @returns A promise that resolves when the notification has been archived.
*/
@action
archive() {
if (this.archivedAt) {
return;
}
this.archivedAt = new Date();
return this.save();
}
/**
* Returns translated text that describes the notification
*
* @param t - The translation function
* @returns The event text
*/
eventText(t: TFunction): string {
switch (this.event) {
case NotificationEventType.PublishDocument:
return t("published");
case NotificationEventType.UpdateDocument:
case NotificationEventType.CreateRevision:
return t("edited");
case NotificationEventType.CreateCollection:
return t("created the collection");
case NotificationEventType.MentionedInDocument:
case NotificationEventType.MentionedInComment:
return t("mentioned you in");
case NotificationEventType.GroupMentionedInComment:
case NotificationEventType.GroupMentionedInDocument:
return t("mentioned your group in");
case NotificationEventType.CreateComment:
return t("left a comment on");
case NotificationEventType.ResolveComment:
return t("resolved a comment on");
case NotificationEventType.ReactionsCreate:
return t("reacted {{ emoji }} to your comment on", {
emoji: this.data.emoji,
});
case NotificationEventType.AddUserToDocument:
return t("shared");
case NotificationEventType.AddUserToCollection:
return t("invited you to");
case NotificationEventType.AddUserToGroup:
return t("added you to the group");
case NotificationEventType.RemoveUserFromGroup:
return t("removed you from the group");
case NotificationEventType.RequestDocumentAccess:
if (this.accessRequestStatus === "approved") {
return t("was granted access to");
}
if (this.accessRequestStatus === "dismissed") {
return t("requested access to");
}
return t("is requesting access to");
default:
return this.event;
}
}
/**
* Returns translated text for the subject of the notification. This is the
* name of the associated document, collection, or group.
*
* @param t - The translation function.
* @returns The subject.
*/
subject(t: TFunction): string {
if (this.documentId) {
return this.document?.title ?? t("a document");
}
if (this.collectionId) {
return this.collection?.displayName ?? t("a collection");
}
if (this.groupId) {
return this.group?.name ?? t("a group");
}
return t("Unknown");
}
/**
* Returns the path to the model associated with the notification that can be
* used with the router.
*
* @returns The router path.
*/
@computed
get path() {
switch (this.event) {
case NotificationEventType.PublishDocument:
case NotificationEventType.UpdateDocument:
case NotificationEventType.CreateRevision: {
return this.document ? documentPath(this.document) : "";
}
case NotificationEventType.AddUserToCollection:
case NotificationEventType.CreateCollection: {
const collection = this.collectionId
? this.store.rootStore.collections.get(this.collectionId)
: undefined;
return collection ? collectionPath(collection) : "";
}
case NotificationEventType.RequestDocumentAccess:
case NotificationEventType.AddUserToDocument:
case NotificationEventType.GroupMentionedInDocument:
case NotificationEventType.MentionedInDocument: {
return this.document?.path;
}
case NotificationEventType.GroupMentionedInComment:
case NotificationEventType.MentionedInComment:
case NotificationEventType.ResolveComment:
case NotificationEventType.CreateComment:
case NotificationEventType.ReactionsCreate: {
return this.document && this.comment
? commentPath(this.document, this.comment)
: this.document?.path;
}
case NotificationEventType.InviteAccepted: {
return settingsPath("users");
}
case NotificationEventType.Onboarding:
case NotificationEventType.Features: {
return "";
}
case NotificationEventType.ExportCompleted: {
return settingsPath("export");
}
case NotificationEventType.AddUserToGroup:
case NotificationEventType.RemoveUserFromGroup: {
return this.groupId
? settingsPath("groups", this.groupId, "members")
: "";
}
default:
this.event satisfies never;
return;
}
}
}
export default Notification;